Đơn hàng
Nếu CheckoutSession là thứ người mua thấy, thì Order mới là thứ bạn quan tâm. Nó là bản ghi vĩnh viễn về:
- Người mua đang mua gì (line items)
- Bao nhiêu được nợ và bao nhiêu thực tế đã trả
- Refund đang chờ và đã được áp dụng
- Reference ngoài của bạn (
external_ref) — thường là order ID của chính bạn, được lưu trên Order và trả về tạiGET /b2b/v1/orders/{id}(không echo trong payload webhook — xem bên dưới)
CheckoutSession chết sau khi một trong các PaymentIntent của nó được settle hoặc TTL hết hạn. Order sống mãi mãi.
Khi nào Order được tạo
Khi bạn gọi POST /b2b/v1/checkout-sessions/quick, payment-service tạo
cả Order mới và CheckoutSession mới trong cùng một transaction.
Nếu bạn đã có Order và muốn retry checkout (ví dụ sau khi người mua từ
bỏ), dùng POST /b2b/v1/checkout-sessions để gắn một session mới vào
order đã có — giữ nguyên audit trail.
Vòng đời
| Trạng thái | Ý nghĩa |
|---|---|
DRAFT | Dành riêng cho một luồng drafts trong tương lai. Không có code path nào tạo order DRAFT hôm nay — mọi order đều được tạo ở trạng thái PENDING, nên bạn sẽ không quan sát thấy trạng thái này. |
PENDING | Một CheckoutSession đang chạy và chưa được giải quyết. |
PAID | Toàn bộ số tiền đã được settle. Webhook payment.settled được phát ở đây. An toàn để fulfillment. |
PARTIAL_PAID | Tiền đã đến nhưng ít hơn tổng. Xem “Underpayment” bên dưới. |
CANCELED | Session hết hạn hoặc merchant đã hủy. metadata.canceled_reason giải thích lý do (payment_timeout, merchant_canceled, …). |
REFUNDED | Toàn bộ số tiền đã trả đều đã được hoàn lại. |
PARTIALLY_REFUNDED | Có refund đã được thực thi nhưng phần còn lại vẫn được giữ là đã trả. |
Trạng thái để chuyển logic fulfillment là PAID — không phải
COMPLETED của CheckoutSession. Webhook payment.settled là tín
hiệu canonical.
Trường external_ref
Khi tạo session bạn có thể đưa kèm external_ref (chuỗi bất kỳ tối
đa 255 ký tự — thường là order ID của chính bạn). Nó xuyên suốt cả
pipeline:
- Lưu trên Order
- Hiển thị trong merchant dashboard cho việc tra cứu support
- Trả về tại
GET /b2b/v1/orders/{id}để webhook handler có thể lấy sau khi nhậnpayment.settled
Payload webhook không echo external_ref trực tiếp ở thời điểm
hiện tại — các bản nháp tài liệu cũ từng tuyên bố data.external_ref
chảy xuyên qua mọi event, và điều đó sai. Để map một webhook
payment.* về row DB của bạn, lấy order_id từ payload và fetch
order. Trường external_ref native trên payload webhook nằm trong
roadmap.
Underpayment
Nếu giao dịch chuyển on-chain của người mua clear ít hơn tổng order,
Order chuyển sang PARTIAL_PAID. Bạn có ba lựa chọn:
- Chấp nhận và resolve. Chuyển order sang
PAIDvà phátorder.resolved. Đây không phải là endpoint REST công khai — resolve hiện là một hành động nội bộ/vận hành, nên với luồng self-serve, ưu tiên lựa chọn 2 (thu phần còn thiếu). - Chờ phần còn thiếu. Tạo một CheckoutSession mới ứng với cùng
Order với
amount_due= residual. Người mua trả phần chênh lệch; khi nó settle, Order chuyển sangPAID. - Hủy và refund. Hoàn lại số tiền partial và hủy Order. Người mua chịu mọi chain fee.
Sản phẩm không đưa ra khuyến nghị ở đây — các merchant khác nhau muốn chính sách khác nhau. Chọn một và đưa vào admin của bạn.
Refunds
Refund là API surface riêng và là khái niệm riêng. Xem Khái niệm → Hoàn tiền.
API endpoints
| Method | Path | Ghi chú |
|---|---|---|
POST | /b2b/v1/orders | Tạo Order mà không có session (hiếm) |
GET | /b2b/v1/orders/:order_id | Đọc order đầy đủ với line items + lịch sử thanh toán |
PATCH | /b2b/v1/orders/:order_id/cancel | Hủy một order chưa thanh toán |
PATCH | /b2b/v1/orders/:order_id/reopen | Mở lại một order bị auto-cancel (payment_timeout) |
Tiếp theo
- Khái niệm → Sessions — lớp vỏ hướng tới người mua bao quanh một Order.
- Khái niệm → Hoàn tiền — trạng thái refund và bước submit on-chain thủ công.
- Webhooks → Tổng quan — mọi event được phát trong vòng đời của Order.