Skip to Content
ConceptsOrders
View as Markdown

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)

An order does not need line items: send amount instead of items to bill a plain amount (an invoice, a deposit, a custom payment link). Send one or the other, never both.

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, InfraIO Pay 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
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 include external_ref. To map a payment.* webhook back to your own record, take order_id from the payload and fetch the order.

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 isn’t available through the REST API, so for a self-serve flow use 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.

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