Guide
Orders and fulfilment
The order lifecycle: statuses, editing line items, backorders, cancellation requests, forwarding and book-back. What each state actually means and which transitions are safe to automate.
What the order states mean, how line items change under you, and which operations are safe to run unattended.
Statuses
open · pending · on-hold · completed · cancelled
Filter with ?status=open, or pass several comma separated. An order arriving from a marketplace can land in any of them: a bol.com import can arrive already completed, which is why orders.completed fires on arrival as well as on transition.
Reading an order
GET /orders
gives you a page of summaries. GET /orders/get-single
takes either order_pk or order_number, and returns the full record with line items, addresses and channel.
Two identifiers appear throughout the order endpoints and they are not interchangeable:
order_pkis Stockpilot’s internal primary key. Most endpoints want this.order_numberis the human or marketplace facing reference.
The path parameter is sometimes named order_id and sometimes order_pk for the same value. Read the parameter name on each endpoint rather than assuming.
Editing line items
An order is not frozen once created. Four operations change its contents:
| Operation | Endpoint |
|---|---|
| Add a product | POST /orders/{order_pk}/items/add |
| Replace the product on a line, keeping quantity and price | POST /orders/{order_pk}/items/swap |
| Change quantity or record a refund | PATCH /orders/ordered-items/{item_id}/update |
| Remove a line | DELETE /orders/{order_id}/items/{item_id} |
items/add is not idempotent. A retry adds a second line rather than reconciling with the first. If the call fails ambiguously, re-read the order and check before sending it again. See rate limits and idempotency.
Deleting a line takes book_back, which decides whether the quantity returns to sellable stock. Omitting it is a decision, not a default to ignore: the units either come back into inventory or they do not.
Backorders
When stock will not cover a line, move it to backorder rather than leaving the order stuck:
POST /orders/{order_id}/move-to-backorder{
"backorder_items": [
{ "item_id": 123, "quantity": 5 },
{ "item_id": 456, "quantity": 2 }
]
}
The response reports what actually moved, per line:
{
"message": "Successfully moved 2 item(s) to backorder",
"items_processed": 2,
"backorder_status": "partial",
"backorder_results": [
{ "item_id": 123, "quantity_moved": 5, "new_backorder_qty": 5 }
]
}
Note backorder_status: "partial". Read the per line results rather than assuming a 200 moved everything you asked for.
Release them with POST /orders/{order_id}/move-from-backorder once stock lands. Neither direction is idempotent, because both apply a delta to a running backorder quantity.
Cancellations
There are two different things here, and conflating them is a common bug.
- A cancellation request is a marketplace or customer asking. GET /orders/cancellation-requests lists orders with an open request; GET /orders/cancellation-request checks one order.
- A cancellation is you acting. PUT /orders/cancel-order cancels the order.
A request does not cancel anything on its own. If you are building a queue for warehouse staff, poll the requests endpoint and let a human decide, especially for orders already picked.
Deleting an order
DELETE /orders/{order_id}
removes the order entirely, and takes book_back to decide whether every line’s quantity returns to inventory.
Deletion is not cancellation. A cancelled order stays in the record with a cancelled status and remains visible in reporting. A deleted order is gone. Reach for cancel-order unless you specifically need the record removed.
Forwarding
If another system fulfils an order, mark it forwarded so Stockpilot stops pulling it from the marketplace again:
PATCH /orders/{order_id}/update-forwarding{ "register_order_id": "MP-12345", "source": "api" }
The returned id is prefixed:
{
"forwarded_order_id": "FWD-MP-12345",
"message": "Forwarding details updated.",
"to_forwarded_channel": "api"
}
That FWD- prefix is what prevents duplicate fetching, so store the returned value rather than reconstructing it yourself. Channels also carry a channel_is_forwarded flag, covered in sales channels.
Fulfilment
POST /orders/fulfil records that an order shipped: carrier, tracking code, tracking URL, shipping method and timestamp. It also accepts a list of items, so partial fulfilment is a matter of naming the lines and quantities that actually went out.
Confirm with GET /orders/fulfillment , which returns the tracking details as stored.
Fulfilment and label buying are separate steps. Getting a label does not fulfil the order, and fulfilling does not buy a label. Shipping and labels covers the ordering, and Order to label walks the whole path.
Updating status directly
PATCH /orders/{order_id}/update-status sets the status field. It is an absolute write, so it is safe to retry.
Use it to reflect a decision you have already made, not to drive the pipeline. Setting an order to completed does not fulfil it, ship it, or move any stock.
