Skip to main content

Order Status

Order and payment status values, what moves them, and which webhook fires when they move.

Order Status​

An order is the amount you asked to be paid. Its status is a rollup of the payments that have settled against it. The customer's transfer and its verification are tracked on the payment, not on the order.

const CheckoutOrderStatus = {
CREATED: 'CREATED',
PARTIALLY_FULFILLED: 'PARTIALLY_FULFILLED',
FULFILLED: 'FULFILLED',
CANCELLED: 'CANCELLED',
} as const;

Status Descriptions​

StatusDescription
CREATEDNo settled payment yet. Payment attempts may be open, expired, failed, or cancelled underneath it. Every order starts here
PARTIALLY_FULFILLEDAt least one payment settled, but remainingUsdcAmount is still above the order's completion threshold. Further payment attempts are allowed
FULFILLEDremainingUsdcAmount is 0, or a residual at or below the order's completion threshold. completedAt is set and the residual stays in remainingUsdcAmount
CANCELLEDYou cancelled a CREATED order that had no payment attempts. cancelledAt is set

Completion threshold​

An order's completion threshold is the greater of ORDER_COMPLETION_THRESHOLD_USDC (default 1 USDC) and requestedUsdcAmount × ORDER_COMPLETION_THRESHOLD_BPS / 10_000 (BPS default 100, or 1%). Both the floor and the percentage are current settings applied on each rollup; changing either applies to every order on its next rollup, including existing orders and late settlements. For example, with the defaults, a 1,000 USDC order completes once 10 USDC or less remains, while a 20 USDC order (1% is 0.2 USDC) completes once 1 USDC or less remains due to the floor. A split-fee order uses the larger of that threshold and its split-fee pricing tolerance. The residual stays in remainingUsdcAmount, and refunds use the settled payment amount.

Transitions​

FromToTriggerWebhook
noneCREATEDOrder created through the SDK, the API, or the dashboardORDER_CREATED
CREATEDCREATED (amounts change)Customer resizes a dynamic order. Only while the order is untouched and has no open or expired payment attemptORDER_RESIZED
CREATEDCREATED (amount saved)Customer starts a payment with a new amount on an open-amount order. Only while no payment can still completeORDER_AMOUNT_SET, then PAYMENT_CREATED
CREATED, PARTIALLY_FULFILLEDPARTIALLY_FULFILLEDA payment settles and the remaining amount is still above the order's completion thresholdPAYMENT_SETTLED
CREATED, PARTIALLY_FULFILLEDFULFILLEDA payment settles and the remaining amount is 0 or at or below the order's completion thresholdPAYMENT_SETTLED, then ORDER_FULFILLED
CREATEDCANCELLEDMerchant cancels from the dashboard. Rejected once any payment attempt existsORDER_CANCELLED

Rules that follow from this:

  • Orders never expire and never fail. There is no EXPIRED or FAILED order status. The customer payment window applies to the payment, below. The dashboard's Active and Expired filters are derived from payment state, not stored on the order.
  • PARTIALLY_FULFILLED cannot be cancelled. Cancellation is only possible before the first payment attempt, and only from the dashboard, not with an API key.
  • status and remainingUsdcAmount always agree in any snapshot.
  • An open-amount order has no amount until a payment starts. It stays CREATED with requestedUsdcAmount and remainingUsdcAmount set to null and amountVersion 0. Every payment start with a new amount saves both amounts and raises amountVersion by one.
  • chargebackStatus and refundStatus are additive. Neither changes status.

Terminal States​

StatusIs Terminal
CREATEDNo
PARTIALLY_FULFILLEDNo
FULFILLEDYes
CANCELLEDYes

New payment attempts are refused on a terminal order.


Payment Status​

A payment is one customer attempt to pay an order on one rail. This is the data.payment.status value you reconcile on in webhooks, and the status on rows from the Payments API.

const CheckoutPaymentStatus = {
CREATED: 'CREATED',
SETTLED: 'SETTLED',
CANCELLED: 'CANCELLED',
EXPIRED: 'EXPIRED',
FAILED: 'FAILED',
} as const;

Status Descriptions​

StatusDescription
CREATEDAttempt open. The customer is inside their window, sending money or waiting for verification. quoteExpiresAt is the cutoff
SETTLEDSettled onchain. netSettledUsdcAmount and fulfillTransaction are populated and completedAt is set. penalties lists any attestation-applied reductions, for example purchase protection
EXPIREDquoteExpiresAt elapsed while the attempt was still open. Not terminal: a late settlement can still land, and a recreate reopens it
FAILEDThe attempt could not be started onchain, or a crypto transfer stalled. A rejected verification does not move a payment here; it stays CREATED so the customer can retry. Usually terminal; a stalled crypto payment reopens if the deposit arrives late
CANCELLEDThe customer abandoned this attempt, for example by switching rail. Terminal on every rail except Zcash, where a deposit that lands on a cancelled attempt still settles it for 30 days after the attempt was created

The customer payment window​

quoteExpiresAt is set when the attempt is created: 1 hour for fiat rails, 6 hours 10 minutes for Relay, and the provider's deposit deadline for Zcash (currently requested for 20 minutes). Follow the actual checkout countdown. A fiat attempt still open at its cutoff becomes EXPIRED and fires PAYMENT_EXPIRED.

Live crypto attempts behave differently by provider. A Relay-backed attempt never becomes EXPIRED: a transfer that fails or is refunded is marked FAILED at once, and one still unresolved after about 6 hours 20 minutes is marked FAILED too, both firing PAYMENT_FAILED. A Zcash attempt that is never funded does become EXPIRED, about 6 hours 20 minutes after it was created. That backend stall window does not extend the displayed deposit deadline. Eligible expired or cancelled Zcash attempts remain checked for late deposits for up to 30 days from creation, unless the provider quote is already FAILED or REFUNDED. Sandbox crypto attempts expire on their quote window like fiat ones.

Transitions​

FromToTriggerWebhook
noneCREATEDCustomer picks a rail on an open orderPAYMENT_CREATED
CREATEDSETTLEDSettlement confirmed onchain, whether by buyer-verified proof, Seller Automated Release, or a crypto fillPAYMENT_SETTLED, plus ORDER_FULFILLED when the order completes, plus PAYMENT_BRIDGE_PENDING when a payout bridge starts
CREATEDEXPIREDFiat or sandbox quote window elapsed; live unfunded Zcash reached its backend stall windowPAYMENT_EXPIRED
CREATEDFAILEDThe attempt could not be started onchain, or a crypto transfer stalledPAYMENT_FAILED
CREATEDCANCELLEDCustomer cancels or switches method on the checkoutPAYMENT_CANCELLED
EXPIREDSETTLEDLate onchain settlement after the windowPAYMENT_SETTLED, plus ORDER_FULFILLED when the order completes
CANCELLEDSETTLEDA late Zcash deposit lands on a cancelled attemptPAYMENT_SETTLED, plus ORDER_FULFILLED when the order completes
EXPIRED, FAILED, CANCELLEDCREATEDA recreate reopens an eligible fiat attemptNone
EXPIREDCREATEDAn intent extension lands with an expiry in the future, from an extend or from Peer support extending the onchain intentNone
FAILEDCREATEDA stalled crypto deposit is observed settling late; settlement then followsNone, then PAYMENT_SETTLED

SETTLED is terminal. A Relay crypto payment can settle from its onchain payout receipt before Relay publishes its fee and deposit accounting. Within minutes Peer then refines totalUsdcFeeAmount, referralFees, paymentAmount, currency and currencyPerUsdRate on the settled payment without sending another event. netSettledUsdcAmount never decreases; it only increases when another deposit to the same address also succeeded. Until Relay's accounting arrives, a merchant-pays-fee order paid in a stablecoin is credited conservatively, about 0.2% below the deposit. When that brief shortfall is above the order's completion threshold the order shows PARTIALLY_FULFILLED with a slightly higher remainingUsdcAmount, then moves to FULFILLED and sends ORDER_FULFILLED.

One cancellation is silent: when a customer starts a fresh Zcash attempt on an order that already has an unfunded one, the old attempt is cancelled in the same transaction and no PAYMENT_CANCELLED fires. CANCELLED can therefore show up in a read back with no event behind it.

Reconciliation guidance: PAYMENT_EXPIRED and PAYMENT_FAILED do not touch the order. Treat the order as done only on ORDER_FULFILLED, or when data.order.status is FULFILLED. Do not close your side on a payment-level terminal event alone.


Chargeback Status​

Orders and payments carry a chargeback status alongside their lifecycle status. A chargeback never changes FULFILLED or SETTLED; it is an additive fact recorded after settlement.

const OrderChargebackStatus = {
NONE: 'NONE',
PARTIALLY_CHARGEBACKED: 'PARTIALLY_CHARGEBACKED',
CHARGEBACKED: 'CHARGEBACKED',
} as const;

const PaymentChargebackStatus = {
NONE: 'NONE',
CHARGEBACKED: 'CHARGEBACKED',
} as const;
StatusDescription
NONENo settled payment on the order has been charged back
PARTIALLY_CHARGEBACKEDSome, but not all, currently settled payments carry a chargeback
CHARGEBACKEDEvery currently settled payment carries a chargeback. A single-payment order goes here directly

The order value is not monotonic: a later settlement can move an order from CHARGEBACKED back to PARTIALLY_CHARGEBACKED. Reconcile from the snapshot in each chargeback event rather than ranking transitions.


Refund Status​

const CheckoutOrderRefundStatus = {
NONE: 'NONE',
PENDING: 'PENDING',
COMPLETED: 'COMPLETED',
} as const;
StatusDescription
NONENo refund on the order
PENDINGRefund started; REFUND_PENDING emitted on the first move from NONE
COMPLETEDRefund completed; REFUND_COMPLETED emitted

Refunds apply to FULFILLED orders only.


Webhook Delivery Status​

const WebhookDeliveryStatus = {
PENDING: 'PENDING',
DELIVERED: 'DELIVERED',
FAILED: 'FAILED',
} as const;
StatusDescription
PENDINGAwaiting delivery or retry
DELIVEREDSuccessfully delivered (2xx response)
FAILEDAll 7 attempts exhausted, or delivery aborted because the webhook was inactive, its URL no longer resolves to a public HTTPS host, or it was a test delivery whose single attempt failed

See the retry policy for the schedule.