Order status flow
Every order carries a single canonical lifecycle field, status, returned by
GET /orders and GET /orders/{id}. Drive your integration off this field. Two supplementary
fields — paymentStatus and fulfillmentStatus — carry finer payment and logistics
detail, but they are not the state machine. Do not conflate the three.
The statuses
| status | What it means | Who moves it here | Your next action |
|---|---|---|---|
| READY_TO_SHIP | Payment is captured and the order is waiting for you to arrange shipment. This is the first state you ever see — the platform never exposes pre-payment states over the API. | Platform (buyer pays) | Arrange the pickup, then mark it shipped. |
| SHIPPED | You have handed the parcel to the courier; it is in transit. | You (POST /orders/{id}/ship) | Nothing — the courier and buyer drive delivery. |
| DELIVERED | The courier confirmed delivery and/or the buyer confirmed receipt. Terminal unless the buyer opens a return. | Platform (courier + buyer) | Nothing. See the escrow caveat below before you treat this as “done”. |
| CANCELLED | The order was cancelled before shipment, or cancelled as a result of a rejected return. Terminal. | You (POST /orders/{id}/cancel) or platform | Nothing. |
| RETURN_REFUND | The buyer opened a return after delivery. Terminal at the order level — track the resolution on the return object, not the order. | Platform (buyer initiates) | Review via GET /returns and approve or dispute. |
The flow
buyer pays
↓
READY_TO_SHIP ————→ CANCELLED (POST /orders/{id}/cancel, pre-ship only)
↓ POST /orders/{id}/ship
SHIPPED
↓ courier delivers + buyer confirms
DELIVERED ————→ RETURN_REFUND (buyer opens a return)
Cancellation is only valid while the order is READY_TO_SHIP. Once it is
SHIPPED, DELIVERED, CANCELLED or RETURN_REFUND, a cancel returns
422 ORDER_NOT_CANCELLABLE — handle it as a return instead.
Who drives each transition
Only three transitions are yours to make over the API. The rest happen platform- or buyer-side — react to them with webhooks rather than polling.
| Transition | Driven by | How you know |
|---|---|---|
| → READY_TO_SHIP | Buyer places the order & payment is captured | order.created |
| READY_TO_SHIP → SHIPPED | You — POST /orders/{id}/ship or bulk-ship | order.shipped + order.updated |
| READY_TO_SHIP → CANCELLED | You — POST /orders/{id}/cancel or bulk-cancel | order.cancelled + order.updated |
| SHIPPED → DELIVERED | Courier delivery + buyer confirmation | No delivery webhook — poll GET /orders/{id} (see caveat) |
| DELIVERED → RETURN_REFUND | Buyer opens a return | return.created |
How this maps to Seller Center
Sellers think in Seller Center tabs, not API enum values. When you talk to a seller about an order, this is the crosswalk:
| API status | Seller Center tab | Seller Center label |
|---|---|---|
| READY_TO_SHIP | To Ship | To Ship — once a pickup is booked, the seller sees the sub-state “Awaiting courier pickup” (still the To Ship tab) |
| SHIPPED | Shipping | Shipping |
| DELIVERED | Shipping, then Completed | Delivered while escrow is held; moves to Completed once escrow is released |
| CANCELLED | Return / Refund / Cancel | Cancelled |
| RETURN_REFUND | Return / Refund / Cancel | Return / Refund / Cancel |
Seller Center has a few sub-states the API does not expose as a distinct status: an
Unpaid stage (never visible over the API), a Processed / Awaiting courier pickup sub-state of To Ship, a
Failed Delivery flag (the order stays SHIPPED), and the escrow stages behind Completed.
Pre-shipment booking state
bookingStatus supplements the existing status field and distinguishes the
pre-shipment booking state while status remains READY_TO_SHIP. Use it when you need to mirror
the Seller Center movement from To Process to Processed.
| Seller Center stage | Order status | bookingStatus | Meaning |
|---|---|---|---|
| To Process | READY_TO_SHIP | PENDING_ARRANGE | Payment is captured and shipment has not been arranged. |
| Processed / Awaiting courier pickup | READY_TO_SHIP | READY_FOR_HANDOVER | Shipment is arranged and the parcel is waiting for courier pickup. |
Do not add a processed order status. PROCESSED is not a live production
Order.status value. Booking-arranged updates are signalled with bookingStatus on order reads
and order.updated webhook payloads.
DELIVERED is not “paid out”. Seller Center splits a delivered order into
Delivered (escrow still held) and Completed (escrow released). The API returns DELIVERED for
both — it has no separate “completed” value. If you trigger payout or reconciliation logic off
status == DELIVERED, it will fire before the money is released. For real settlement timing, use
GET /orders/{id}/payouts, not the order status.
Supplementary fields. paymentStatus (e.g. captured,
refunded) reflects the payment record, fulfillmentStatus (e.g. fulfilled,
shipped, delivered) reflects the logistics record, and bookingStatus reflects
the pre-shipment booking state. They are useful detail, but the status field is the one canonical lifecycle signal — build your state machine on it.
Sandbox exposes more states than production. The sandbox order simulator walks a longer
lifecycle (including PENDING, PAID, PROCESSED, COMPLETED) so you can
exercise each step. Production only ever returns the five values above — do not build logic that expects
PROCESSED or COMPLETED on a live order.