A partner order moves through a fixed set of states. Every move is an event with a timestamp, an actor and a per-partner sequence number — listable on the order, on the account feed and delivered to your webhooks.
States
| State | Moved there by | What it means |
|---|---|---|
received | you | Your POST /v1/orders was accepted and every item is being priced. You may cancel. |
pending_review | pricing | Every item has a price (pricing_status: priced), or one needs a hand to price (failed); an engineer is looking at the order. You may cancel. |
accepted | engineer | In the production queue. The price is frozen (pricing.final: true), payment instructions are on the order, and production starts after payment unless your plan says otherwise. You may still cancel. |
in_production | production | Printing. From here on, cancellation goes through us: write from the order page. |
ready_to_ship | production | Passed quality check and packed. |
shipped | courier | Handed to the courier; shipments[] carries the tracking number and URL. Tracking updates follow as order.tracking_updated. |
delivered | courier | The parcel arrived. Final. |
on_hold | engineer | We need something from you before going on — hold.reason says what. The order returns to its previous state when released. |
rejected | engineer | Declined with a reason you can act on: rejection.code, rejection.message and the engineer's rejection.note. Final. |
cancelled | you | Cancelled by you (POST /v1/orders/{id}/cancel) or by us at your request. Final. |
Transitions
| From | To | Event | Actor |
|---|---|---|---|
received | pending_review | order.priced | pricing |
received | pending_review | order.pricing_failed | pricing |
pending_review | accepted | order.accepted | engineer |
pending_review | rejected | order.rejected | engineer |
accepted | in_production | order.in_production | production |
in_production | ready_to_ship | order.ready_to_ship | production |
ready_to_ship | shipped | order.shipped | courier |
shipped | delivered | order.delivered | courier |
received | cancelled | order.cancelled | you |
pending_review | cancelled | order.cancelled | you |
accepted | cancelled | order.cancelled | you |
in_production | cancelled | order.cancelled | engineer |
ready_to_ship | cancelled | order.cancelled | engineer |
received | on_hold | order.on_hold | engineer |
pending_review | on_hold | order.on_hold | engineer |
accepted | on_hold | order.on_hold | engineer |
in_production | on_hold | order.on_hold | engineer |
ready_to_ship | on_hold | order.on_hold | engineer |
on_hold | (previous state) | order.released | engineer |
Who acts
- You — create the order, cancel it while it is
received,pending_revieworaccepted, erase the recipient once it is final; in test, advance it. - Pricing — slices and prices every item within minutes:
order.priced, ororder.pricing_failedwhen an item needs a hand. - An engineer — accepts, rejects, holds and releases; prices by hand the items the slicer left unpriced.
- Production —
in_productionwhen printing starts,ready_to_shipafter quality check and packing. - The courier —
shippedwith tracking,tracking_updated,delivered, andreturnedwhen a parcel comes back.
The event envelope
The envelope is the same on the account feed, on the order's events and in a webhook body:
{
"id": "9c8b7a6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
"type": "order.shipped",
"api_version": "2026-10-24",
"created_at": "2026-10-27T14:05:12Z",
"seq": 1234,
"environment": "live",
"reason_code": null,
"data": {
"order": {
"id": "7a3e9c10-2b4d-4f61-9e8a-5c6d7e8f9a0b",
"number": "PA-2026-0007",
"reference": "SHOP-10231",
"status": "shipped",
"shipments": [
{
"carrier": "FAN Courier",
"tracking_number": "2057100012345",
"tracking_url": "https://www.fancourier.ro/awb-tracking/?awb=2057100012345",
"status": "shipped",
"shipped_at": "2026-10-27T14:05:00Z",
"delivered_at": null
}
],
"metadata": {
"shop_order_id": "10231"
},
"…": "the rest of the order, exactly as GET /v1/orders/{id} returned it at that moment"
}
}
}| Field | Meaning |
|---|---|
id | The event id. A webhook delivery of this event carries it as event_id; the delivery's own id is webhook-id. |
type | One of the types below. |
api_version | The API version the payload follows — 2026-10-24. |
seq | Per partner and per environment, gap-free, strictly increasing. The authoritative order of everything that happened. |
reason_code | Set when a transition had a reason you can act on — a hold, a rejection, a reconciliation. |
data | The object the event is about: order for order.*, quote for quote.*, file for file.*, endpoint for webhook_endpoint.*, key for key.* (never the secret), usage for usage.warning, {} for test.ping. Rendered once at event time and stored; data.order is exactly what GET /v1/orders/{id} returned then, and a redelivery sends the same bytes. |
Event types
| Type | data key | Produced by | When |
|---|---|---|---|
order.received | order | you | Your POST /v1/orders was accepted for pricing. |
order.priced | order | pricing | Every item has a price; the order is pending_review. |
order.pricing_failed | order | pricing | An item needs a hand to price; an engineer prices it by hand or declines the order with a reason. |
order.accepted | order | LayerCrew | An engineer accepted the order; the price is frozen and payment instructions are on it. |
order.rejected | order | LayerCrew | The order was declined; data.order.rejection carries the code, the message and the engineer's note. |
order.on_hold | order | LayerCrew | We need something before going on; data.order.hold.reason says what. |
order.released | order | LayerCrew | The hold is over; the order is back in the state it had before. |
order.in_production | order | LayerCrew | Printing started. |
order.ready_to_ship | order | LayerCrew | Passed quality check and packed. |
order.shipped | order | courier | Handed to the courier; data.order.shipments carries carrier, tracking number and URL. |
order.tracking_updated | order | courier | The courier reported a new tracking status. |
order.delivered | order | courier | The parcel arrived. Final. |
order.cancelled | order | you | Cancelled by you, or by us at your request. Final. |
order.paid | order | LayerCrew | Your transfer arrived; data.order.payment.status is paid. |
order.invoiced | order | LayerCrew | An invoice was issued; fetch it with GET /v1/orders/{id}/invoices. |
order.returned | order | courier | The parcel came back to us; we write to you. |
order.recipient_redacted | order | system | Your customer's personal data on this order was erased, on your request or at the end of the retention window. |
quote.priced | quote | pricing | The quote has a price. |
quote.failed | quote | pricing | Pricing stopped; data.quote.failure_code says why and what to change. |
file.ready | file | system | complete verified the upload; the file can be quoted and ordered. |
file.rejected | file | system | complete refused the upload; data.file.rejection_code says why. |
file.purged | file | system | The file's bytes were deleted at the end of its retention. |
agreement.accepted | agreement | you | Your account owner accepted the integration and data processing agreements. |
agreement.countersigned | agreement | LayerCrew | LayerCrew countersigned; live keys can be issued. |
key.issued | key | you | An API key was created (never carries the secret). |
key.revoked | key | you | An API key was revoked. |
webhook_endpoint.disabled | endpoint | system | An endpoint was disabled after sustained failures or a 410; an email goes out too. |
webhook_endpoint.secret_rotated | endpoint | you | The signing secret was rotated; both secrets are valid for 24 hours. |
partner.suspended | partner | LayerCrew | The account was suspended; keys answer PARTNER_INACTIVE until it is active again. |
partner.activated | partner | LayerCrew | The account is active. |
usage.warning | usage | system | A monthly cap on your plan reached 80 percent; once per cap per month. |
test.ping | {} | you | You asked for a test delivery with POST /v1/webhook-endpoints/{id}/ping. |
Polling the feed
curl "https://engine.layercrew.com/v1/events?after=1200&limit=100&types=order.shipped,order.delivered" \
-H "Authorization: Bearer $LAYERCREW_API_KEY"Store the last seq you processed and ask for what came after it; meta.next_after and meta.has_more drive the loop. GET /v1/orders/{id}/events does the same for one order. Webhooks carry the same events sooner; the feed is the truth when a webhook is late or missed — reconcile against it on a timer and on every restart. See Webhooks.