Order lifecycle

Updated May 26, 20264 min read

This page explains how an Order progresses from ingestion to closure. It also shows how Order status rolls up from fulfillment orders and Shipments. All three lifecycles are distinct but connected; knowing how they relate is the foundation of order management.

Status flow

An Order's status is computed from the statuses of its Fulfillment orders. Fulfillment order status is in turn computed from the statuses of its line items. The progression looks like:

open → partially_allocated → allocated → processing → fulfilled → closed
                                                                 ↘ cancelled (alternative terminal)
StatusMeaning
openNo fulfillment orders yet, or all FOs are still open.
partially_allocatedSome FOs are allocated; others are still open.
allocatedAll FOs reached at least allocated.
processingAt least one FO is in pick / pack / fulfillment.
fulfilledAll FOs are fulfilled (or in a terminal state).
closedAll Shipments delivered → line items closed → FOs closed → Order closed.
cancelledEvery FO was cancelled.

For the full criteria, see Order status codes.

How the rollup works

The cascade from leaf to root:

  1. A Shipment reaches delivered.
  2. Every line item linked to that Shipment moves to closed.
  3. The fulfillment order moves through processingfulfilledclosed as its line items reach those states.
  4. The Order moves through allocatedprocessingfulfilledclosed as its FOs reach those states.

Cancellations propagate the same way: when every leaf is cancelled the parent flips to cancelled.

See Fulfillment order status codes and Line item status codes for the full criteria at each level.

Order status vs shipment status

A common point of confusion. They're related but answer different questions:

StatusQuestion it answers
Order status"How far through fulfillment is this customer purchase?"
Shipment status"Where is this specific parcel right now?"

An Order can be fulfilled while one of its Shipments is still in_transit. The Order moves to fulfilled once handover is complete; delivery (and the cascade to closed) can follow later.

Allocation timing

When does allocation happen? Two patterns:

  • At ingestion. Allocation rules fire as soon as the order lands. Fulfillment orders are created and allocated immediately. Best when inventory and rules are stable enough to commit early.
  • On-demand. The Order sits in open while ops or an upstream system decides allocation. Fulfillment orders are produced manually or via a deferred rule run.

Both are valid. Most integrations pick at-ingestion for speed; ops override (re-allocate) when needed.

Cancellation semantics

Cancelling the whole Order. An Order can be cancelled only while it's in open, partially_allocated, or allocated. Once any FO enters processing, wholesale order cancellation is no longer allowed. Cancellation must then happen at the fulfillment order or line-item level.

Cancelling a fulfillment order that has already been fulfilled. A fulfilled FO must be unfulfilled before it can be cancelled. Unfulfilling reverses the fulfillment state and cascades back to Shipments. Any Shipment whose items all become unfulfilled is automatically cancelled, provided the Shipment is still in a cancellable state.

Partial cancellation. Cancelling a single line item or Fulfillment order while leaving the others in place is supported. The Order continues toward fulfilled / closed based on the lines that did fulfil.

Closing an order from external status updates

When a partner system books and tracks the parcel outside Carriyo, Carriyo can still act as the order of record. Use POST /orders/shipment-status-update to push a Shipment payload keyed by references.partner_order_reference. When post_shipping_info.status is delivered, Carriyo runs the standard auto-close logic on the matched fulfillment line items. That cascade propagates through to fulfillment order and Order status.

The payload uses the Carriyo Shipment shape, so a partner system can forward what it already has, with no shape translation needed. Shopify-sourced orders are skipped (Shopify manages its own order closure).

Audit and diagnostics

Every order exposes two log types:

  • Change logs. GET /orders/{reference}/change-logs returns the transactional history of the order itself: creation, status transitions, field updates, line-item changes. Sorted oldest-first by default; pass sort_order=DESC for newest-first.
  • System logs. GET /orders/{reference}/system-logs returns a paginated list of integration log entries: outbound API calls, webhook deliveries, and other traffic associated with the order. Filter by correlation_id, event_type, request_type, or HTTP response code. For a single entry's full request/response payload, call GET /orders/{reference}/system-logs/{identifier} to get a time-limited presigned URL to the S3-stored body. You can also push entries inbound via POST /orders/{reference}/system-logs to record your own middleware traffic against the order.

Change logs answer "what changed and when"; system logs answer "what did the integrations actually exchange". Together they're the first diagnostic stop when an order looks wrong.

How it fits with other modules

  • Shipping. Order fulfillment produces shipments; shipment delivery cascades back into FO and Order status.
  • Inventory. Allocation decisions often depend on inventory visibility per location.
  • Returns. Return requests reference an order via partner_order_reference.