độ ổn định: Beta
Kết xuất hóa đơn từ đầu đến cuối qua REST
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”Đưa một hóa đơn từ JSON đến một tệp PDF được xác minh cục bộ qua bề mặt
Representational State Transfer (REST) của NextPDF Connect, mỗi lần một
lượt trao đổi trên đường truyền. Công thức này gửi một tác vụ kết xuất tới
POST /api/v1/jobs, phát lại lượt gửi với cùng một Idempotency-Key để
minh họa đường dẫn an toàn với trùng lặp, thăm dò GET /api/v1/jobs/{id},
tải tệp PDF về từ GET /api/v1/jobs/{id}/result, kiểm tra các byte bằng
qpdf --check, và xóa tác vụ đã hoàn tất.
Mọi phản hồi bên dưới đều là bản thu thập nguyên văn từ một triển khai
Connect bậc core thực tế (nextpdf/server chạy dưới RoadRunner, gắn với
http://localhost:8080). Thay thế duy nhất là khóa API, được hiển thị
dưới dạng biến môi trường $NEXTPDF_CONNECT_TOKEN; các mã định danh tác
vụ, mã định danh yêu cầu, dấu thời gian, header và byte thân đều đúng chính
xác những gì máy chủ trả về. Các giá trị header như Date và
X-Request-Id tất nhiên sẽ khác đi trên triển khai của bạn.
Công thức này điều khiển một tài liệu duy nhất để bạn có thể đọc trọn vẹn
từng lượt trao đổi. Với nhiều tài liệu, xử lý đồng thời có giới hạn, và các
vòng lặp thăm dò do Retry-After điều khiển, hãy xem
Tạo PDF hàng loạt kèm theo dõi tiến độ,
vốn dùng chung bề mặt tác vụ này.
Cài đặt
Phần tiêu đề “Cài đặt”Phía máy chủ là bản phân phối Connect tiêu chuẩn:
composer require nextpdf/serverPhía client của công thức này là curl cộng với qpdf, nên bạn có thể
chuyển nó sang bất kỳ HTTP client nào. Trước tiên, hãy export các
giá trị của triển khai của bạn:
export NEXTPDF_CONNECT_URL="http://localhost:8080"export NEXTPDF_CONNECT_TOKEN="npk_live_{kid}_{secret}" # your real key# Key provisioning and server startup live in the quickstart:Tổng quan khái niệm
Phần tiêu đề “Tổng quan khái niệm”Bề mặt tác vụ bất đồng bộ tách việc gửi khỏi việc truy xuất: bạn gửi một
yêu cầu kết xuất, nhận một bản ghi tác vụ, và lấy kết quả khi tác vụ đạt
trạng thái completed. Bản thân yêu cầu kết xuất là một mảng operations
có thứ tự — cùng các loại thao tác (set_font, add_text, add_table,
add_image, add_page) làm nền cho các lệnh gọi công cụ Connect trên mọi
transport — cộng thêm các trường ở cấp tài liệu (page_size,
orientation, title, author).
Hai chi tiết hợp đồng định hình bản ghi mà bạn sắp đọc:
- Gửi bất biến. Một lượt gửi có khóa
Idempotency-Keytrả về201 Createdở lần đầu và200 OKvới cùng bản ghi tác vụ khi được phát lại, nên một lần thử lại qua mạng không bao giờ kết xuất hai lần. - Lượt gửi có thể đã ở trạng thái kết thúc. Bản phát hành hiện tại xử
lý tác vụ tại chỗ trước khi trả lời
POST, nên phản hồi của lượt gửi có thể đã mangstatus: "completed"— như trường hợp bên dưới. Hợp đồng thăm-dò-đến-khi-kết-thúc mới là hình dạng API ổn định: hãy viết vòng lặp thăm dò, và chấp nhận một trạng thái kết thúc ở bất kỳ lần thử nào, kể cả lần đầu.
Bạn có thể xác nhận những gì triển khai của bạn cung cấp trước khi gửi bất
cứ thứ gì: GET /api/v1/capabilities trả về danh mục thao tác mà bậc
khóa API của bạn có thể truy cập. Trên triển khai bậc core được thu thập ở
đây, nó chỉ liệt kê các thao tác core; danh mục chính thức luôn là phản hồi
của chính máy chủ đang chạy, chứ không phải trang này.
Bề mặt API
Phần tiêu đề “Bề mặt API”| Lượt trao đổi | Phương thức và đường dẫn | Trạng thái đã thu thập |
|---|---|---|
| Gửi tác vụ kết xuất | POST /api/v1/jobs | 201 Created |
| Phát lại cùng lượt gửi | POST /api/v1/jobs (cùng Idempotency-Key) | 200 OK |
| Thăm dò bản ghi tác vụ | GET /api/v1/jobs/{id} | 200 OK |
| Tải tệp PDF về | GET /api/v1/jobs/{id}/result | 200 OK, application/pdf |
| Xóa tác vụ đã hoàn tất | DELETE /api/v1/jobs/{id} | 204 No Content |
Xác thực là một bearer token trên mọi yêu cầu /api/v1/*:
Authorization: Bearer npk_live_{kid}_{secret}. Các phản hồi JSON thành
công dùng chung phong bì { "data": ..., "meta": ... }; các trường bạn
thao tác nằm dưới data.
Yêu cầu hóa đơn
Phần tiêu đề “Yêu cầu hóa đơn”Ghi yêu cầu kết xuất vào invoice.json. Đó là một danh sách thao tác đơn
giản, tất định — một dòng tiêu đề in đậm, một dòng phát hành, và một bảng
các mục hàng:
{ "page_size": "A4", "orientation": "portrait", "title": "Invoice INV-2026-0042", "author": "Aurora Fixtures Ltd.", "operations": [ { "type": "set_font", "family": "helvetica", "style": "B", "size": 16 }, { "type": "add_text", "text": "Invoice INV-2026-0042" }, { "type": "set_font", "family": "helvetica", "style": "", "size": 10 }, { "type": "add_text", "text": "Issued 2026-07-08 by Aurora Fixtures Ltd. Payment is due within 30 days.", "width": 0, "line_height": 5 }, { "type": "add_table", "html": "<table><tr><th>Item</th><th>Qty</th><th>Unit price</th><th>Amount</th></tr><tr><td>Cable tray, 300 mm</td><td>12</td><td>18.40</td><td>220.80</td></tr><tr><td>Mounting kit</td><td>4</td><td>9.75</td><td>39.00</td></tr><tr><td>Site delivery</td><td>1</td><td>25.00</td><td>25.00</td></tr><tr><td>Total (EUR)</td><td></td><td></td><td>284.80</td></tr></table>" } ]}Các trường hóa đơn ở đây là dữ liệu mẫu. Hình dạng đối số chính thức cho
mỗi thao tác là hình dạng do triển khai của bạn báo cáo — qua MCP,
tools/list trả về schema đầu vào đầy đủ cho mọi loại thao tác mà yêu cầu
này sử dụng.
Bản ghi từ đầu đến cuối
Phần tiêu đề “Bản ghi từ đầu đến cuối”1. Gửi tác vụ kết xuất
Phần tiêu đề “1. Gửi tác vụ kết xuất”curl -sS -i -X POST "$NEXTPDF_CONNECT_URL/api/v1/jobs" \ -H "Authorization: Bearer $NEXTPDF_CONNECT_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: inv-2026-0042" \ --data-binary @invoice.jsonMáy chủ trả lời 201 Created:
HTTP/1.1 201 CreatedCache-Control: no-storeContent-Security-Policy: default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'Content-Type: application/json; charset=utf-8Referrer-Policy: no-referrerVary: Accept-EncodingX-Content-Type-Options: nosniffX-Frame-Options: DENYX-Powered-By: NextPDF ConnectX-Ratelimit-Remaining: 99X-Request-Id: 019f3fd6-c6ed-727c-958e-2fa4370ba97eDate: Wed, 08 Jul 2026 03:47:48 GMTTransfer-Encoding: chunked{ "data": { "job_id": "job_9bd0808960f10eb568484acc", "status": "completed", "created_at": "2026-07-08T03:47:48+00:00", "started_at": "2026-07-08T03:47:48+00:00", "completed_at": "2026-07-08T03:47:48+00:00", "result_url": "/api/v1/jobs/job_9bd0808960f10eb568484acc/result" }, "meta": { "request_id": "019f3fd6-c6ed-727c-958e-2fa4370ba97e", "timestamp": "2026-07-08T03:47:48+00:00", "duration_ms": 63.31, "api_version": "v1" }}Tác vụ đã ở trạng thái kết thúc trong bản thu thập này — status là
"completed" và result_url hiện diện — vì bản phát hành hiện tại kết
xuất tại chỗ trước khi trả lời. Đừng phụ thuộc vào điều đó: hãy xem phản
hồi của lượt gửi như kết quả thăm dò đầu tiên và rẽ nhánh theo data.status
như mọi lần thăm dò khác.
2. Phát lại lượt gửi (đường dẫn bất biến)
Phần tiêu đề “2. Phát lại lượt gửi (đường dẫn bất biến)”Thử lại đúng cùng một lệnh — cùng Idempotency-Key, cùng thân:
curl -sS -i -X POST "$NEXTPDF_CONNECT_URL/api/v1/jobs" \ -H "Authorization: Bearer $NEXTPDF_CONNECT_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: inv-2026-0042" \ --data-binary @invoice.jsonMáy chủ trả về 200 OK — không phải 201 — với cùng job_id, và không
có lượt kết xuất thứ hai nào diễn ra (hãy so sánh meta.duration_ms với
phản hồi đầu tiên):
HTTP/1.1 200 OKCache-Control: no-storeContent-Security-Policy: default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'Content-Type: application/json; charset=utf-8Referrer-Policy: no-referrerVary: Accept-EncodingX-Content-Type-Options: nosniffX-Frame-Options: DENYX-Powered-By: NextPDF ConnectX-Ratelimit-Remaining: 99X-Request-Id: 019f3fd6-c756-7226-bc85-b255d75bd449Date: Wed, 08 Jul 2026 03:47:48 GMTTransfer-Encoding: chunked{ "data": { "job_id": "job_9bd0808960f10eb568484acc", "status": "completed", "created_at": "2026-07-08T03:47:48+00:00", "started_at": "2026-07-08T03:47:48+00:00", "completed_at": "2026-07-08T03:47:48+00:00", "result_url": "/api/v1/jobs/job_9bd0808960f10eb568484acc/result" }, "meta": { "request_id": "019f3fd6-c756-7226-bc85-b255d75bd449", "timestamp": "2026-07-08T03:47:48+00:00", "duration_ms": 1.03, "api_version": "v1" }}3. Thăm dò bản ghi tác vụ
Phần tiêu đề “3. Thăm dò bản ghi tác vụ”curl -sS -i "$NEXTPDF_CONNECT_URL/api/v1/jobs/job_9bd0808960f10eb568484acc" \ -H "Authorization: Bearer $NEXTPDF_CONNECT_TOKEN"HTTP/1.1 200 OKCache-Control: no-storeContent-Security-Policy: default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'Content-Type: application/json; charset=utf-8Referrer-Policy: no-referrerVary: Accept-EncodingX-Content-Type-Options: nosniffX-Frame-Options: DENYX-Powered-By: NextPDF ConnectX-Ratelimit-Remaining: 98X-Request-Id: 019f3fd7-0038-7131-b71e-4c69e637233bDate: Wed, 08 Jul 2026 03:48:02 GMTTransfer-Encoding: chunked{ "data": { "job_id": "job_9bd0808960f10eb568484acc", "status": "completed", "created_at": "2026-07-08T03:47:48+00:00", "started_at": "2026-07-08T03:47:48+00:00", "completed_at": "2026-07-08T03:47:48+00:00", "result_url": "/api/v1/jobs/job_9bd0808960f10eb568484acc/result" }, "meta": { "request_id": "019f3fd7-0038-7131-b71e-4c69e637233b", "timestamp": "2026-07-08T03:48:02+00:00", "duration_ms": 0.24, "api_version": "v1" }}Lần thăm dò này cho thấy một bản ghi ở trạng thái kết thúc, nên không có
header Retry-After và không có trường poll_url. Khi một tác vụ vẫn còn
pending hoặc running, máy chủ đặt Retry-After (một khoảng 2 giây) ở
mỗi lần thăm dò — hãy tôn trọng nó thay vì thăm dò trong một vòng lặp dồn
dập.
4. Tải tệp PDF về
Phần tiêu đề “4. Tải tệp PDF về”curl -sS -D result-headers.txt \ "$NEXTPDF_CONNECT_URL/api/v1/jobs/job_9bd0808960f10eb568484acc/result" \ -H "Authorization: Bearer $NEXTPDF_CONNECT_TOKEN" \ -o invoice-inv-2026-0042.pdfHTTP/1.1 200 OKCache-Control: no-storeContent-Disposition: attachment; filename="job-job_9bd0808960f10eb568484acc.pdf"Content-Length: 3663Content-Security-Policy: default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'Content-Type: application/pdfReferrer-Policy: no-referrerVary: Accept-EncodingX-Content-Type-Options: nosniffX-Frame-Options: DENYX-Powered-By: NextPDF ConnectX-Ratelimit-Remaining: 98X-Request-Id: 019f3fd7-0056-711e-acad-9f7ac5f21ba7Date: Wed, 08 Jul 2026 03:48:02 GMTThân phản hồi là tệp PDF nhị phân — 3.663 byte trong bản thu thập này, khớp
với header Content-Length — và được lược bỏ ở đây. Nó được ghi vào
invoice-inv-2026-0042.pdf.
5. Xác minh cục bộ các byte đã tải về
Phần tiêu đề “5. Xác minh cục bộ các byte đã tải về”Một 200 với Content-Type: application/pdf tự nó không phải là bằng chứng
cho thấy thân phản hồi là một tệp PDF đúng định dạng. Hãy chạy một lượt kiểm
tra cấu trúc bằng qpdf:
qpdf --check invoice-inv-2026-0042.pdfKết quả thu thập cho tệp đã tải về ở trên:
checking invoice-inv-2026-0042.pdfPDF Version: 2.0File is not encryptedFile is not linearizedNo syntax or stream encoding errors found; the file may still containerrors that qpdf cannot detectChính cách diễn đạt của qpdf là ranh giới trung thực: đây là một lượt kiểm tra cú pháp và luồng, không phải là kết luận về mức độ tuân thủ đối với bất kỳ tiêu chuẩn nào.
6. Xóa tác vụ đã hoàn tất
Phần tiêu đề “6. Xóa tác vụ đã hoàn tất”curl -sS -i -X DELETE "$NEXTPDF_CONNECT_URL/api/v1/jobs/job_9bd0808960f10eb568484acc" \ -H "Authorization: Bearer $NEXTPDF_CONNECT_TOKEN"HTTP/1.1 204 No ContentCache-Control: no-storeContent-Security-Policy: default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'Content-Type: application/json; charset=utf-8Referrer-Policy: no-referrerVary: Accept-EncodingX-Content-Type-Options: nosniffX-Frame-Options: DENYX-Powered-By: NextPDF ConnectX-Ratelimit-Remaining: 97X-Request-Id: 019f3fd7-0084-722f-bf54-3dabead8aeeaDate: Wed, 08 Jul 2026 03:48:02 GMTSau khi xóa, bản ghi tác vụ và kết quả đã lưu trữ của nó biến mất; một
GET tiếp theo trên tác vụ trả về 404.
Trường hợp đặc biệt & lưu ý
Phần tiêu đề “Trường hợp đặc biệt & lưu ý”- Rẽ nhánh theo
data.status, không chỉ dựa vào trạng thái HTTP. Gửi, phát lại và thăm dò đều trả về2xxkèm một bản ghi tác vụ; trạng thái vòng đời nằm trongdata.status(pending,running,completed,failed,cancelled). - Một khóa được phát lại với thân khác là
409 Conflict. Lượt phát lại200bất biến chỉ xảy ra khi thân khớp với lượt gửi ban đầu. Đừng bao giờ tái sử dụng một khóa cho nội dung khác. - Gọi
/resulttrước khi hoàn tất là409. Chỉ tải về sau khi một lần thăm dò cho thấycompleted.409là một phản hồi bình thường cần kiểm tra, không phải một lỗi truyền tải — chính sự tách biệt giữa truyền tải và trạng thái mà mọi công thức Connect đều tuân theo (xem Quy ước công thức). - Tác vụ bị giới hạn theo chủ sở hữu. Một tác vụ được gửi bằng một khóa
API là vô hình đối với khóa khác: một
GETxuyên chủ sở hữu trả về404, không phải403. Hãy thăm dò bằng chính thông tin xác thực mà bạn đã dùng để gửi. progresscó thể vắng mặt. Bản ghi được thu thập không mang trườngprogressvì tác vụ đã ở trạng thái kết thúc. Khi máy chủ theo dõi tiến độ cho một tác vụ chưa kết thúc,data.progresslà một số nguyên từ 0 đến 100; hãy xem một trường thiếu là không xác định, chứ không phải bằng không.- Một tác vụ
failedmang theodata.error. Hãy ghi lại nó; đừng gửi lại một cách mù quáng.
Hiệu năng
Phần tiêu đề “Hiệu năng”Một tác vụ kết xuất tốn một lượt gửi, nhiều nhất là một vài lần thăm dò, và
một lượt tải về. Các giá trị meta.duration_ms được thu thập kể lại câu
chuyện: 63.31 ms để kết xuất hóa đơn khi gửi, 1.03 ms cho lượt phát lại bất
biến vốn không làm gì, và các lượt đọc trạng thái dưới một mili-giây. Hãy
thăm dò theo nhịp Retry-After của máy chủ thay vì một vòng lặp dồn dập;
lượt đọc trạng thái rẻ nhưng không miễn phí, và bộ giới hạn tần suất tính
chi phí cho nó (hãy quan sát X-Ratelimit-Remaining giảm dần trong các
header được thu thập). Với các lô, hãy giới hạn số tác vụ đang xử lý thay
vì gửi tất cả cùng một lúc — công thức hàng loạt
hiện thực vòng lặp đó.
Lưu ý bảo mật
Phần tiêu đề “Lưu ý bảo mật”- Chỉ giữ bearer token trong header
Authorization. Không bao giờ để trong query string, một dòng nhật ký, hay một tệp đã commit. Bản ghi ở trên thay thế bằng một biến môi trường chính vì lý do đó. - Xác thực các byte đã tải về trước khi tin tưởng chúng. Bước 5 là một
phần của luồng, không phải phần thêm tùy chọn: hãy kiểm tra phản hồi là
một tệp PDF (tối thiểu là header
%PDF,qpdf --checkcho cấu trúc) trước khi lưu trữ hoặc chuyển tiếp nó. - Xóa các tác vụ đã hoàn tất mà bạn không còn cần. Bước 6 loại bỏ kết quả đã lưu trữ khỏi máy chủ; nếu không, một tác vụ đã hoàn tất vẫn có thể tải về cho đến khi cơ chế thu gom rác tác vụ của máy chủ loại bỏ nó.
- Dùng một khóa với đặc quyền tối thiểu. Luồng này cần một khóa kết xuất bậc core và không cần gì hơn.
Tuân thủ
Phần tiêu đề “Tuân thủ”Công thức này không đưa ra tuyên bố tiêu chuẩn quy phạm nào. Nó sử dụng
các endpoint REST cho tác vụ bất đồng bộ của Connect và đọc các trường bản
ghi tác vụ mà máy chủ định nghĩa. Bước qpdf --check chỉ xác nhận tính
toàn vẹn về cấu trúc — “the file may still contain errors that qpdf cannot
detect” là lời cảnh báo của chính qpdf, được trích nguyên văn ở trên. Việc
xác định mức độ tuân thủ đối với một tiêu chuẩn (PDF/A-4, PDF/UA) là công
việc của một trình xác thực độc lập, và là một bề mặt khác — hãy xem
Chạy kiểm tra tiêu chuẩn có tên
cho ranh giới đó.
Xem thêm
Phần tiêu đề “Xem thêm”- Tạo PDF hàng loạt kèm theo dõi tiến độ — cùng bề mặt tác vụ được điều khiển như một lô có xử lý đồng thời giới hạn.
- Tạo tệp PDF đầu tiên của bạn — lượt kết xuất Connect nhỏ nhất.
- Điều khiển một phiên tài liệu agent qua MCP — cùng động cơ, từng công cụ một, qua transport stdio của MCP.
- Quy ước công thức Connect — hợp đồng về truyền tải, bậc, và tuân thủ mà mọi công thức Connect đều tuân theo.
- Xử lý lỗi có nhận biết ngoại lệ qua Connect — cách tách các lỗi truyền tải khỏi các trạng thái không thành công.