Orders and fulfilment
Carts
The buying workspace — lifecycle, items, claim, merge, conversion to an order, CSV import and export.
Orders
POST /orders/place and the state machine — acknowledge, hold, ship, complete, cancel, item-level cancel.
Returns
A sub-resource of an order. Register, receive, then complete or reject.
Order lists
Saved reusable position collections — kinds, positions, and the two routes that turn one into a cart or an order.
Stock
Locations, stock levels, the movements ledger, and availability as the designated override point.
Events and comments
The append-only audit trail, operator notes, and the customer rollup report.
Number ranges
How orders, delivery notes and returns get their numbers, and the shape a merchant gives them.
Four apps carry this flow, and each owns one stage:
| App | Base path | Owns |
|---|---|---|
| carts | /v1/carts | The buying workspace, until it becomes an order |
| orderlists | /v1/orderlists | Saved, reusable position collections |
| orders | /v1/orders | The order, its shipments, cancellations, returns and audit trail |
| inventories | /v1/inventories | Locations, stock levels, the movements ledger, reservations |
The one design rule to internalise
Each route does exactly one thing, and the orchestration is yours. Placing an order does not reserve stock, take payment or talk to an ERP. Shipping does not print a label. Cancelling refunds nothing and returns nothing to stock. Completing a return books the goods on the order and hands you a restock array to pass on.
That is deliberate: an order lifecycle differs per merchant, and an app that fused the steps would be un-composable. What ties the steps together is the event trail — every action writes an order_events row, which is also the domain event a workflow reacts to, so what a workflow saw and what an operator reads cannot diverge.
The happy path
POST /v1/carts open a cart
POST /v1/carts/{id}/items add lines
POST /v1/carts/{id}/order close the cart, hand off ─┐
POST /v1/orders/place the order comes into being ┘
POST /v1/orders/{id}/acknowledge the fulfilling system took it
POST /v1/inventories/reserve hold the stock
POST /v1/orders/{id}/ship book goods out
POST /v1/inventories/commit consume the reservation
POST /v1/orders/{id}/payment-status record what the money did
POST /v1/orders/{id}/complete close it (or let shipping close it)
And when goods come back:
POST /v1/orders/{id}/return register the case
POST /v1/orders/{id}/returns/{rid}/receive the parcel is here
POST /v1/orders/{id}/returns/{rid}/complete accept it — books quantity_returned
POST /v1/inventories/restock put the sellable goods back
/v1/returns. A return is a sub-resource of an order and has no top-level path. See Returns.Five status dimensions, and they are orthogonal
| Dimension | Values | Written by |
|---|---|---|
status | pending, placed, in_fulfillment, completed, cancelled | The action routes |
fulfillment_status | unfulfilled, partial, fulfilled | Derived from position arithmetic |
payment_status | open, pending, authorized, paid, partially_paid, refunded, failed | Fed in by whatever took the money |
on_hold + hold_reason | boolean | hold / unhold, and deliberately outside the lifecycle |
Return status | registered, received, completed, rejected | The four return routes |
In this group
- Carts — the workspace before an order.
- Orders — placement and the state machine.
- Returns — the four-step return case.
- Order lists — reusable position collections.
- Stock — what these movements consume.
- Events and comments — the audit trail.
- Number ranges — where the numbers come from.