Documentation
Partner API

Lifecycle and events

Every state a partner order passes through, every transition and who makes it, the event envelope with its sequence number, and every event type.

Updated 2026-10-24MarkdownOpenAPI

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.

Partner order lifecyclereceived leads to pending_review after pricing; an engineer accepts or rejects; accepted orders go to in_production, ready_to_ship, shipped and delivered. You may cancel while received, pending_review or accepted. Any state before shipped may be put on hold and released back.receivedpending_reviewacceptedin_productionready_to_shipshippeddeliveredorder.pricedorder.acceptedin_productionready_to_shiporder.shippedorder.deliveredorder.rejectedrejectedorder.cancelled (you)cancelledorder.on_holdorder.releasedon_holdfinal states have a green edge · on_hold returns to the state it came from · any state before shipped may be held

States

StateMoved there byWhat it means
receivedyouYour POST /v1/orders was accepted and every item is being priced. You may cancel.
pending_reviewpricingEvery 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.
acceptedengineerIn 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_productionproductionPrinting. From here on, cancellation goes through us: write from the order page.
ready_to_shipproductionPassed quality check and packed.
shippedcourierHanded to the courier; shipments[] carries the tracking number and URL. Tracking updates follow as order.tracking_updated.
deliveredcourierThe parcel arrived. Final.
on_holdengineerWe need something from you before going on — hold.reason says what. The order returns to its previous state when released.
rejectedengineerDeclined with a reason you can act on: rejection.code, rejection.message and the engineer's rejection.note. Final.
cancelledyouCancelled by you (POST /v1/orders/{id}/cancel) or by us at your request. Final.

Transitions

FromToEventActor
receivedpending_revieworder.pricedpricing
receivedpending_revieworder.pricing_failedpricing
pending_reviewacceptedorder.acceptedengineer
pending_reviewrejectedorder.rejectedengineer
acceptedin_productionorder.in_productionproduction
in_productionready_to_shiporder.ready_to_shipproduction
ready_to_shipshippedorder.shippedcourier
shippeddeliveredorder.deliveredcourier
receivedcancelledorder.cancelledyou
pending_reviewcancelledorder.cancelledyou
acceptedcancelledorder.cancelledyou
in_productioncancelledorder.cancelledengineer
ready_to_shipcancelledorder.cancelledengineer
receivedon_holdorder.on_holdengineer
pending_reviewon_holdorder.on_holdengineer
acceptedon_holdorder.on_holdengineer
in_productionon_holdorder.on_holdengineer
ready_to_shipon_holdorder.on_holdengineer
on_hold(previous state)order.releasedengineer

Who acts

  • You — create the order, cancel it while it is received, pending_review or accepted, erase the recipient once it is final; in test, advance it.
  • Pricing — slices and prices every item within minutes: order.priced, or order.pricing_failed when an item needs a hand.
  • An engineer — accepts, rejects, holds and releases; prices by hand the items the slicer left unpriced.
  • Production — in_production when printing starts, ready_to_ship after quality check and packing.
  • The courier — shipped with tracking, tracking_updated, delivered, and returned when 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:

JSON
{
  "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"
    }
  }
}
FieldMeaning
idThe event id. A webhook delivery of this event carries it as event_id; the delivery's own id is webhook-id.
typeOne of the types below.
api_versionThe API version the payload follows — 2026-10-24.
seqPer partner and per environment, gap-free, strictly increasing. The authoritative order of everything that happened.
reason_codeSet when a transition had a reason you can act on — a hold, a rejection, a reconciliation.
dataThe 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

Typedata keyProduced byWhen
order.receivedorderyouYour POST /v1/orders was accepted for pricing.
order.pricedorderpricingEvery item has a price; the order is pending_review.
order.pricing_failedorderpricingAn item needs a hand to price; an engineer prices it by hand or declines the order with a reason.
order.acceptedorderLayerCrewAn engineer accepted the order; the price is frozen and payment instructions are on it.
order.rejectedorderLayerCrewThe order was declined; data.order.rejection carries the code, the message and the engineer's note.
order.on_holdorderLayerCrewWe need something before going on; data.order.hold.reason says what.
order.releasedorderLayerCrewThe hold is over; the order is back in the state it had before.
order.in_productionorderLayerCrewPrinting started.
order.ready_to_shiporderLayerCrewPassed quality check and packed.
order.shippedordercourierHanded to the courier; data.order.shipments carries carrier, tracking number and URL.
order.tracking_updatedordercourierThe courier reported a new tracking status.
order.deliveredordercourierThe parcel arrived. Final.
order.cancelledorderyouCancelled by you, or by us at your request. Final.
order.paidorderLayerCrewYour transfer arrived; data.order.payment.status is paid.
order.invoicedorderLayerCrewAn invoice was issued; fetch it with GET /v1/orders/{id}/invoices.
order.returnedordercourierThe parcel came back to us; we write to you.
order.recipient_redactedordersystemYour customer's personal data on this order was erased, on your request or at the end of the retention window.
quote.pricedquotepricingThe quote has a price.
quote.failedquotepricingPricing stopped; data.quote.failure_code says why and what to change.
file.readyfilesystemcomplete verified the upload; the file can be quoted and ordered.
file.rejectedfilesystemcomplete refused the upload; data.file.rejection_code says why.
file.purgedfilesystemThe file's bytes were deleted at the end of its retention.
agreement.acceptedagreementyouYour account owner accepted the integration and data processing agreements.
agreement.countersignedagreementLayerCrewLayerCrew countersigned; live keys can be issued.
key.issuedkeyyouAn API key was created (never carries the secret).
key.revokedkeyyouAn API key was revoked.
webhook_endpoint.disabledendpointsystemAn endpoint was disabled after sustained failures or a 410; an email goes out too.
webhook_endpoint.secret_rotatedendpointyouThe signing secret was rotated; both secrets are valid for 24 hours.
partner.suspendedpartnerLayerCrewThe account was suspended; keys answer PARTNER_INACTIVE until it is active again.
partner.activatedpartnerLayerCrewThe account is active.
usage.warningusagesystemA monthly cap on your plan reached 80 percent; once per cap per month.
test.ping{}youYou 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.

We value your privacy

We use cookies for analytics and advertising to improve your experience and measure our marketing. See our Privacy Policy.