Fulfill a fulfillment order

Updated September 22, 20263 min read

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

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_items names the lines (and quantities) being fulfilled, referenced by the order line item id. Each must still be pending: open, allocated, pick_in_progress, picked, or pack_in_progress.
  • partner_fulfillment_reference is 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, or pack_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[].id is the order line item id. Send product_id, product_ref or sku instead, when that identifier names exactly one line.
  • Draft vs booked. With create_draft_shipment=true the 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_ids instead.