Overview

When you integrate with Luminous via the External V1 API, creating a fulfillment order (FO) from a posted sales order and pushing it to your warehouse or OMS involves four main steps:

  1. Confirm the sales order is posted
  2. Trigger fulfillment order generation
  3. Poll until the fulfillment order appears
  4. Push the fulfillment order to its destination channel

All External V1 requests require an Authorization: Bearer <token> header. Your tenant's base URL is the host configured for your account; all paths below are relative to /external/api/v1.


Step 1 — Confirm the sales order is posted

Fulfillment orders can only be generated for posted sales orders.

GET /sales-orders/{salesOrderId}

In the response, verify that "is_posted": true. If it is false, the order is still in a draft or purgatory state and cannot generate a fulfillment order yet. Once posting is confirmed, proceed to the next step.


Step 2 — Trigger fulfillment order generation

Luminous creates fulfillment orders automatically through a background job. To kick this off via the API, use the refresh endpoint:

POST /sales-orders/{salesOrderId}/refresh

This dispatches an asynchronous job that recalculates order quantities, removes any unpushed fulfillment orders, and auto-generates new ones based on your warehouse priority lists and Smart Fulfillment settings.

Optional request body (JSON):

FieldTypeDefaultWhen to use
reset_skip_inventorybooleanfalseSet to true if the order previously had inventory skipped and you want new FOs to be created
delete_all_shipmentsbooleanfalseSet to true to clear existing shipments before refresh

Successful response (200):

{
  "data": {
    "success": true,
    "message": "Order refresh job dispatched. Processing runs asynchronously on the order-refresh queue.",
    "sales_order_id": 123,
    "order_number": "ORD-123"
  }
}

Note: The job runs in the background. A 200 response means the job was queued, not that fulfillment orders have already been created. Proceed to Step 3 to wait for the results.

Why a fulfillment order might not be generated:

  • No fulfillment priority list is configured for the product
  • Insufficient stock and your Smart Fulfillment setting Always Create is turned off
  • The order's skip_inventory flag is set (use reset_skip_inventory: true to clear it)

Step 3 — Poll for the fulfillment order

Because generation is asynchronous, poll the fulfillment orders list endpoint until results appear:

GET /fulfillment-orders?sales_order_id[eq]={salesOrderId}

Repeat this request every few seconds until the response data array contains at least one fulfillment order. Each fulfillment order object includes:

FieldMeaning
idFulfillment order ID (needed for Step 4)
order_statusCurrent status (e.g., Pending, Awaiting_Shipment)
warehouse_group_idWhich warehouse group was assigned
destination_oms_idID of the destination OMS/fulfillment channel
pushed_atnull until the FO is pushed
source_reference_identifierRemote OMS order ID once pushed

If the array remains empty after a reasonable wait (typically 30–60 seconds), re-check the reasons listed at the end of Step 2.


Step 4 — Push the fulfillment order to its destination

Once the fulfillment order exists, send it to the assigned warehouse or OMS:

POST /fulfillment-orders/{fulfillmentOrderId}/push

No request body is required. You may optionally send { "debug": true } to include outbound HTTP traffic details in the response (useful for troubleshooting).

Successful response (200):

{
  "data": {
    "success": true,
    "message": "Fulfillment order pushed successfully."
  }
}

After a successful push, pushed_at will be set on the fulfillment order and source_reference_identifier will contain the remote system's order ID.

If the push fails (422): The response body contains a links.reconcile URL:

{
  "data": {
    "success": false,
    "message": "...",
    "links": {
      "reconcile": "https://{your-host}/external/api/v1/fulfillment-orders/123/reconcile-source-reference"
    }
  }
}

A push failure often means the destination OMS already has an order for this FO (a duplicate). Use the reconcile endpoint to recover:

POST /fulfillment-orders/{fulfillmentOrderId}/reconcile-source-reference

Send an empty body {} to let Luminous automatically look up and bind the matching remote order ID, clearing the error state. Once reconciled, the FO is treated as successfully pushed.


Optional Step — Record a carrier shipment

When the warehouse has shipped the order and you have a tracking number, record the carrier shipment against the fulfillment order:

POST /fulfillment-orders/{fulfillmentOrderId}/shipments

Minimum request body:

{
  "ship_date": "2026-07-27",
  "tracking_number": "1Z999AA1234567890",
  "carrier_code": "ups",
  "ship_to": {
    "name": "Jane Smith",
    "street1": "123 Main St",
    "city": "Austin",
    "state": "TX",
    "postalCode": "78701",
    "country": "US",
    "residential": true
  },
  "weight": { "value": 16, "units": "ounces" },
  "dimensions": { "units": "inches", "length": 12, "width": 8, "height": 6 },
  "items": [
    {
      "product_id": 1,
      "order_item_id": 10,
      "weight": { "value": 16, "units": "ounces" },
      "quantity": 1,
      "unit_price": 29.99
    }
  ]
}

This call is idempotent: if a shipment with the same tracking number and carrier already exists for this sales order, it is returned as-is and linked to the FO rather than duplicated.


Summary: full request sequence

#Method & PathPurpose
1GET /sales-orders/{id}Confirm is_posted: true
2POST /sales-orders/{id}/refreshQueue fulfillment order generation
3GET /fulfillment-orders?sales_order_id[eq]={id}Poll until FO appears
4POST /fulfillment-orders/{foId}/pushPush FO to warehouse/OMS
4aPOST /fulfillment-orders/{foId}/reconcile-source-referenceRecover from a duplicate-push error
5 (optional)POST /fulfillment-orders/{foId}/shipmentsRecord carrier tracking once shipped

Auto-push alternative

If your fulfillment channel is configured with an Auto-Push delay (set in your channel's integration mapping), Luminous will automatically push fulfillment orders after the configured number of minutes without requiring Step 4. You can still call POST /fulfillment-orders/{foId}/push manually at any time before that delay elapses if you need to push sooner.