Skip to Content
Khái niệmĐơn hàng

Đơ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ại GET /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 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
DRAFTDà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.
PENDINGMột CheckoutSession đang chạy và chưa được giải quyết.
PAIDToàn bộ số tiền đã được settle. Webhook payment.settled được phát ở đây. An toàn để fulfillment.
PARTIAL_PAIDTiền đã đến nhưng ít hơn tổng. Xem “Underpayment” bên dưới.
CANCELEDSession hết hạn hoặc merchant đã hủy. metadata.canceled_reason giải thích lý do (payment_timeout, merchant_canceled, …).
REFUNDEDToàn bộ số tiền đã trả đều đã được hoàn lại.
PARTIALLY_REFUNDEDCó 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ận payment.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:

  1. Chấp nhận và resolve. Chuyển order sang PAID và phát order.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).
  2. 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 sang PAID.
  3. 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

MethodPathGhi chú
POST/b2b/v1/ordersTạ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/cancelHủy một order chưa thanh toán
PATCH/b2b/v1/orders/:order_id/reopenMở lại một order bị auto-cancel (payment_timeout)

Tiếp theo