Manage fulfillments as a fulfillment service app

This guide describes how fulfillment service apps can use the Admin API to manage fulfillments in Shopify. If your app manages a FulfillmentService location (such as a third-party warehouse that prepares and ships orders on behalf of the store owner), then follow this guide. If your app doesn't manage a FulfillmentService location, but it assigns orders to be fulfilled by the merchant or by third-party locations, then you can follow our guide on managing fulfillments as an order management app.

Overview

Fulfillment Services represent third-party warehousing, print on demand, or fulfillment services that prepare and ship orders on behalf of the store owner. In Shopify, each fulfillment service has a dedicated location. When you create a fulfillment service, Shopify automatically creates a new location for it. Fulfillment services are represented in the GraphQL Admin API by the FulfillmentService object.

Fulfillment Services know what to fulfill (and when) by listening for a FulfillmentOrderMerchantRequest that represents a specific request sent from the merchant to a fulfillment service.

For example, a merchant submits a request to fulfill a given fulfillment order to a fulfillment service. The request data, including any notes that the merchant provided, is made API accessible through FulfillmentOrderMerchantRequest, which is available as a part of the FulfillmentOrder.

FulfillmentService app capabilities

Apps that are registered as fulfillment services can use fulfillment orders to do the following:

  • Receive fulfillment requests and cancellation requests on their registered callback URL (callback_url/fulfillment_order_notification) rather than relying on webhooks. This is a requirement to receive requests from Shopify. To learn more about how this works, see Receiving FULFILLMENT_REQUEST and CANCELLATION_REQUEST notifications.
  • Explicitly accept or reject a fulfillment request to indicate to merchants whether the app intends to perform fulfillment.
  • Accept or reject fulfillment cancellation requests sent by merchants.
  • Exchange fulfillment request notes with merchants when accepting, rejecting, or creating fulfillments to facilitate communication.
  • Create multiple fulfillments for a given fulfillment order to represent multiple packages.
  • Perform fulfillment only for work assigned to them
  • Create a fulfillment at any time once the app has accepted a fulfillment request, marking it as fulfilled.
  • Close a fulfillment order after performing only some of the work.

Getting Started

Before receiving fulfillment requests, you'll first need to have some unfulfilled orders on your test store. If you need to learn how to create test orders, then refer to our tutorial, Manage test orders with the REST Admin API.

Apps that fall under this category also need to request the following permissions using OAuth:

  • read and write permissions for write_assigned_fulfillment_orders to manage fulfillment orders assigned to their location

Registration

The first step is to create a Fulfillment Service in Shopify with a callback URL that will listen for fulfillment requests.

Instructions for creating a new Fulfillment Service can be found in our reference documentation for GraphQL and REST.

A fulfillment service needs to opt into fulfillment orders by letting Shopify know that they’re ready to perform FulfillmentOrder-based fulfillment rather than order-based fulfillment. This is done with a single request, detailed in our migration guide.

Receiving FULFILLMENT_REQUEST and CANCELLATION_REQUEST notifications

Apps must configure an endpoint on a callback URL where Shopify will send the notifications for fulfillment requests. This endpoint should be structured in the following format: <callback_url>/fulfillment_order_notification.

The payloads that it will receive include a field titled kind, which can be one of either FULFILLMENT_REQUEST or CANCELLATION_REQUEST. When a merchant requests a fulfillment from their Shopify admin, Shopify sends the fulfillment service a notification with kind set to FULFILLMENT_REQUEST. In this case, the body of the request sent to the callback URL contains {"kind":"FULFILLMENT_REQUEST"}. If the merchant submitted a cancellation request, then the body would include {"kind":"CANCELLATION_REQUEST"} instead.

Below, you can find example payloads for each type of request:

Acting on FULFILLMENT_REQUEST notifications

A fulfillment order notification of FULFILLMENT_REQUEST indicates that there’s a new fulfillment order assigned to the service, and it’s ready to be acted on (since the merchant has requested a fulfillment). The fulfillment service is now expected to query the assignedFulfillmentOrders connection that’s exposed under the shop object, optionally passing in the argument assignmentStatus set to FULFILLMENT_REQUESTED. The fulfillment service can then specify the fields required to determine whether it wants to accept or reject a given fulfillment request

In the following example, the query requests the fulfillment order destination, line item and line item SKUs, and the merchant requests which include whatever note the merchant supplied when they submitted the request.

The fulfillment service can now review each fulfillment order requested above, and determine whether it can be fulfilled. To accept a given fulfillment order, the fulfillment service must send an accept request by using the fulfillmentOrderAcceptFulfillmentRequest mutation. It can also send an optional message:

After the fulfillment service sends an accept request, the fulfillment order card in the Shopify admin indicates to the merchant that the request was accepted.

Shows a fulfillment card indicating that the request accepted

If the fulfillment service determines that it can’t fulfill the order, then it rejects the fulfillment request by using the fulfillmentOrderRejectFulfillmentRequest mutation:

In this case, the fulfillment order card in the Shopify admin indicates to the merchant that the request was rejected.

Shows a fulfillment card indicating that the request was rejected

Creating fulfillments

After accepting a fulfillment request, the fulfillment service can begin creating fulfillments. Note that fulfillments can’t be created for a fulfillment order before the fulfillment service accepts the fulfillment request. The fulfillment service can create multiple fulfillments for a given fulfillment order if required, representing multiple packages to be shipped.

When an app accepts a fulfillment request, the fulfillment order status transitions to IN_PROGRESS. After all line items on the fulfillment order are entirely fulfilled, the fulfillment order status transitions to a CLOSED state. If no individual lineItemsByFulfillmentOrder.fulfillmentOrderLineItems are provided, then the app creates a fulfillment for all remaining line items.

Receiving CANCEL_REQUEST notifications

Cancellation requests can also be sent to the notification endpoint URL of <callback_url>/fulfillment_order_notification. The payload of the request includes a kind, with the value CANCELLATION_REQUEST. A merchant can request cancellation through the Shopify admin by using the menu displayed below.

Image of the Request cancellation button

This renders a modal to submit a cancellation request, which lets the merchant add specific notes about this cancellation request for the fulfillment service.

After the modal is submitted, the fulfillment order card indicates that this work is now pending cancellation.

Image of the fulfillment pending cancellation

Acting on CANCEL_REQUEST notifications issued by the merchant

Receiving a fulfillment order notification with a type of CANCELLATION_REQUEST indicates that a merchant has requested for a fulfillment order to be cancelled. Similar to acting on a fulfillment request, a fulfillment service should now query assignedFulfillmentOrders and pass in the argument assignmentStatus, but set it to CANCELLATION_REQUESTED instead.

A fulfillment service can’t create fulfillments for the fulfillment orders that are returned in this list until it accepts or rejects the cancellation requests. The fulfillment service can now review each fulfillment order, and determine whether they can be cancelled. If it can, then the fulfillment service can submit a request by using the fulfillmentOrderAcceptCancellationRequest mutation to accept the cancellation of the fulfillment order along with an optional message. This results in a fulfillment order where requestStatus is CANCELLATION_ACCEPTED.

After the fulfillment service accepts a cancellation request, the fulfillment order card in the Shopify admin indicates to the merchant that the cancellation request was accepted.

Image of the accepted fulfillment cancellation request

If the fulfillment service determines that it can’t accept the cancellation of the fulfillment order, then it rejects the cancellation request by using the fulfillmentOrderRejectCancellationRequest mutation. This results in a fulfillment order where requestStatus is CANCELLATION_REJECTED. The fulfillment service can continue to create fulfillments after rejecting a cancellation.

In this case, the fulfillment order card in the Shopify admin indicates to the merchant that the cancellation request was rejected.

Image of the rejected fulfillment cancellation request

Merchants forcefully cancelling fulfillment orders

Merchants can cancel a fulfillment order before the fulfillment service responds to the cancellation request. This option is provided immediately after requesting cancellation. A warning message is also displayed to the merchant, indicating that forcibly cancelling a fulfillment order doesn’t guarantee that the fulfillment service will not ship the items. Once the fulfillment service responds by either rejecting or accepting the cancellation request, the option is no longer provided to the merchant. The fulfillment service can’t create fulfillments against a fulfillment order that was cancelled by the merchant.

Fulfillment services closing fulfillment orders

In some cases, a fulfillment service realizes that it can’t fulfill the requested items only after it’s already accepted a fulfillment order request. The fulfillment service can then make a call to close the fulfillment order, indicating to the merchant that they will not be performing fulfillment. This results in a fulfillment order where the status is INCOMPLETE and the requestStatus is CLOSED.

After a fulfillment service cancels a fulfillment, the fulfillment order card in the Shopify admin notifies the merchant that the fulfillment request has been canceled.

Image of a cancelled fulfillment request

Cancelling fulfillments

Fulfillments can be canceled through the API by using the fulfillmentCancel mutation. However, any fulfillment orders that the fulfillment was created against will be affected:

  • If the underlying fulfillment order was entirely fulfilled, then it will be automatically CLOSED.
  • Upon cancellation of an associated fulfillment, a new fulfillment order is created consisting of the line items from the canceled fulfillment. This new fulfillment order is assigned to the same location as the original fulfillment order if the items are still stocked there.
  • If all items from the cancelled fulfillment cannot be sourced from the same location, the new fulfillment order is assigned to a location where the items are stocked, considering the shop’s fulfillment priority settings. This may result in multiple newly opened fulfillment orders for different locations.
  • If the fulfillment order was partially fulfilled, then the fulfillmentOrderLineItem remainingQuantity is adjusted back based on the canceled fulfillment’s line items.


Managing your inventory

To learn more about managing inventory through the API, see the Updating inventory guide.

API references