Skip to main content

Fulfill Sales Order

POST 

/api/sales-orders/:salesOrder/fulfill

Records a fulfillment (shipment) against a sales order, deducting inventory and, by default, submitting the fulfillment to the warehouse's shipping provider and reporting it to the originating sales channel.

Required scope: orders:write

Grant this scope to your token under Settings → Developer → Personal Access Tokens.

Authentication: Requires Bearer token.

Request body fields:

  • fulfillment_type (string, required): How the order was/will be fulfilled. One of: manual, shipstation, starshipit, shipmyorders, fba, walmart_wfs, veracore, shiphero, shipfusion, d3, trackstar, pickup, sales_channel.
  • warehouse_id (integer, optional): Warehouse to fulfill from; inventory is deducted from this warehouse. Auto-resolved when every product line can only ship from one warehouse; required when lines span multiple warehouses. A line can ship from the warehouse it is routed to or from any warehouse it has been split to (a line split across warehouses ships each portion from its own warehouse).
  • requested_shipping_method_id (integer, optional): Mapped shipping method to request from the provider.
  • requested_shipping_method (string, optional, max 255): Free-text requested shipping method.
  • fulfilled_shipping_method_id (integer, optional): The shipping method actually used (manual fulfillments).
  • manual_fulfilled_shipping_method (string, optional, max 255): Free-text actual shipping method (manual fulfillments).
  • fulfilled_at (date-time, required when fulfillment_type is manual): When the shipment left the warehouse.
  • cost (number, optional, < 100000): Shipping cost.
  • tracking_number (string, optional, max 255): Carrier tracking number.
  • fulfillment_sequence (integer, optional): Sequence number; must be unique within the sales order.
  • packing_slip_printed_at (date-time, optional): When the packing slip was printed.
  • status (string, optional): Initial fulfillment status.
  • submit_to_shipping_provider (boolean, optional, default true): Set false to record the fulfillment without notifying the shipping provider.
  • submit_to_sales_channel (boolean, optional, default true): Set false to record the fulfillment without reporting it to the sales channel.
  • fulfillment_lines (array, optional, min 1 when present): Lines and quantities to fulfill. When omitted, defaults to every unfulfilled product line in the resolved warehouse at its full remaining quantity.
    • fulfillment_lines.*.sales_order_line_id (integer, required): Sales order line to fulfill; must belong to the order and be fulfillable from the resolved warehouse (its routed warehouse, or a warehouse it has been split to).
    • fulfillment_lines.*.quantity (number, required, >= 0, < 100000): Quantity to fulfill; cannot exceed the line's remaining-to-fulfill quantity (already-shipped and in-flight quantities are subtracted).
    • fulfillment_lines.*.metadata.fba_seller_sku (string, optional): Amazon seller SKU override for FBA fulfillments.
    • fulfillment_lines.*.lot_allocation (array, optional): Per-line lot override for lot-tracked products. When omitted, lots are consumed first-expired-first-out. Entries must reconcile to the line quantity and reference active lots of the line's product and warehouse.
      • fulfillment_lines..lot_allocation..fifo_layer_id (integer, required with lot_allocation): Inventory lot/layer to consume from.
      • fulfillment_lines..lot_allocation..quantity (number, required with lot_allocation, > 0): Quantity to take from that lot.
    • fulfillment_lines.*.pick_allocations (array, optional): The bins the line's units were picked from. The quantities must sum to the line's quantity.
      • fulfillment_lines..pick_allocations..warehouse_location_id (integer, required with pick_allocations): A bin (warehouse location). It must be in the warehouse the line ships from (the request's warehouse_id, or the line's own warehouse when omitted); a bin in another warehouse returns 422 on this field with code PickBinInAnotherWarehouse.
      • fulfillment_lines..pick_allocations..quantity (number, required with pick_allocations, > 0): Units picked from that bin.
  • metadata.signature_required (boolean, optional): Require a delivery signature.
  • metadata.saturday_delivery (boolean, optional): Request Saturday delivery.
  • metadata.shipping_speed (string, optional): Provider shipping speed hint.
  • metadata.comments (string, optional): Comments passed to the provider.
  • metadata.veracore_packing_slip_comments (string, optional, max 500): Packing slip comments (Veracore fulfillments).
  • metadata.veracore_shipping_comments (string, optional, max 500): Shipping comments (Veracore fulfillments).
  • metadata.veracore_third_party_account_number (string, optional, max 100): Third-party billing account number (Veracore fulfillments).
  • metadata.veracore_third_party_type (integer, optional, one of 1, 2, 3): Third-party billing type (Veracore fulfillments).

Behavior:

  • The order must be approved (not draft). Closed orders can only be fulfilled while their fulfillment status is out_of_sync.
  • Fulfillments recorded with a Personal Access Token are treated as external/channel imports (the order was shipped outside SKU.io) rather than shipments dispatched from SKU.io.
  • Insufficient allocated inventory returns 422 with a structured shortfalls list, and the shortfall is also recorded as a note on the order.
  • If the shipping provider times out, the fulfillment is queued and processed in the background; the request still succeeds with a processing message.

Path parameters:

  • salesOrder (required): Sales order ID.

Requires permission: sales_orders.fulfill

Mixed delivery: on an order that mixes shipped items and Click & Collect (in-store pickup) items, one fulfillment may only carry lines of one delivery method — a request whose lines (or, when fulfillment_lines is omitted, the remaining lines at the warehouse) span both returns 422. Lines with quantity 0 are ignored for this check.

Serial numbers: for serial-tracked products, a serial that can't be shipped (unknown, already shipped, or not in stock) or that is listed twice returns 422 with a message naming the serial.

Locked accounting period: a fulfilled_at on or before the accounting lock date returns 422 with error code InventoryPeriodLocked under errors.fulfilled_at (its data carries date and lock_date). Nothing is created; resubmit with a date after the lock date, or move the lock date back first.

Shipping provider did not answer: when the order is submitted to a shipping provider and the provider does not answer in time, the request returns 502. SKU.io cannot tell whether the provider created the shipment, so nothing is retried automatically — check the order in the provider before fulfilling again.

Request​

Responses​

OK

Response Headers
    Content-Type