Skip to Content
ConceptsOrders

Orders

If CheckoutSession is what the buyer sees, Order is what you care about. It’s the permanent record of:

  • What was being bought (line items)
  • How much was owed and how much has actually been paid
  • Refunds outstanding and applied
  • Your external reference (external_ref) — typically your own order ID, stored on the Order and returned on GET /b2b/v1/orders/{id} (not echoed in webhook payloads — see below)

A CheckoutSession dies after one of its PaymentIntents settles or the TTL expires. The Order lives forever.

When an Order is created

When you call POST /b2b/v1/checkout-sessions/quick, the payment-service creates both a new Order and a new CheckoutSession in one transaction. If you already have an Order and want to retry checkout (e.g., after the buyer abandoned), use POST /b2b/v1/checkout-sessions instead to attach a fresh session to the existing order — preserving the audit trail.

Lifecycle

StateMeans
DRAFTReserved for a future drafts flow. No code path creates DRAFT orders today — every order is created PENDING, so you will not observe this state.
PENDINGA CheckoutSession is live and unresolved.
PAIDFull amount settled. The webhook payment.settled fires here. Safe to fulfill.
PARTIAL_PAIDMoney arrived but less than total. See “Underpayment” below.
CANCELEDSession expired or merchant cancelled. metadata.canceled_reason explains why (payment_timeout, merchant_canceled, …).
REFUNDEDAll paid amount has been refunded.
PARTIALLY_REFUNDEDSome refund executed but balance remains paid.

The state to switch your fulfillment logic on is PAID — not the CheckoutSession’s COMPLETED. The payment.settled webhook is the canonical signal.

The external_ref field

When creating a session you can include external_ref (any string up to 255 chars — typically your own order ID). It threads through the whole pipeline:

  • Stored on the Order
  • Visible in the merchant dashboard for support lookups
  • Returned on GET /b2b/v1/orders/{id} so a webhook handler can fetch it after receiving payment.settled

Webhook payloads do not echo external_ref directly today — earlier drafts of these docs claimed data.external_ref flowed through to every event, and that was wrong. To map a payment.* webhook back to your DB row, take order_id from the payload and fetch the order. The native external_ref field on webhook payloads is on the roadmap.

Underpayment

If the buyer’s on-chain transfer clears for less than the order total, the Order goes to PARTIAL_PAID. You have three options:

  1. Accept and resolve. Flips the order to PAID and fires order.resolved. This is not a public REST endpoint — resolution is an internal/operational action today, so for a self-serve flow prefer option 2 (collect the remainder).
  2. Wait for the remainder. Create a new CheckoutSession against the same Order with amount_due = residual. The buyer pays the difference; when that settles, Order moves to PAID.
  3. Cancel and refund. Refund the partial amount and cancel the Order. The buyer is responsible for any chain fees.

The product hasn’t made a recommendation here — different merchants want different policies. Pick one and bake it into your admin.

Refunds

Refunds are a separate API surface and a separate concept page. See Concepts → Refunds.

API endpoints

MethodPathNotes
POST/b2b/v1/ordersCreate an Order without a session (rare)
GET/b2b/v1/orders/:order_idRead full order with line items + payment history
PATCH/b2b/v1/orders/:order_id/cancelCancel an unpaid order
PATCH/b2b/v1/orders/:order_id/reopenReopen an auto-canceled (payment_timeout) order

What’s next