Overview
A fulfillment order (FO) is the picking-and-shipping instruction that lives between a sales order and an actual carrier shipment. This article covers both the in-app UI workflow and the full API sequence for creating, pushing, and recording a shipment against a fulfillment order.
Prerequisites
Before a fulfillment order can be created:
- The sales order must be posted (
is_posted = true). Unposted orders are skipped by both the UI and the auto-generation system. - At least one Fulfillment Priority List must be configured (Operations → Operations Admin → Fulfillment Priority Lists) so the system knows which warehouse group to assign to the order.
- The sales order must have remaining unfulfilled quantity on at least one physical/inventory line item.
Creating a Fulfillment Order in the UI
There are two paths:
Option A — Manual creation
- Open the sales order detail page.
- Go to the Fulfillment Orders tab, click Actions and choose Create Fulfillment Order (or, from the Sales Orders list, select orders and choose Bulk Actions → Fulfill Orders).
- A dialog titled Fulfill Orders opens. Review the line items, choose quantities and warehouse assignment as needed, then confirm.
- The fulfillment order is created and appears in the Fulfillment Orders tab of the sales order.
Option B — Auto-generate
- Open the sales order detail page (or the sales orders list).
- On the Fulfillment Orders tab click Actions → Auto Generate Fulfillment Orders (on the list, use Bulk Actions → Auto Generate Fulfillment Orders).
- Luminous applies your Smart Fulfillment Settings (consolidation preference, line-item splitting threshold, always-create override, etc.) and creates one or more fulfillment orders automatically.
- A confirmation snackbar appears: "Auto generate fulfillment order completed."
Auto-generation also runs on a daily schedule for any posted sales order created in the past 2 days that does not yet have a fulfillment order.
Smart Fulfillment Settings that affect how the FO is built (Operations → Operations Admin → Smart Fulfillment Settings):
| Setting | What it controls |
|---|---|
| Consolidate orders | Try to fulfill everything from one warehouse first |
| Allow line-item splitting | Split quantities across multiple warehouses |
| Partial fulfillment threshold | Minimum % of remaining qty a warehouse must cover |
| Always create | Create an FO even when stock is insufficient |
| Default FO status | Initial status for new FOs (e.g., Pending, Awaiting Shipment) |
Pushing / Confirming a Fulfillment Order
Once a fulfillment order exists, "confirming" it means one of two things depending on your setup:
Push to fulfillment channel (send to WMS/OMS)
- In the Fulfillment Orders grid or on the FO detail page, select Push to Fulfillment Channel.
- This sends the FO to the connected fulfillment destination (e.g., TrackStar WMS).
- After a successful push, the FO records a
pushed_attimestamp and its channel sync status changes to Pushed. - If the push fails, the status is set to Error and a reconcile link is surfaced so you can bind the correct remote order ID.
Auto-push: If the Auto Push Fulfillment Orders feature is enabled for your account, the system pushes eligible FOs automatically after a configured delay (set per fulfillment channel). No manual action is needed.
Mark as Shipped (in-warehouse confirmation)
If your fulfillment happens entirely within Luminous (no external WMS push required):
- Open the fulfillment order.
- From the fulfillment order's action menu, choose Create Shipment.
- Optionally enter a tracking number and carrier code.
- The FO status is updated to Shipped and inventory is decremented.
Full API Sequence
All External V1 endpoints are prefixed with /external/api/v1. Internal admin endpoints use /v2/api/admin.
Step 1 — Confirm the sales order is posted
GET /external/api/v1/sales-orders/{salesOrderId}
Check that the returned order has is_posted: true. If not, post it through the Luminous UI before continuing.
Step 2 — Auto-generate fulfillment order(s)
POST /v2/api/admin/orders/fulfillment-orders/auto-generate-for-sales-orders
Request body:
{
"salesOrderIds": [12345],
"skipStatusCheck": true,
"fulfillmentOrderStatus": "Awaiting_Shipment"
}
| Field | Notes |
|---|---|
salesOrderIds | Array of posted sales order IDs to process |
skipStatusCheck | Defaults true; skips the posted-status guard (pass false to enforce it) |
fulfillmentOrderStatus | Optional override for initial FO status. Allowed values: pending, planned, Awaiting_Shipment, shipped. Omit to use the tenant default from Smart Fulfillment Settings. |
The response lists each sales order ID alongside the fulfillment orders created or any shortage details.
Step 3 — Retrieve the new fulfillment order(s)
GET /external/api/v1/fulfillment-orders?filter[sales_order_id][eq]=12345
Or using the internal list endpoint with the salesOrderId filter:
GET /v2/api/admin/orders/fulfillment-orders?salesOrderId=12345
The response includes each FO's id, order_status, warehouse_group_id, ship_by_date, and channel sync status.
Step 4 — Push the fulfillment order to the fulfillment channel
POST /external/api/v1/fulfillment-orders/{fulfillmentOrderId}/push
Optional body:
{ "debug": true }
Set debug: true to receive outbound OMS request/response details in the response — useful for diagnosing push failures.
Success response (200):
{
"data": {
"success": true,
"message": "Fulfillment order pushed successfully."
}
}
Failure response (422) includes a links.reconcile URL you can call to bind a remote OMS order ID and recover from duplicate-push errors.
Step 5 — Record a carrier shipment
Once the warehouse has shipped, record the carrier shipment. Use the FO-scoped endpoint to automatically link the shipment to the fulfillment order:
POST /external/api/v1/fulfillment-orders/{fulfillmentOrderId}/shipments
Minimum request body:
{
"ship_date": "2026-07-31",
"tracking_number": "1Z999AA1234567890",
"carrier_code": "ups",
"ship_to": {
"name": "Jane Smith",
"street1": "123 Main St",
"city": "Springfield",
"state": "IL",
"postalCode": "62701",
"country": "US",
"residential": true
},
"weight": { "value": 16, "units": "ounces" },
"dimensions": { "units": "inches", "length": 12, "width": 8, "height": 6 },
"items": [
{
"product_id": 101,
"order_item_id": 5001,
"quantity": 2,
"unit_price": 29.99
}
]
}
| Field | Requirement |
|---|---|
ship_date | Required, YYYY-MM-DD |
tracking_number, carrier_code | Required strings |
items[].product_id | Required — Luminous product ID |
items[].order_item_id | Required — sales order line item ID |
items[].quantity | Required integer ≥ 1 |
items[].unit_price | Required numeric ≥ 0 |
warehouse_id | Optional |
This endpoint automatically creates both the carrier shipment record and the pivot link between the shipment and the fulfillment order. If a shipment with the same tracking number and carrier already exists for the sales order, it is returned as-is and linked to the FO rather than creating a duplicate.
Response: 201 Created with the full shipment resource, including warehouse_group_id from the linked FO.
Alternate: Create a shipment without going through a fulfillment order
If you need to record a carrier shipment directly against a sales order (without first creating a FO), use:
POST /external/api/v1/sales-orders/{salesOrderId}/shipments
You may optionally pass fulfillment_order_id in the body to associate the shipment with an existing FO on that sales order. The FO must belong to the same sales order, otherwise the request returns 422.
Common Issues
| Symptom | Likely cause |
|---|---|
| Auto-generate produces no FOs | Sales order is not posted, or there is no Fulfillment Priority List configured |
| All items land in one FO despite different ship dates | Channel is not configured to split by estimated_ship_date, or the CHANNEL_TYPES feature is not enabled |
| Push fails with Error status | Carrier/service code mapping is missing, or the remote OMS rejected the order. Use the reconcile link from the 422 response to recover. |
| FO created despite stock shortage | The Always Create setting is enabled in Smart Fulfillment Settings |