Manage fulfillments with Fulfillment and FulfillmentOrder resources
This guide describes how fulfillment apps can use the GraphQL Admin API to perform FulfillmentOrder-based fulfillment. Using the FulfillmentOrder resource instead of using the Fulfillment and Order resources separately gives you more control over the ways that you can manage fulfillments. It also provides the following benefits:
- You can fetch the assigned location of a given group of unfulfilled line items to determine where fulfillment should occur.
- You no longer need to match SKUs or filter out the items on an order that don’t apply to you before you can determine which items you need to fulfill.
- Merchants and apps can add notes to requests to improve communication throughout the fulfillment process.
- The process of making fulfillment and cancellation requests is formalized.
The following walkthroughs show how two different types of apps can use the GraphQL Admin API to manage fulfillments in Shopify: fulfillment service apps and order management apps.
Related concepts and resources
Before you get started with fulfillment orders, it’s a good idea to make sure that you’re familiar with the following concepts and resources.
The fulfillment lifecycle
When an order is placed in Shopify, the line items are divided into groups of line items based on their location. Each group is referred to as a fulfillment order. These fulfillment orders are then assigned to a location based on the fulfillment priority. A location in Shopify can refer to either a merchant-managed location (a location created in the Shopify admin) or a third-party fulfillment location (a location that’s created when a fulfillment service is registered on that shop).
These fulfillment orders can now be acted on by the merchant, allowing them to request or cancel fulfillment. After a merchant has requested fulfillment, apps can either accept or reject these fulfillment orders, and then create fulfillments and provide tracking information for them.
Fulfillment order
Represents a group of line items to be fulfilled from the same location for the same order.
For example, a merchant receives an order for 2 hats and 2 shirts. The hats are assigned to location A, and the shirts are to be fulfilled by a fulfillment service. In this case the order includes two fulfillment orders:
- one represents the hats to be fulfilled from location A
- one represents the shirts to be fulfilled by the fulfillment service
Fulfillment orders are represented in the GraphQL Admin API by the FulfillmentOrder object.
Fulfillment
Represents a shipment of one or more items in an order. It includes the line item that the fulfillment applies to, its tracking information, and the location where fulfillment occurred.
Fulfillments are represented in the GraphQL Admin API by the Fulfillment object.
Fulfillment service
Represents a third-party warehousing, print on demand, or fulfillment service that prepares and ships orders on behalf of the store owner. In Shopify, each fulfillment service is associated with its own location. When you create a fulfillment service, a new location is automatically created and associated with it.
Fulfillment services are represented in the GraphQL Admin API by the FulfillmentService object.
FulfillmentOrderMerchantRequest
A GraphQL object that represents a specific request sent from the merchant to a fulfillment service.
For example, a merchant submits a request for fulfillment of a given fulfillment order to a fulfillment service. The request data, including any notes that the merchant provided, is made available in the API through FulfillmentOrderMerchantRequest
, which is a node that’s associated with 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 notifications and Receiving CANCEL_REQUEST notifications. - Clearly 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.
Fulfillment service app walkthrough
This section focuses on a detailed query to show a few different ways that a fulfillment service can interact with the GraphQL Admin API.
Permissions for fulfillment service apps
Apps acting as fulfillment services need to request the write_assigned_fulfillment_orders
permission using OAuth. For shops that have already installed your app, follow the migration guide for instructions on how to add these permissions without requiring the merchant to reinstall your app.
Registration
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 has the following consequences:
- Shopify won't create pending fulfillments for the fulfillment service when fulfillment is requested.
- Shopify will create successful fulfillments instead of pending fulfillments for the fulfillment service when a fulfilled order is imported.
The communication pattern between Shopify and the app changes, no longer relying on fulfillment create webhooks but rather on explicit POSTs to the callback URL (services won't be able to receive fulfillment and cancellation requests unless they have a callback URL registered). This can be done by using the fulfillmentServiceUpdate mutation.
mutation {
fulfillmentServiceUpdate(
id: "gid://shopify/FulfillmentService/5",
fulfillmentOrdersOptIn: true,
callbackUrl: "https://www.myapp.com/callback_url",
) {
fulfillmentService {
fulfillmentOrdersOptIn
}
}
Before opting into FulfillmentOrder-based fulfillment, your app must meet the following requirements:
- All assigned fulfillments must be completed (none in
PENDING
orOPEN
states).
You can also opt out FulfillmentOrder-based fulfillment after you’ve opted in. But before you can do so, your app must meet the following requirements:
- All fulfillment requests must be rejected
- All cancellation requests must be accepted
- All in-progress fulfillment orders that were previously accepted must either have their fulfillment orders closed or their fulfillments created
If the assignedFulfillmentOrders
query doesn’t return any results, then you should be able to opt out of FulfillmentOrder-based fulfillment.
Receiving FULFILLMENT_REQUEST notifications
To receive notifications for fulfillment requests, an endpoint must be configured on the callback URL where the requests will be sent. 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.
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 that it requires to determine whether it wants to accept or reject a given fulfillment request.
In the following example, the query requests the fulfillment order line item and line item SKUs, along with the merchant requests, which include whatever note the merchant supplied when they submitted the request.
{
shop {
assignedFulfillmentOrders(first: 10, assignmentStatus: FULFILLMENT_REQUESTED) {
edges {
cursor
node {
id
lineItems(first: 10) {
edges {
cursor
node {
id
totalQuantity
lineItem {
sku
}
}
}
}
merchantRequests(first: 10, kind: FULFILLMENT_REQUEST) {
edges {
cursor
node {
message
}
}
}
}
}
}
}
}
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:
mutation {
fulfillmentOrderAcceptFulfillmentRequest(
id: "gid://shopify/FulfillmentOrder/5",
message: "Reminder that tomorrow is a holiday, we won't be able to ship this until Monday"
){
fulfillmentOrder {
status
requestStatus
}
}
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.
If the fulfillment service determines that it can’t fulfill the order, then it rejects the fulfillment request by using the fulfillmentOrderRejectFulfillmentRequest mutation:
mutation {
fulfillmentOrderRejectFulfillmentRequest(
id: "gid://shopify/FulfillmentOrder/5",
message: "We are out of inventory for these items"
){
fulfillmentOrder {
status
requestStatus
}
}
In this case, the fulfillment order card in the Shopify admin indicates to the merchant 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.
mutation {
fulfillmentCreateV2(fulfillment: {
notifyCustomer: true
trackingInfo: {
number: "123456789",
company: "USPS",
url: "http://www.google.com"
}
lineItemsByFulfillmentOrder: {
fulfillmentOrderId: "gid://shopify/FulfillmentOrder/5",
fulfillmentOrderLineItems: [
{
id: "gid://shopify/FulfillmentOrderLineItem/8",
quantity: 3,
}
]
}
}) {
fulfillment {
trackingInfo {
url
number
company
}
}
}
}
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.
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.
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.
{
shop {
assignedFulfillmentOrders (first: 10, assignmentStatus: CANCELLATION_REQUESTED) {
edges {
cursor
node {
id
lineItems(first: 10) {
edges {
cursor
node {
totalQuantity
lineItem {
sku
}
}
}
merchantRequests(first: 10, kind: CANCELLATION_REQUEST) {
edges {
cursor
node {
message
}
}
}
}
}
}
}
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
.
mutation {
fulfillmentOrderAcceptCancellationRequest(
id: "gid://shopify/FulfillmentOrder/5",
message: "Item was not picked and packed yet, cancelling as requested"
){
fulfillmentOrder {
status
requestStatus
}
}
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.
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.
mutation {
fulfillmentOrderRejectCancellationRequest(
id: "gid://shopify/FulfillmentOrder/5",
message: "This was already picked up by the courier"
){
fulfillmentOrder {
status
requestStatus
}
}
In this case, the fulfillment order card in the Shopify admin indicates to the merchant that the cancellation request was rejected.
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
.
mutation {
fulfillmentOrderClose(
id: "gid://shopify/FulfillmentOrder/5",
message: "Apologies but it appears we are out of stock."
){
fulfillmentOrder {
status
requestStatus
}
}
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.
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 have been automatically
CLOSED
. Upon cancellation of an associated fulfillment, a new fulfillment order is created consisting of the line items from the canceled fulfillment. The new fulfillment order is assigned to the same location as the original fulfillment order if the items are still stocked there. Otherwise, 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 if all items from the cancelled fulfillment cannot be sourced from the same location. - If the fulfillment order was partially fulfilled, then the
fulfillmentOrderLineItem
remainingQuantity
is adjusted back based on the canceled fulfillment’s line items.
mutation {
fulfillmentCancel(id: "gid://shopify/Fulfillment/2"){
fulfillment {
status
}
}
}
Managing Your Inventory
To learn more about managing inventory through the API, see the Updating inventory guide.
Order management app walkthrough
This section focuses on a detailed query to show a few different ways that an order management app can interact with the GraphQL Admin API.
Permissions for order management apps
Apps that fall under this category need to request either (or both) of the following permissions using OAuth.
- read or write permissions for
merchant_managed_fulfillment_orders
to manage fulfillment orders assigned to merchant-managed locations - read or write permissions for
third_party_fulfillment_orders
to manage third-party fulfillment orders on behalf of the merchant
For shops that have already installed your app, follow the migration guide for instructions on how to add these permissions without requiring the merchant to reinstall your app.
Fetching the assigned location ID for a fulfillment order
Apps can use the API to determine which fulfillment location Shopify has assigned to an item. After requesting all fulfillment orders for a given order, apps can identify the origin location of the fulfillment order.
{
order(id: "gid://shopify/Order/1205103689784") {
fulfillmentOrders(first: 10) {
edges {
node {
id
status
assignedLocation {
name
location {
id
}
}
lineItems(first: 10) {
edges {
node {
id
totalQuantity
remainingQuantity
lineItem {
sku
variant {
id
displayName
}
}
}
}
}
}
}
}
}
}
In the above query, the assignedLocation
type is a copy of the location record at the time the merchant requested fulfillment of the fulfillment order. This means you must use assignedLocation.location.id
to determine the ID of the backing location in Shopify.
Managing orders by using fulfillment order actions
The app needs to request some details regarding the status of the fulfillmentOrder object and the supported fulfillment order actions to determine which actions it can take.
{
order(id: "gid://shopify/Order/1212222734358") {
fulfillmentOrders(first: 10) {
edges {
node {
id
status
supportedActions {
action
externalUrl
}
destination {
address1
address2
city
company
countryCode
province
zip
firstName
lastName
email
phone
}
lineItems(first: 10) {
edges {
node {
id
remainingQuantity
lineItem {
sku
}
}
}
}
}
}
}
}
}
The client should then filter out CLOSED
fulfillment orders and inspect the list of supported actions to see what is available to them. The list of supported fulfillment order actions includes:
Each action is used at a different stage in the fulfillment process.
REQUEST_FULFILLMENT
To perform this action, an app requires write on the third_party_fulfillment_orders
permission. For fulfillment orders that return REQUEST_FULFILLMENT
as a supported action, it is recommended to call the fulfillmentOrderSubmitFulfillmentRequest mutation. This mutation submits a request to the assigned fulfillment service. Clients can also provide an optional message to facilitate communication with the fulfillment service.
In the following example, it’s assumed that the fulfillmentOrder
has two line items, each with a remaining quantity of 2. The request submits the entire fulfillmentOrder
to the third party (including all line items):
mutation {
fulfillmentOrderSubmitFulfillmentRequest(
id: "gid://shopify/FulfillmentOrder/1",
message: "Please gift wrap.") {
originalFulfillmentOrder {
status
requestStatus
}
submittedFulfillmentOrder {
status
requestStatus
}
unsubmittedFulfillmentOrder {
status
requestStatus
}
}
}
The submitted fulfillment order is always returned in the submittedFulfillmentOrder
field. In this case, the requestStatus
is SUBMITTED
, and the status is OPEN
.
Based on the same example above, if the app wanted to submit only one of the line items on the fulfillmentOrder
for fulfillment, then the request might look like this:
mutation {
fulfillmentOrderSubmitFulfillmentRequest(
id: "gid://shopify/FulfillmentOrder/1",
fulfillmentOrderLineItems: [{id: "gid://shopify/FulfillmentOrderLineItem/1", quantity: 2}],
message: "Please gift wrap.") {
originalFulfillmentOrder {
status
requestStatus
}
submittedFulfillmentOrder {
status
requestStatus
}
unsubmittedFulfillmentOrder {
status
requestStatus
}
}
}
Note how the above submits an ID of only 1 for the FulfillmentOrderLineItem
. Given that this is a partial request, Shopify closes the original fulfillmentOrder
for which a fulfillment request was submitted, and opens two new fulfillment orders:
originalFulfillmentOrder
- This is the originalfulfillmentOrder
, which contained both line items. The status isCLOSED
, and therequestStatus
isUNSUBMITTED
.submittedFulfillmentOrder
- This is a newfulfillmentOrder
, which contains aFulfillmentOrderLineItem
ID 1 with a quantity of 2 that is submitted to the fulfillment service. The status isOPEN
, and therequestStatus
isSUBMITTED
.unsubmittedFulfillmentOrder
- This is a newfulfillmentOrder
, which contains the remaining line item that was not submitted (in this case,FulfillmentOrderLineItem
ID 2). The status isOPEN
, and therequestStatus
isUNSUBMITTED
.
CREATE_FULFILLMENT
For creating fulfillments, the app should also request any information that it needs to determine how to fulfill a given fulfillmentOrder
. Typically this includes the destination for this fulfillmentOrder
(such as the address to ship the items to), the fulfillmentOrderLineItem
’s ID, the remainingQuantity
(which is required when submitting a request to create a fulfillment), and the order line item’s SKU.
Note that fulfillmentOrderLineItem.remainingQuantity
is the most reliable way to determine the remaining quantity to be fulfilled for a line item that’s included in a given fulfillmentOrder
. To find the fulfillable quantity for a given line item for the entire order (not for a specific fulfillmentOrder
), use lineItem.fulfillableQuantity
instead.
For fulfillment orders that return CREATE_FULFILLMENT
as a supported action, it's recommended that you use the fulfillmentCreateV2 mutation. It’s important to note that if the fulfillmentOrder
in question is assigned to a third party, then you need to have the third_party_fulfillment_orders
permission to perform this action. For fulfillmentOrders
assigned to a merchant-managed location, you need the merchant_managed_fulfillment_orders
permission.
In the following example, it’s assumed that fulfillmentOrder
ID 5 has 2 line items, each with a remaining quantity of 3. The request fulfills all the line items on the fulfillmentOrder:
mutation {
fulfillmentCreateV2(fulfillment: {
notifyCustomer: true
trackingInfo: {
number: "123456789",
company: "USPS",
url: "http://www.google.com"
}
lineItemsByFulfillmentOrder: {
fulfillmentOrderId: "gid://shopify/FulfillmentOrder/5",
fulfillmentOrderLineItems: [
{
id: "gid://shopify/FulfillmentOrderLineItem/6",
quantity: 3
},
{
id: "gid://shopify/FulfillmentOrderLineItem/7",
quantity: 3
}
]
}
}) {
fulfillment {
trackingInfo {
url
number
company
}
createdAt
id
}
}
}
If successful, this request transitions the fulfillmentOrder
to a CLOSED
status since there is no more remaining work to be done on it. If this was a partial fulfillment (for example, only fulfilling fulfillmentOrderLineItem
6), then the fulfillmentOrder
would be in an IN_PROGRESS
status.
Note that fulfillmentCreateV2
accepts an array of FulfillmentOrderLineItemsInputs
, which lets apps create a single fulfillment that bridges multiple fulfillment orders. To do so, all the fulfillment orders in question have to be on the same order, and assigned to the same location.
REQUEST_CANCELLATION
After a fulfillment request is submitted for a fulfillment order, apps can also submit cancellation requests for it. For fulfillment orders that return REQUEST_CANCELLATION
as a supported action, it is recommended to call the fulfillmentOrderSubmitCancellationRequest mutation.
{
fulfillmentOrderSubmitCancellationRequest(
id: "gid://shopify/FulfillmentOrder/1",
message: "The customer changed their mind, please cancel!"
){
fulfillmentOrder {
status
requestStatus
}
}
}
If the request is successful, then the fulfillmentOrder
is updated to have a requestStatus
of CANCELLATION_REQUESTED
. If you call FulfillmentOrderSubmitCancellationRequest
on a fulfillment order assigned to a fulfillment service that is not opted into FulfillmentOrder-based fulfillment, then the request will fail.
CANCEL_FULFILLMENT_ORDER
For fulfillment orders that return CANCEL_FULFILLMENT_ORDER
as a supported action, it is recommended to call the fulfillmentOrderCancel mutation. Fulfillment orders that return this supported action have a requestStatus
of SUBMITTED
or CANCELLATION_REQUESTED
.
If a fulfillmentOrder
has a requestStatus
of SUBMITTED
, then a request for fulfillment has been sent to the third-party fulfillment service, but it has not been acknowledged. Calling FulfillmentOrderCancel
cancels the fulfillmentOrder
immediately since the fulfillment service has not yet accepted the fulfillment request. For example, a merchant submits a fulfillment request for a fulfillmentOrder
. They then receive an email from the customer, who wants to confirm the size of an item. To stop the fulfillmentService
from accepting the fulfillment order request, the merchant chooses to cancel the fulfillment order request in the app until the customer confirms the size. The app makes a call to FulfillmentOrderCancel
:
mutation {
fulfillmentOrderCancel(
id: "gid://shopify/FulfillmentOrder/1",
){
fulfillmentOrder {
status
requestStatus
}
replacementFulfillmentOrder {
status
requestStatus
}
}
}
If a fulfillmentOrder
has a requestStatus
of CANCELLATION_REQUESTED
, then the cancellation request has been sent to the third-party fulfillment service, but they have not yet accepted or rejected the request. Calling FulfillmentOrderCancel
cancels the fulfillment order without waiting for the third-party fulfillment service to respond. For example, a merchant submits a cancellation request for a fulfillmentOrder
. The merchant chooses to cancel the fulfillment order in the app, even though the third-party fulfillment service could still complete the work. The app makes a call to FulfillmentOrderCancel
as displayed in the example above.
The call returns the following:
fulfillmentOrder
- This is the original fulfillment order, which now has aCLOSED
status.replacementFulfillmentOrder
- This is the new fulfillment order, which is assigned to the same fulfillment service. This fulfillment order will be in anOPEN
status, with arequestStatus
ofUNSUBMITTED
.
If you call FulfillmentOrderCancel
on a fulfillment order assigned to a fulfillment service that is not opted into FulfillmentOrder-based fulfillment, then the request will fail.
MOVE
You can move a fulfillment order between locations if it returns MOVE
as a supported action. To move a fulfillment order from one location to another, use the fulfillmentOrderMove mutation. Accessing this mutation requires the merchant_managed_fulfillment_orders
permission. You can retrieve a list of locations where a fulfillment order can potentially move to with FulfillmentOrder.locationsForMove. 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 buyer has already paid.
In the following example, an unfulfilled fulfillmentOrder
– with a status
of OPEN
– has been assigned to location one with two line items:
- 1x hat
- 1x pants
To move this fulfillmentOrder
to location two, you can make a call to FulfillmentOrderMove
:
mutation {
fulfillmentOrderMove(
id: "gid://shopify/FulfillmentOrder/1",
newLocationId: "gid://shopify/Location/2",
){
originalFulfillmentOrder {
status
}
movedFulfillmentOrder {
status
}
remainingFulfillmentOrder {
status
}
}
}
If both items are stocked at Location two, then the following information is returned:
originalFulfillmentOrder
- This is the originalfulfillmentOrder
that was requested to be moved. The status of thisfulfillmentOrder
is nowCLOSED
.movedFulfillmentOrder
- This is a newfulfillmentOrder
assigned to location two, consisting of both line items (hat and pants). The status of thisfulfillmentOrder
isOPEN
.remainingFulfillmentOrder
- In this case, it isNULL
since there are no remaining items at location one that need to be fulfilled.
If only one of the items is stocked at Location two (say, the hat), then the following information is returned:
originalFulfillmentOrder
- This is the originalfulfillmentOrder
that was requested to be moved. The status of thisfulfillmentOrder
is nowCLOSED
.movedFulfillmentOrder
- This is a newfulfillmentOrder
assigned to location two, consisting of only the hat. The status of thisfulfillmentOrder
isOPEN
.remainingFulfillmentOrder
- This is a newfulfillmentOrder
assigned to the original location, consisting of only the pants. The status of thisfulfillmentOrder
isOPEN
.
Fulfillment outside of Shopify
Fulfillment orders that are assigned to an external fulfillment service return EXTERNAL
as a supported action. It is recommended to redirect the merchant to the URL in the externalUrl
field to initiate the fulfillment process outside of Shopify.