Skip to main content

Submit Fulfillment Order to Provider

POST 

/api/fulfillment-orders/:fulfillmentOrder/submit

Transitions request_status from unsubmitted → submitting and stamps submitted_at to the moment of hand-off (NOT when the carrier confirms — see Stage 2 for the carrier-callback flow that flips submitting → submitted/accepted).

Required scope: orders:write

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

Mutability gate. Allowed ONLY when status=open AND request_status=unsubmitted. Violations return 409.

Request body (all fields optional). Submission acts on the WHOLE FO — there are no per-line quantities (split the FO first to dispatch part of it).

  • acknowledge_open_channel_fulfillment (boolean, default false) — double-fulfillment guardrail (F4a). When an still-open sales-channel (Shopify) fulfillment order may yet ship some of this FO's units, an omitted/false submit is refused with 409 carrying requires_acknowledgement: true and a coverage preview. Resubmit with this true to dispatch natively anyway.
  • requested_integration_instance_id (integer|null) — per-FO shipping-provider override; must be a SHIPPING_PROVIDER instance.
  • requested_fulfillment_type (string|null, only manual) — force Manual dispatch (no integration instance).
  • requested_shipping_method_id (integer|null) / requested_shipping_method (string|null) — requested carrier service.
  • requested_ship_date (date|null), requested_metadata (object|null) — optional ship intent bridged onto the SalesOrderFulfillment (notes, fulfillment_sequence, signature_required, veracore_*, isInsured, instructionsForWarehouse).
  • lot_allocations (array|null) — per-line FEFO override for lot-tracked lines: [{ sales_order_line_id, lots: [{ fifo_layer_id, quantity }] }]. Re-validated at dispatch; stale picks fall back to FEFO. Omit for automatic FEFO/FIFO.
  • serials (array|null) — serials picked for serialized lines: [{ sales_order_line_id, serials: ["SN-1", ...] }]. Stored on the fulfillment order line and re-checked when the shipment is recorded: a picked serial that has since left stock at the FO's warehouse is dropped, and units without a usable serial take the oldest serials in stock. Serials reported by the provider win. A non-empty list must hold exactly one serial per unit still to ship, with no repeats, and under Require exact match only serials available at the FO's warehouse (422 on serials.N.serials). A line not on this FO returns 422 on serials.N.sales_order_line_id. Omit to let the shipment pick the serials; a re-submit without it clears an earlier pick.

The "Allow Sales Orders with unfulfillable quantity to be dispatched (partially)" setting does not gate this endpoint: submitting a single fulfillment order is a deliberate per-order dispatch, so it proceeds even when the sales order still has unfulfillable (backordered) quantity. That setting applies to automatic dispatch and to the bulk-submit endpoint only.

On an order that mixes shipped and Click & Collect items, requested_shipping_method_id may not switch the fulfillment order between shipping and pickup — change its shipping method first (409).

Each line includes requires_pallet_delivery (bool): the buyer chose pallet (freight/LTL) delivery for that line, so it should ship by freight, not parcel.

A 409 is also returned when the sales channel has already fulfilled units this fulfillment order would ship (for example, the order was marked fulfilled directly in the channel). Those lines report channel_covered: true with channel_already_fulfilled_quantity greater than 0. Re-submit with acknowledge_open_channel_fulfillment: true only if the units are genuinely still owed.

Required permission: fulfillment_orders.submit (Fulfillment Orders → Submit & sync) and fulfillment_orders.index (Fulfillment Orders → View). A token also needs its orders scope; the owner needs these role permissions.

Request​

Responses​

OK

Response Headers
    Content-Type