Skip to main content
POST
Create Fulfillment
Creates a fulfillment record on the order and, when status is a terminal success state, automatically bumps order.status to shipped (or delivered). Shipping apps don’t need a second call to update the order — one POST writes the tracking number, courier, and status in a single request.
This endpoint is the write-back half of the live-rate flow. For the full lifecycle (quote → checkout pick → orders/create webhook → push to carrier → call this endpoint with the AWB), see Live Rate Providers and Build a shipping app.

When the order status changes

Each Fulfillment row represents one shipment. After every write, the platform recomputes coverage by summing lineItems[].quantity across all success-state Fulfillment rows for the order and updates order.status accordingly: The order lifecycle is:
order.status is only mutated from pending, confirmed, paid, or partial. Manual overrides (shipped set by the merchant) and terminal states (canceled/delivered) are never trampled. One exception: a fulfillment with status delivered also moves an order that is already shipped to delivered. Without it a delivered parcel sat at shipped forever, since shipped is otherwise not a mutable state — carrier tracking could never complete the order.

Multi-package orders

For orders that ship in multiple packages, POST one fulfillment per shipment and include only the items in that package in line_items. The platform tracks coverage per line_item.id:
Omitting line_items is the back-compat shortcut for single-shipment orders: the fulfillment is treated as covering everything, so a single POST flips order.status straight to shipped (skipping partial).

Path Parameters

string
required
The order ID

Body Parameters

string
default:"pending"
Initial fulfillment status. Set to success to immediately mark the shipment as out the door — this is what bumps order.status to shipped. Allowed: pending, open, success, shipped, delivered, cancelled, error, failure.shipped and delivered are terminal carrier states, typically written later from tracking rather than at creation. Prefer update for progressing an existing shipment — posting a second fulfillment for the same parcel leaves the order showing the same tracking number twice.
string
Carrier tracking number (e.g. AWB code).
string
Carrier name (e.g. "UPS", "FedEx", "USPS", "DHL", "Shiprocket").
string
Public, shopper-facing tracking URL. Must be a valid URL.
string
Optional. The ID of the fulfillment service that produced this shipment, returned by Create Fulfillment Service. Caching this on a shop metafield after registration avoids a list-call on every push.
array
Optional. Items being fulfilled in this shipment. Omit for single-shipment orders where every line item ships together.
boolean
default:"true"
Send shipment notification email to the customer.

Side effects

When the call succeeds:
  1. A fulfillment record is created on the order.
  2. If status triggers a status flip (see table above), order.status is updated in the same request.
  3. A fulfillments/create webhook is dispatched to every subscriber on the store (3-retry exponential backoff: 1m / 5m / 15m).

Required scope

write_orders

Request example

Response

order.status is not returned in this response — the order row is updated as a side effect. Re-fetch the order via Get Order if you need the new status in the same flow.