Build fulfillment solutions
Order management apps can automate the fulfillment process in Shopify on behalf of merchants.
This guide describes how to use the GraphQL Admin API to query orders and inventory levels, and manage orders using fulfillment order actions.
Anchor to RequirementsRequirements
- Your app can make authenticated requests to the GraphQL Admin API.
- Your app has the
merchant_managed_fulfillment_orders
andthird_party_fulfillment_orders
access scopes. Learn how to configure your access scopes using Shopify CLI. - Your store has existing orders that are unfulfilled. If you need to make changes to an unfulfilled item, then you can edit an order.
- You're familiar with the API objects that pertain to fulfillment orders.
- You've met Shopify's protected customer data requirements.
Anchor to Step 1: Retrieve an orderStep 1: Retrieve an order
You can use the GraphQL Admin API's order
query to retrieve an order and its associated fulfillment orders. To retrieve fulfillment orders, provide the ID of the order in the request.
The response returns information about the associated fulfillment orders, including the fulfillment order ID, fulfillment order line items, supported actions, and assigned locations. Make note of the inventory item ID, as you'll use it to query inventory levels in the next step.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL query
JSON response
Anchor to Step 2: Retrieve inventory levelsStep 2: Retrieve inventory levels
You can use the GraphQL Admin API's inventoryItem
query to retrieve the inventory levels for items and the locations where the items are stocked.
To retrieve inventory levels, provide the ID of the inventory item in your request:
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL query
JSON response
Anchor to Step 3: Query supported fulfillment order actionsStep 3: Query supported fulfillment order actions
Each fulfillment order object includes a list of supported fulfillment order actions to determine which actions the app can take. This information is available in the JSON response received in the first step in this guide.
You can use the order
query to independently request information about fulfillment order actions. Provide the order ID to retrieve supported actions:
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL query
JSON response
Anchor to Step 4: Determine which actions to takeStep 4: Determine which actions to take
If a fulfillment order is open, then apps can inspect the list of supported actions and decide what action to take.
The following table describes the list of supported fulfillment order actions. Each action is used at a different stage in the fulfillment process.
Fulfillment order action | Description |
---|---|
MOVE | Moves a fulfillment order between merchant-managed locations. |
CREATE_FULFILLMENT | Creates a fulfillment for an order that a merchant or third-party fulfillment service can manage. |
REQUEST_FULFILLMENT | Sends a request to a third-party fulfillment service to fulfill an order. |
CANCEL_FULFILLMENT_ORDER | Immediately cancels a fulfillment that's being managed by a third-party fulfillment service. |
REQUEST_CANCELLATION | Sends a request to a third-party fulfillment service to cancel a fulfillment order. |
EXTERNAL | Indicates fulfillment orders that are assigned to an external fulfillment service. |
Apps should filter out closed fulfillment orders. Closed fulfillment orders have no supported actions, and can't be changed.
Anchor to Move a fulfillment orderMove a fulfillment order
You can use the GraphQL Admin API's fulfillmentOrderMove
mutation to move a fulfillment order from one location to another.
Only fulfillment orders assigned to merchant-managed locations can be moved between locations, and moving a fulfillment order has no impact on the shipping rate that the customer has already paid.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Create a fulfillmentCreate a fulfillment
You can use the GraphQL Admin API's fulfillmentCreateV2
mutation to create a fulfillment.
In the request, provide the line items, destination, and order information you retrieved in the first step of this guide.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
As of API version 2024-10, you can only create fulfillments for orders that are assigned to a merchant-managed location or for orders that are assigned to a third-party fulfillment service that you own. If you use the GraphQL Admin API's fulfillmentCreateV2
for an order that's assigned to another third-party fulfillment service, then the request will fail.
Anchor to Request a fulfillmentRequest a fulfillment
If a merchant is using a third-party fulfillment service, then the service can support the REQUEST_FULFILLMENT
action.
You can use the GraphQL Admin API's fulfillmentOrderSubmitFulfillmentRequest
mutation to request a fulfillment with the assigned fulfillment service. Apps can also provide an optional message to facilitate communication with the fulfillment service.
To request a fulfillment for all the line items, you only need to pass the fulfillment order ID in the request:
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Request a partial fulfillmentRequest a partial fulfillment
You can also use the GraphQL Admin API's fulfillmentOrderSubmitFulfillmentRequest
mutation to submit only one of the line items on the fulfillmentOrder
for fulfillment.
The following example shows a request to fulfill one fulfillment order line item:
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Cancel a fulfillment orderCancel a fulfillment order
If a merchant is using a third-party fulfillment service, then the service can support the CANCEL_FULFILLMENT_ORDER
action.
You can use the GraphQL Admin API's fulfillmentOrderCancel
mutation to immediately cancel the fulfillment order.
Fulfillment orders that return the CANCEL_FULFILLMENT_ORDER
action have one of the following request statuses:
Request status | Description | Behavior |
---|---|---|
SUBMITTED | A request for fulfillment has been sent to the third-party fulfillment service, but it hasn't been acknowledged. | The fulfillment order is immediately cancelled because the fulfillment service hasn't yet accepted the fulfillment request. |
CANCELLATION_REQUESTED | A request to cancel the fulfillment order has been submitted to the third-party fulfillment service. | If an app cancels the fulfillment order and doesn't wait for the third-party fulfillment service to respond, then the fulfillment service might still complete the assigned work, and the order might still succeed. |
Anchor to ExampleExample
A merchant might submit a fulfillment request for a fulfillment order. They then receive an email from the customer, who wants to confirm the size of an item. To stop the third-party fulfillment service from accepting the fulfillment order request, the app can cancel the fulfillment order request until the customer confirms the size.
The following example shows how to cancel a fulfillment that's being managed by a third-party fulfillment service:
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
If you use the GraphQL Admin API's fulfillmentOrderCancel
mutation on a fulfillment order assigned to a legacy fulfillment service that hasn't opted into FulfillmentOrder
-based fulfillment, then the request will fail. For more information, refer to Migrate to fulfillment orders.
Anchor to Request to cancel a fulfillment orderRequest to cancel a fulfillment order
If a merchant is using a third-party fulfillment service, then the service can support the REQUEST_CANCELLATION
action.
You can use the GraphQL Admin API's fulfillmentOrderSubmitCancellationRequest
mutation to send a request to the third-party fulfillment service to cancel the fulfillment order.
The following example shows how to send a request to the third-party fulfillment service to cancel the fulfillment order. The response returns that the cancellation request is in progress.
Even after a fulfillment request is accepted for a fulfillment order, apps can also submit cancellation requests for the fulfillment order.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
If you use the GraphQL Admin API's fulfillmentOrderSubmitCancellationRequest
mutation on a fulfillment order assigned to a legacy fulfillment service that hasn't opted into FulfillmentOrder
-based fulfillment, then the request will fail. For more information, refer to Migrate to fulfillment orders.
Anchor to Fulfillment outside of ShopifyFulfillment outside of Shopify
Fulfillment orders that are assigned to an external fulfillment service return EXTERNAL
as a supported action.
When dealing with a fulfillment order that's assigned to an external fulfillment service, your app should redirect the merchant to the URL in the externalUrl
field to initiate the fulfillment process outside of Shopify.
Anchor to WebhooksWebhooks
In API version 2023-01 and higher, your app can subscribe to webhooks for event notifications related to fulfillment orders. The following examples show the JSON responses from each of the available webhooks.
To learn how to set up and consume webhooks, refer to Webhooks configuration overview.
Example webhook responses
// Occurs when a fulfillment order is created and the order routing has been completed for the order
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "open",
}
}
// Occurs when a merchant requests one or more fulfilment order line items be fulfilled by a fulfilment service
{
"original_fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "in_progress",
"request_status": "submitted"
},
"submitted_fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "in_progress",
"request_status": "submitted"
},
"unsubmitted_fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/2",
"status": "in_progress",
"request_status": "submitted"
},
"fulfillment_order_merchant_request": {
"id": "gid://shopify/FulfillmentOrderMerchantRequest/1",
"message": "Fragile"
}
}
// Occurs when a fulfillment service accepts a merchant's request to fulfill one or more fulfillment order line items
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "in_progress",
"request_status": "accepted"
},
"message": "Reminder that tomorrow is a holiday. We won't be able to ship this until Monday.",
}
// Occurs when a fulfillment service rejects a merchant's request to fulfill an order
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "open",
"request_status": "rejected"
},
"message": "We weren't able to find this product in the warehouse. Sorry!",
}
// Occurs when a fulfillment order is placed on hold
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/5862841122838",
"status": "on_hold",
"fulfillment_holds": [
{
"reason": "inventory_out_of_stock",
"reason_notes": "Sorry, we ran out of stock."
}
]
}
}
// Occurs when a fulfillment order hold is released
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "open"
}
}
// Occurs when a scheduled fulfillment order is ready to be fulfilled
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "open",
"risk_assessment": "low"
}
}
// Occurs when a fulfillment order is rescheduled
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"fulfill_at": "2023-09-11T13:54:00-04:00",
"status": "cancelled"
}
}
// Occurs when a merchant requests to cancel a fulfillment order after the request was accepted by a fulfillment service
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "in_progress",
"request_status": "cancellation_requested"
},
"fulfillment_order_merchant_request": {
"id": "gid://shopify/FulfillmentOrderMerchantRequest/1",
"message": "The customer cancelled their order."
}
}
// Occurs when a fulfillment service accepts a fulfillment cancellation request from a merchant
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "in_progress",
},
"message": "The item was not picked and packed yet. As a result, cancelling as requested.",
}
// Occurs when a fulfillment service rejects a fulfillment cancellation request from a merchant
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "in_progress",
},
"message": "This was already picked up by the courier."
}
// Occurs when a fulfillment service or merchant cancels a fulfillment order
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "cancelled"
},
"replacement_fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/2",
"status": "open"
}
}
// Occurs when a fulfillment service intends to close an assigned fulfillment order that was previously accepted for fulfillment. After this action, the fulfillment order transitions to an incomplete status. To continue the fulfillment process, the merchant or app needs to determine the next course of action.
{
"fulfillment_order": {
"id": "gid://shopify/FulfillmentOrder/1",
"status": "incomplete"
},
"message": "Apologies, but it appears we are out of stock.",
}
Anchor to Next stepsNext steps
- Learn about the recommended workflow for using Shopify APIs to track orders placed through third-party marketplaces.