Fulfillments
Fulfillments
Sales in Lightspeed Retail (X-Series) can be marked for fulfillment at a later time, either for pickup or delivery.
This tutorial will describe the following Lightspeed Retail (X-Series) fulfillment workflows:
- Creating sales with fulfillments
- Identifying sales with fulfillments
- Retrieving fulfillment data for a sale
- Fulfilling an entire sale
- Partially picking, packing, and fulfilling
This tutorial will also include a step-by-step walk through of the following omnichannel workflows:
Please note that, at this time, partial fulfillment functionality (i.e., picking, packing, and fulfilling at the line item quantity level) is not yet supported in the X-Series UI. We will be releasing that UI update soon! The old fulfillments and picklists endpoints also remain available with plans to deprecate them as the UI changes are rolled out.
See also, the fulfillments API specification.
Fulfillments Terminology
- Picking: Taking an item off the shelf and setting it aside for a specific unfulfilled order.
- Packing: Packaging an item for shipment to the customer or for in-store pickup.
- Fulfilling: Marking an item as delivered to or picked up by the customer. Triggers inventory movements.
- Fulfillment: A versioned, uniquely identified aggregation representing all items for a given sale, outlet, and fulfillment type. An individual sale may have multiple associated fulfillments if orders are placed at multiple outlets based on inventory availability. This typically only occurs for eCommerce sales.
Lightspeed Retail (X-Series) Fulfillment Workflows - Overview
X-Series fulfillment workflows, when not using an eCommerce provider, usually proceed as follows:
- A customer places an order to be fulfilled at a later time via pickup or delivery.
- The retailer creates a sale with one or more items marked for fulfillment. The corresponding fulfillment is created automatically.
- The retailer optionally picks and/or packs one or more items, preparing them to be shipped to or picked up by the customer.
- Either the customer comes to the store and collects their item(s) or the retailer ships the item(s) to the customer.
- The retailer marks the picked up / shipped item(s) as fulfilled.
When all items are fulfilled (marked as picked up or shipped), the order is now completed.
Note that, via the UI, only fully paid orders can be fulfilled. Via the API, however, items may be fulfilled regardless of sale payment status to accommodate omnichannel flows like cash on delivery. If you are developing a custom API integration or workflow, you must implement a separate check for sale payment status if necessary.
Creating a sale with fulfillments
Create a sale with the following fields:
"status"
: one of the following:- for pickup orders:
"AWAITING_PICKUP"
- for delivery orders:
"AWAITING_DISPATCH"
"register_id"
: the id of a register at the outlet specified above. For example, a retailer might have a specific 'online' register used for online orders."fulfillment_details"
: Optional The details or notes for this fulfillment sale. This cannot be modified after the fulfillment is created. This may include information about pickup or delivery details.- For each product in
"register_sale_products"
: "product_id"
: the id of the product being sold in this line item."fulfillment_type"
: one of the following:- for items to be picked:
"PICKUP"
- for items to be delivered:
"DISPATCH"
- for items taken immediately with the customer: omit this field entirely
- Warning: At this time, you cannot include both
"PICKUP"
and"DISPATCH"
items in the same sale. You can, however, include items with no"fulfillment_type"
value and either"PICKUP"
or"DISPATCH"
.
POST https://<<domain_prefix>>.retail.lightspeed.app/api/register_sales
Identifying sales with fulfillments
When retrieving sales using the List Sales endpoint and when retrieving a sale by ID using the Get a single sale endpoint, sales with associated fulfillments have the pickup
or delivery
attribute in the attributes
array.
List Sales: GET https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/sales
Get a single sale: GET https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/sales/:sale_id
Alternatively, you can retrieve fulfillment data for a sale as described in Retrieving fulfillment data for a sale. If a sale has no associated fulfillment data, this flow will return 200 OK
with an empty "data"
array.
Retrieving fulfillment data for a sale
The following endpoint allows you to retrieve fulfillment data: GET /api/2.0/fulfillments
. You may retrieve all fulfillment data (paginated) or may filter by any of the following criteria:
- sale Id
- outlet Id
- fulfillment type
- fulfillment state
To retrieve all fulfillment data for a specific sale, use GET /api/2.0/fulfillments?sale_id=:saleId
. If using omnichannel workflows in which sales may have fulfillment orders at multiple outlets, you may additionally filter on outlet Id, for example: GET /api/2.0/fulfillments?sale_id=:saleId&outlet_id=:outletId
or specify more than one outlet explicitly: GET /api/2.0/fulfillments?outlet_id=:outletId1&outlet_id=:outletId2
The following example shows the response from GET https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/fulfillments?sale_id=7069fb5d-2222-457f-9f7c-1414693ca1c9
{
"data": [
{
"id": "1944881269706846208",
"outlet_id": "7d5885e3-3590-4b74-9697-8ab8b9676a26",
"sale_id": "7069fb5d-2222-457f-9f7c-1414693ca1c9",
"type": "DISPATCH",
"state": "STARTED",
"userIds": ["4ed11b09-44cb-4667-a25f-3a4804340df8"],
"note": "",
"created_at": "2025-09-02T13:44:00Z",
"updated_at": "2025-09-04T11:12:45Z",
"version": 2,
"line_items": [
{
"sale_line_item_id": "4340ca5b-3b7d-4189-bc78-5ded66d46818",
"product_id": "97cfe639-f75c-466e-a3da-4bd9e9b8a7b0",
"quantity": "4",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "4"
},
{
"sale_line_item_id": "1df8b4c0-fdd0-45a0-810d-53277fd8740c",
"product_id": "4cdb6b00-090e-4da2-a01f-b980e3ebd519",
"quantity": "3",
"picked_quantity": "3",
"packed_quantity": "2",
"fulfilled_quantity": "0"
},
{
"sale_line_item_id": "7d5885e3-3590-4b74-9697-8ab8b9676a26",
"product_id": "de3e6543-52a8-460d-8d7f-455d9df24001",
"quantity": "10",
"picked_quantity": "2",
"packed_quantity": "2",
"fulfilled_quantity": "5"
}
]
}
]
}
In the response above, you can see that:
- there is a single fulfillment associated with this sale
- there are three items that were marked for fulfillment
- the first item is entirely fulfilled because
"fulfilled_quantity"
is equal to"quantity"
. Note that"picked_quantity"
and"packed_quantity"
values never include fulfilled quantities. - the second item is entirely unfulfilled because
"fulfilled_quantity"
is equal to0
. The full"quantity"
value has been picked because"picked_quantity"
is equal to"quantity"
. Two of the three unfulfilled items have also been packed, because"packed_quantity"
is equal to 2. Note that there will never be a greater"packed_quantity"
value than the"picked_quantity"
; an item that is packed also counts as having been picked. - the third item is partially fulfilled because
"fulfilled_quantity"
is greater than0
but less than the"quantity"
value. 5 items have been fulfilled, leaving five items unfulfilled. Of the five unfulfilled items, two of them have been picked and packed.
Importantly, this endpoint returns the fulfillment id ("id"
) and version ("version"
) - you will need these values to partially pick, pack, or fulfill as described in the Partially picking, packing, and fulfilling section.
A few additional notes about this endpoint:
- This endpoint returns data regardless of whether the order is fulfilled or unfulfilled
- This endpoint returns
200 OK
with an empty"data"
array when there is no matching fulfillment data (e.g., the sale has no fulfillment data)
Fulfilling an entire sale
To fulfill everything unfulfilled that is associated with a given sale, use the Fulfill Sale endpoint. You will need to know the relevant sale id.
For example, to fulfill a sale, call POST https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/fulfillments/fulfill
with the following request body:
{
"sale_id": "075bbd4b-302a-837b-11f0-71f1832d8d94"
}
This will mark relevant items as fulfilled and return a response with the fulfillment items of the sale that were impacted with their resulting versions.
{
"data": [
{
"id": "1948112561387188224",
"version": 4
},
{
"id": "1948112561387188225",
"version": 2
},
{
"id": "1948112561387188226",
"version": 5
}
]
}
The sale status will update to "PICKED_UP_CLOSED"
. This can be confirmed by looking up the sale.
GET https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/sales/:sale_id
{
"register_id": "b1e198a9-f019-11e3-a0f5-b8ca3a64f8f4",
"user_id": "b1ed6158-f019-11e3-a0f5-b8ca3a64f8f4",
"outlet_id": "02e60bb7-8d62-11e9-f4c2-b314f6a052d1",
"status": "PICKED_UP_CLOSED",
...
"line_items": [{
"product_id": "b1d87b58-f019-11e3-a0f5-b8ca3a64f8f4",
"quantity": 1,
"price": 12,
"tax": 1.8,
"tax_id": "b1d192bc-f019-11e3-a0f5-b8ca3a64f8f4",
...
}]
}
Partially picking, packing, and fulfilling
For more complex fulfillment workflows, Lightspeed Retail (X-Series) now allows you to take fulfillment actions at the line item quantity level, including picking, packing, and fulfilling. Decimal line item quantities are also supported.
A few things to note:
- When taking partial fulfillment actions, you must always first retrieve the fulfillment id and the latest version as described in Retrieving fulfillment data for a sale. The version is updated every time any fulfillment action is taken on any item in the resource; if you do not pass the latest version with your request, the request will fail with a
409 Conflict
status code. - Picking and packing are optional steps. An item can be packed without being previously picked or fulfilled without being picked or packed.
- You cannot pick, pack, or fulfill items from multiple fulfillments in a single request. This means that you can only pick, pack, or fulfill items that share a sale id, outlet id, and fulfillment type in a single request.
This section will go through the following steps for a sale that has several line items marked for pickup, all at the same outlet:
- Retrieve fulfillment data from the sale to get the fulfillment id and the latest version.
- Pick a few items. (Endpoint)
- Pack a few items. (Endpoint)
- Fulfill a few items. (Endpoint)
- Fulfill all remaining unfulfilled items.
Step 1: Retrieve fulfillment data from the sale
In this step, we are retrieving the fulfillment data for a newly created sale. We need to identify the fulfillment id ("id"
) and version ("version"
) for use in future requests.
Request: GET https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/fulfillments?sale_id=f21b5007-ca4b-4efe-8df5-4e4a34ef38f5
Response:
{
"data": [
{
"id": "1948112561387188224",
"outlet_id": "ea140869-7b1e-4761-930d-66e979b74ec8",
"sale_id": "f21b5007-ca4b-4efe-8df5-4e4a34ef38f5",
"type": "PICKUP",
"state": "OPEN",
"userIds": ["4ed11b09-44cb-4667-a25f-3a4804340df8"],
"note": "",
"created_at": "2025-09-02T13:44:03Z",
"updated_at": "2025-09-02T13:44:03Z",
"version": 1,
"line_items": [
{
"sale_line_item_id": "dcbc9d02-6457-4ab2-80de-cc9964bbb256",
"product_id": "aee773c5-b47b-41c9-9ed2-a01be02d12ee",
"quantity": "1",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "0"
},
{
"sale_line_item_id": "912f415d-3b95-47a2-bed3-173b2e782e16",
"product_id": "3188ac68-0b03-43c7-a5a6-09591e57472c",
"quantity": "3",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "0"
},
{
"sale_line_item_id": "b8c54a32-14f6-41ac-83ba-6ddb1acaca0d",
"product_id": "a8c7ebf7-53b0-4489-8006-d25dc3758480",
"quantity": "10",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "0"
},
{
"sale_line_item_id": "d58832da-1daf-4554-ad2c-6dbf91ed7b6a",
"product_id": "068de4ca-2273-43f2-b475-7352a65cedb3",
"quantity": "2",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "0"
}
]
}
]
}
Step 2: Pick a few items In this step, we are going to pick all the quantity of the first line item and partial quantities of the second line item. (Endpoint)
Request: POST https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/fulfillments/1948112561387188224/pick
{
"version": 1,
"line_items": [
{
"sale_line_item_id": "dcbc9d02-6457-4ab2-80de-cc9964bbb256",
"quantity": "1"
},
{
"sale_line_item_id": "912f415d-3b95-47a2-bed3-173b2e782e16",
"quantity": "2"
}
]
}
Response:
{
"data": {
"id": "1948112561387188224",
"version": 2
}
}
Note that, in the response, the "version"
has incremented from 1
to 2
. If you retrieve the sale fulfillment data at this point, it will look as follows:
{
"data": [
{
"id": "1948112561387188224",
"outlet_id": "ea140869-7b1e-4761-930d-66e979b74ec8",
"sale_id": "f21b5007-ca4b-4efe-8df5-4e4a34ef38f5",
"type": "PICKUP",
"state": "STARTED",
"userIds": ["4ed11b09-44cb-4667-a25f-3a4804340df8"],
"note": "",
"created_at": "2025-09-02T13:44:03",
"updated_at": "2025-09-02T13:50:22Z",
"version": 2,
"line_items": [
{
"sale_line_item_id": "dcbc9d02-6457-4ab2-80de-cc9964bbb256",
"product_id": "aee773c5-b47b-41c9-9ed2-a01be02d12ee",
"quantity": "1",
"picked_quantity": "1",
"packed_quantity": "0",
"fulfilled_quantity": "0"
},
{
"sale_line_item_id": "912f415d-3b95-47a2-bed3-173b2e782e16",
"product_id": "3188ac68-0b03-43c7-a5a6-09591e57472c",
"quantity": "3",
"picked_quantity": "2",
"packed_quantity": "0",
"fulfilled_quantity": "0"
},
{
"sale_line_item_id": "b8c54a32-14f6-41ac-83ba-6ddb1acaca0d",
"product_id": "a8c7ebf7-53b0-4489-8006-d25dc3758480",
"quantity": 10,
"picked_quantity": 0,
"packed_quantity": 0,
"fulfilled_quantity": 0
},
{
"sale_line_item_id": "d58832da-1daf-4554-ad2c-6dbf91ed7b6a",
"product_id": "068de4ca-2273-43f2-b475-7352a65cedb3",
"quantity": "2",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "0"
}
]
}
]
}
Step 3: Pack a few items
In this step, we are going to:
- pack the full quantity of the first line item, which we previously picked
- pack the full quantity of the second line item, 2 of which we previously picked
- pack half the quantity of the third line item, which was not previously picked
We need to now pass in
"version": 2
, since the version was updated in the last step. (Endpoint)
Request: POST https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/fulfillments/1948112561387188224/pack
{
"version": 2,
"line_items": [
{
"sale_line_item_id": "dcbc9d02-6457-4ab2-80de-cc9964bbb256",
"quantity": "1"
},
{
"sale_line_item_id": "912f415d-3b95-47a2-bed3-173b2e782e16",
"quantity": "3"
},
{
"sale_line_item_id": "b8c54a32-14f6-41ac-83ba-6ddb1acaca0d",
"quantity": "5"
}
]
}
Response:
{
"data": {
"id": "1948112561387188224",
"version": 3
}
}
Note that, in the response, the "version"
has incremented from 2
to 3
. If you retrieve the sale fulfillment data at this point, it will look as follows:
{
"data": [
{
"id": "1948112561387188224",
"outlet_id": "ea140869-7b1e-4761-930d-66e979b74ec8",
"sale_id": "f21b5007-ca4b-4efe-8df5-4e4a34ef38f5",
"type": "PICKUP",
"state": "STARTED",
"userIds": ["4ed11b09-44cb-4667-a25f-3a4804340df8"],
"note": "",
"created_at": "2025-09-02T13:44:03Z",
"updated_at": "2025-09-02T14:05:11Z",
"version": 3,
"line_items": [
{
"sale_line_item_id": "dcbc9d02-6457-4ab2-80de-cc9964bbb256",
"product_id": "aee773c5-b47b-41c9-9ed2-a01be02d12ee",
"quantity": "1",
"picked_quantity": "1",
"packed_quantity": "1",
"fulfilled_quantity": "0"
},
{
"sale_line_item_id": "912f415d-3b95-47a2-bed3-173b2e782e16",
"product_id": "3188ac68-0b03-43c7-a5a6-09591e57472c",
"quantity": "3",
"picked_quantity": "3",
"packed_quantity": "3",
"fulfilled_quantity": "0"
},
{
"sale_line_item_id": "b8c54a32-14f6-41ac-83ba-6ddb1acaca0d",
"product_id": "a8c7ebf7-53b0-4489-8006-d25dc3758480",
"quantity": "10",
"picked_quantity": "5",
"packed_quantity": "5",
"fulfilled_quantity": "0"
},
{
"sale_line_item_id": "d58832da-1daf-4554-ad2c-6dbf91ed7b6a",
"product_id": "068de4ca-2273-43f2-b475-7352a65cedb3",
"quantity": "2",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "0"
}
]
}
]
}
As a reminder, you can pack an item without previously marking it as picked; packing an item automatically also marks it as picked. This is why "picked_quantity"
is now 3
for the second line item and 5
for the third line item.
Step 4: Fulfill a few items
In this step, we are going to:
- fulfill the full quantity of the first line item, which we previously packed
- fulfill a partial quantity of the second line item, all of which we previously packed
- fulfill the full quantity of the third line item, half of which we previously packed and half of which we have not touched
- fulfill half the quantity of the fourth line item, which we have not touched.
We need to now pass in "version": 3
, since the version was updated in the last step. (Endpoint)
Request: POST https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/fulfillments/1948112561387188224/fulfill
{
"version": 3,
"line_items": [
{
"sale_line_item_id": "dcbc9d02-6457-4ab2-80de-cc9964bbb256",
"quantity": "1"
},
{
"sale_line_item_id": "912f415d-3b95-47a2-bed3-173b2e782e16",
"quantity": "2"
},
{
"sale_line_item_id": "b8c54a32-14f6-41ac-83ba-6ddb1acaca0d",
"quantity": "10"
},
{
"sale_line_item_id": "d58832da-1daf-4554-ad2c-6dbf91ed7b6a",
"quantity": "1"
}
]
}
Response:
{
"data": {
"id": "1948112561387188224",
"version": 4
}
}
Note that, in the response, the "version"
has incremented from 3
to 4
. If you retrieve the sale fulfillment data at this point, it will look as follows:
{
"data": [
{
"id": "1948112561387188224",
"outlet_id": "ea140869-7b1e-4761-930d-66e979b74ec8",
"sale_id": "f21b5007-ca4b-4efe-8df5-4e4a34ef38f5",
"type": "PICKUP",
"state": "STARTED",
"userIds": ["4ed11b09-44cb-4667-a25f-3a4804340df8"],
"note": "",
"created_at": "2025-09-02T13:44:03",
"updated_at": "2025-09-02T14:08:43",
"version": 4,
"line_items": [
{
"sale_line_item_id": "dcbc9d02-6457-4ab2-80de-cc9964bbb256",
"product_id": "aee773c5-b47b-41c9-9ed2-a01be02d12ee",
"quantity": "1",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "1"
},
{
"sale_line_item_id": "912f415d-3b95-47a2-bed3-173b2e782e16",
"product_id": "3188ac68-0b03-43c7-a5a6-09591e57472c",
"quantity": "3",
"picked_quantity": "1",
"packed_quantity": "1",
"fulfilled_quantity": "2"
},
{
"sale_line_item_id": "b8c54a32-14f6-41ac-83ba-6ddb1acaca0d",
"product_id": "a8c7ebf7-53b0-4489-8006-d25dc3758480",
"quantity": "10",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "10"
},
{
"sale_line_item_id": "d58832da-1daf-4554-ad2c-6dbf91ed7b6a",
"product_id": "068de4ca-2273-43f2-b475-7352a65cedb3",
"quantity": "2",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "1"
}
]
}
]
}
As a reminder, you can fulfill an item without previously marking it as picked or packed. Fulfilling an item removes the fulfilled quantity from the "picked_quantity"
and/or "packed_quantity"
, both of which represent unfulfilled quantities. For example, see in the third line item that we previously had packed 5 of the 10 items, but now both "picked_quantity"
and "packed_quantity"
are 0. If, for example, we had only fulfilled 7 of the 10 items we would still see 0 for both "picked_quantity"
and "packed_quantity"
- the system will first fulfill packed items, then picked items, and finally untouched items. You can always calculate the unfulfilled quantity for a line item with the following formula: "quantity"
- "fulfilled_quantity"
.
Step 5: Fulfill all remaining items
In this step, we will fulfill all remaining unfulfilled items (one each in the second and fourth line items). This example will show how to do so using the partial fulfillment endpoint, but it is equally possible to use the fulfill sale endpoint as described in Fulfilling an entire sale. You may want to use the fulfill sale endpoint in situations where you do not want to have to specify the fulfillment version or specific line item quantities.
Request: POST https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/fulfillments/1948112561387188224/fulfill
{
"version": 4,
"line_items": [
{
"sale_line_item_id": "912f415d-3b95-47a2-bed3-173b2e782e16",
"quantity": "1"
},
{
"sale_line_item_id": "d58832da-1daf-4554-ad2c-6dbf91ed7b6a",
"quantity": "1"
}
]
}
Response:
{
"data": {
"id": "1948112561387188224",
"version": 5
}
}
Note that, in the response, the "version"
has incremented from 4
to 5
, which is the final version for this particular group. If you retrieve the sale fulfillment data at this point, it will look as follows:
{
"data": [
{
"id": "1948112561387188224",
"outlet_id": "ea140869-7b1e-4761-930d-66e979b74ec8",
"sale_id": "f21b5007-ca4b-4efe-8df5-4e4a34ef38f5",
"type": "PICKUP",
"state": "FULFILLED",
"userIds": ["4ed11b09-44cb-4667-a25f-3a4804340df8"],
"note": "",
"created_at": "2025-09-02T13:44:03Z",
"updated_at": "2025-09-02T14:08:43Z",
"version": 5,
"line_items": [
{
"sale_line_item_id": "dcbc9d02-6457-4ab2-80de-cc9964bbb256",
"product_id": "aee773c5-b47b-41c9-9ed2-a01be02d12ee",
"quantity": "1",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "1"
},
{
"sale_line_item_id": "912f415d-3b95-47a2-bed3-173b2e782e16",
"product_id": "3188ac68-0b03-43c7-a5a6-09591e57472c",
"quantity": "3",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "3"
},
{
"sale_line_item_id": "b8c54a32-14f6-41ac-83ba-6ddb1acaca0d",
"product_id": "a8c7ebf7-53b0-4489-8006-d25dc3758480",
"quantity": "10",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "10"
},
{
"sale_line_item_id": "d58832da-1daf-4554-ad2c-6dbf91ed7b6a",
"product_id": "068de4ca-2273-43f2-b475-7352a65cedb3",
"quantity": "2",
"picked_quantity": "0",
"packed_quantity": "0",
"fulfilled_quantity": "2"
}
]
}
]
}
The sale status in this case updates to PICKED_UP_CLOSED
. This is possible because:
- all items of this fulfillment are now fulfilled
- the sale does not have any other fulfillments
- the sale is fully paid
- the sale was not paid on account (in which case the sale status would be an on account sale status)
Omnichannel Fulfillment Workflows - Overview
Omnichannel fulfillment workflows are used when the original order is placed via an e-commerce site. This includes both e-commerce providers that integrated directly with Lightspeed Retail (X-Series) and, via custom or third-party integrations, any ERP provider.
For any omnichannel fulfillment workflow, the key things to note are:
- You should ensure you are either managing the inventory solely using Lightspeed Retail (X-Series) or Lightspeed Retail (X-Series)'s inventory levels are synchronised if you are managing the inventory externally (e.g., using an ERP)
- Your e-commerce provider/ERP needs to be able to support the concept of multiple locations for inventory, and these locations should be able to be mapped to the outlets you'd like to offer for click and collect/delivery.
The omnichannel workflows, either click and collect or delivery, usually proceed as follows:
- Customer places an order on a retailer's e-commerce site
- Customer selects either the 'pick up in store' or 'delivery' option
- Retailer receives the order, then picks and/or packs the inventory for the customer
- The customer either comes to the store to collect their order or the retailer ships the order to them
- The order is now completed
Steps 1 and 2 are performed on the e-commerce site. The following sections of this tutorial explain how you can use Lightspeed Retail (X-Series)'s API to perform steps 3 through 5 to pick, pack, and fulfill using Lightspeed Retail (X-Series). For information on how to create a fulfillment sale that Lightspeed Retail (X-Series) can process, see Creating sales with fulfillments.
Note that, at this time, Lightspeed Retail native integrations with Shopify, BigCommerce, WooCommerce, and Ecwid (E-Series) do not support syncing partially fulfilled orders either to or from the e-Commerce provider. As a result, the example workflows use the Fulfilling an entire sale steps; for custom integration or API development, you may also use partial fulfillment flows described in Partially picking, packing, and fulfilling.
API Workflow - Click and Collect
Create a sale with the following fields:
"status": "AWAITING_PICKUP"
"register_id"
: the id of a register at the outlet specified above. For example, a retailer might have a specific 'online' register that is used for online orders."fulfillment_details"
: the details or notes for this fulfillment sale. This cannot be modified after the fulfillment is created. Optional.- For each product in
"register_sale_products"
: "product_id"
: the id of the product being sold in this line item."fulfillment_type"
: the method of fulfillment for this line item. Use"PICKUP"
if this item is to be picked up later. Otherwise, omit this field if the item is to be taken immediately.
POST https://<<domain_prefix>>.retail.lightspeed.app/api/register_sales
{
"register_id": "b1e198a9-f019-11e3-a0f5-b8ca3a64f8f4",
"user_id": "b1ed6158-f019-11e3-a0f5-b8ca3a64f8f4",
"status": "AWAITING_PICKUP",
"fulfillment_details": [{
"type": "PICKUP",
"note": "here is my pickup fulfillment note"
}],
...
"register_sale_products": [{
"product_id": "b1d87b58-f019-11e3-a0f5-b8ca3a64f8f4",
"quantity": 1,
"price": 12,
"tax": 1.8,
"tax_id": "b1d192bc-f019-11e3-a0f5-b8ca3a64f8f4",
"fulfillment_type": "PICKUP",
...
}]
}
When the customer comes to the store to collect the order, the item can be marked as picked up using Lightspeed Retail (X-Series), or you can mark the sale as fulfilled (PICKED_UP
), by creating a fulfillment with the fulfillments API.
POST https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/sales/:sale_id/fulfill
{
"fulfillment_type": "PICKED_UP"
}
This will return a response with status PICKED_UP
along with the line items that are picked up.
{
"data": {
"status": "PICKED_UP",
...
"line_items": [
{
"id": "1869056896111226880",
"product_id": "b1d87b58-f019-11e3-a0f5-b8ca3a64f8f4",
"quantity": "1"
}
]
}
}
The sale will be marked as "PICKED_UP_CLOSED"
. This can be confirmed by looking up the sale.
GET https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/sales/:sale_id
{
"register_id": "b1e198a9-f019-11e3-a0f5-b8ca3a64f8f4",
"user_id": "b1ed6158-f019-11e3-a0f5-b8ca3a64f8f4",
"outlet_id": "02e60bb7-8d62-11e9-f4c2-b314f6a052d1",
"status": "PICKED_UP_CLOSED",
...
"line_items": [{
"product_id": "b1d87b58-f019-11e3-a0f5-b8ca3a64f8f4",
"quantity": 1,
"price": 12,
"tax": 1.8,
"tax_id": "b1d192bc-f019-11e3-a0f5-b8ca3a64f8f4",
...
}]
}
API Workflow - Delivery
Create a sale with the following fields:
"status": "AWAITING_DISPATCH"
"register_id"
: the id of a register at the outlet specified above. For example, the retailer might have a specific 'online' register that is used for delivery orders."fulfillment_details"
: the details or notes for this fulfillment sale. This cannot be modified after the fulfillment is created. Optional.- For each product in
"register_sale_products"
: "product_id"
: the id of the product being sold in this line item."fulfillment_type"
: the method of fulfillment for this line item. Use"DISPATCH"
if this item is to be delivered later. Otherwise, omit this field if the item is to be taken immediately.
POST https://<<domain_prefix>>.retail.lightspeed.app/api/register_sales
{
"register_id": "b1e198a9-f019-11e3-a0f5-b8ca3a64f8f4",
"user_id": "b1ed6158-f019-11e3-a0f5-b8ca3a64f8f4",
"outlet_id": "02e60bb7-8d62-11e9-f4c2-b314f6a052d1",
"status": "AWAITING_DISPATCH",
"fulfillment_details": [{
"type": "DISPATCH",
"note": "here is my delivery fulfillment note"
}],
...
"register_sale_products": [{
"product_id": "b1d87b58-f019-11e3-a0f5-b8ca3a64f8f4",
"quantity": 1,
"price": 12,
"tax": 1.8,
"tax_id": "b1d192bc-f019-11e3-a0f5-b8ca3a64f8f4",
"fulfillment_type": "DISPATCH",
...
}]
}
Once the order has been picked and sent for delivery, the item can be marked as shipped using Lightspeed Retail (X-Series), or you can mark the sale as fulfilled (SHIPPED
), by creating a fulfillment with the fulfillments API.
POST https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/sales/:sale_id/fulfill
{
"fulfillment_type": "SHIPPED"
}
This will return a response with status SHIPPED
along with the line items that are shipped.
{
"data": {
"status": "SHIPPED",
...
"line_items": [
{
"id": "1869054268111335424",
"product_id": "b1d87b58-f019-11e3-a0f5-b8ca3a64f8f4",
"quantity": "1"
}
]
}
}
The sale will be marked as "DISPATCHED_CLOSED"
. This can be confirmed by looking up the sale.
GET https://<<domain_prefix>>.retail.lightspeed.app/api/2.0/sales/:sale_id
{
"register_id": "b1e198a9-f019-11e3-a0f5-b8ca3a64f8f4",
"user_id": "b1ed6158-f019-11e3-a0f5-b8ca3a64f8f4",
"outlet_id": "02e60bb7-8d62-11e9-f4c2-b314f6a052d1",
"status": "DISPATCHED_CLOSED",
...
"line_items": [{
"product_id": "b1d87b58-f019-11e3-a0f5-b8ca3a64f8f4",
"quantity": 1,
"price": 12,
"tax": 1.8,
"tax_id": "b1d192bc-f019-11e3-a0f5-b8ca3a64f8f4",
...
}]
}
Updated 1 day ago