Fulfill a fulfillment order
Fulfilling a fulfillment order records that its items have been picked and packed and are leaving (or have left) the location. You can optionally have Carriyo create a shipment in the same call.
Use this recipe when picking and packing happen outside Carriyo, for example in your own warehouse system. If your team picks and packs in Carriyo, completing the pack fulfills the line items for you.
Scenario
A fulfillment order at the New Jersey warehouse holds two lines: a keyboard and a monitor. The warehouse has picked and packed both. Ops marks the fulfillment order fulfilled and asks Carriyo to create a draft shipment, so it can be reviewed before booking with a carrier.
Prerequisites
- API credentials: see Getting started.
- An order with an allocated fulfillment order to fulfill, see Place an order with multiple fulfillment orders.
Starting state
Order OMTV36M0ACTKSZT, fulfillment order FOMTV36M0F6RRSMM at
NJ-WH-01, in allocated, carrying:
- Keyboard, line item id
line-kbd, quantity 1 - Monitor, line item id
line-mon, quantity 1
Fulfill the fulfillment order
curl -X POST \
'https://api.carriyo.com/orders/OMTV36M0ACTKSZT/fulfillment-orders/FOMTV36M0F6RRSMM/fulfill?create_draft_shipment=true' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'tenant-id: YOUR_TENANT_ID' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"partner_fulfillment_reference": "YOUR_FULFILLMENT_REF",
"line_items": [
{ "id": "line-kbd", "quantity": 1 },
{ "id": "line-mon", "quantity": 1 }
]
}'
line_itemsnames the lines (and quantities) being fulfilled, referenced by the order line itemid. Each must still be pending:open,allocated,pick_in_progress,picked, orpack_in_progress.partner_fulfillment_referenceis your warehouse's reference for this fulfillment, recorded against each fulfilled line.
Two query parameters control what happens to shipping:
create_draft_shipment=true(used here): create a draft shipment alongside the fulfillment, for review before you book it with a carrier. See Draft then confirm.skip_shipping=true: fulfill without creating any shipment. Useful for digital goods or a local collection.
Omit both to fulfill and book a shipment with a carrier in one
step. Booking is asynchronous: the shipment is submitted to the
carrier and comes back pending, resolving to booked (or error)
later via webhook. See
Book a shipment.
Read the response
The fulfillment order transitions to fulfilled. Each fulfilled line carries the
fulfillment_id Carriyo assigned, your partner_fulfillment_reference,
and shipment_ids, the shipment(s) created for it (response
abridged):
{
"order_id": "OMTV36M0ACTKSZT",
"merchant": "ACME",
"partner_order_reference": "YOUR_ORDER_REF",
"status": "fulfilled",
"fulfillment_orders": [
{
"fulfillment_order_id": "FOMTV36M0F6RRSMM",
"partner_fulfillment_order_reference": "YOUR_ORDER_REF-NJ",
"fulfillment_location": {
"partner_location_id": "ACCOUNT_f2b82334-96d6-43bb-987d-ca36c2305824",
"partner_location_code": "NJ-WH-01",
"partner_location_name": "New Jersey Warehouse"
},
"status": "fulfilled",
"status_update_date": "2026-09-10T05:28:46.748Z",
"line_items": [
{
"id": "line-kbd",
"quantity": 1,
"status": "fulfilled",
"fulfillment_id": "FMTV378RCSYXBOM",
"partner_fulfillment_reference": "YOUR_FULFILLMENT_REF",
"shipment_ids": ["MTV3790N2PDWFJ"]
},
{
"id": "line-mon",
"quantity": 1,
"status": "fulfilled",
"fulfillment_id": "FMTV378RCSYXBOM",
"partner_fulfillment_reference": "YOUR_FULFILLMENT_REF",
"shipment_ids": ["MTV3790N2PDWFJ"]
}
]
}
]
}
The order moves to fulfilled once all its lines reach a terminal
state with at least one fulfilled. It moves on to closed when
the resulting shipment(s) are delivered.
To review the draft, read the shipment by id from shipment_ids
(GET /shipments/MTV3790N2PDWFJ) rather than listing shipments by
order: GET /shipments?order_id=… and ?partner_order_reference=…
can lag a shipment created this way by tens of seconds. A shipment
has no top-level status; the draft state is at
post_shipping_info.status. The shipment links back to the order and
fulfillment order, and its partner_shipment_reference is the fulfillment_id:
{
"shipment_id": "MTV3790N2PDWFJ",
"order_id": "OMTV36M0ACTKSZT",
"fulfillment_order_id": "FOMTV36M0F6RRSMM",
"references": {
"partner_order_reference": "YOUR_ORDER_REF",
"partner_shipment_reference": "FMTV378RCSYXBOM"
},
"post_shipping_info": { "status": "draft" }
// ...pickup, dropoff, items; no carrier or parcels yet
}
Partial fulfillment
Fulfill a subset by sending only the relevant lines (or a smaller
quantity). The remaining lines stay in allocated and the fulfillment order stays
in processing until the rest are fulfilled or cancelled.
Pitfalls
- Lines must be pending. Any pending status can be fulfilled:
open,allocated,pick_in_progress,picked, orpack_in_progress. Already-fulfilled or cancelled lines are rejected. - Active picks and packs block fulfilling. The call is refused while the fulfillment order has an active pick or pack. Complete or cancel it first.
- Identify lines by id or product.
line_items[].idis the order line item id. Sendproduct_id,product_reforskuinstead, when that identifier names exactly one line. - Draft vs booked. With
create_draft_shipment=truethe shipment is created as a draft (post_shipping_info.status: "draft") and is not booked with the carrier until you confirm it. - Don't list shipments straight after fulfilling. The list
filters by order id or partner order reference can lag for tens of
seconds; read the shipment by id from
shipment_idsinstead.