Build for return management
A return represents the intent of a buyer to ship one or more items from an order back to a merchant or a third-party fulfillment location. Merchants can manage their returns in Shopify, and returns apps can take actions on behalf of merchants.
This guide shows you how to manage returns using the GraphQL Admin API.
Anchor to Step 1: Query returnable fulfillmentsStep 1: Query returnable fulfillments
A returnable fulfillment is an order that has been delivered and is eligible to be returned to the merchant or third-party fulfillment service.
To retrieve the fulfillment line items that can be returned in an order, provide the ID of the order in the returnableFulfillments
query. The response returns the fulfillment line item ID, which you'll use as input to create a return in the next step.
You can retrieve the ID of an order using the orders
query.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL query
JSON response
Anchor to Step 2 (Optional): Calculate return financialsStep 2 (Optional): Calculate return financials
You can skip this step if you've already requested a return or created a return
You can use the returnCalculate
query to calculate financial data for a return with given inputs. Note that this does not create the return, it simply calculates the financial impact of a return if created with the same inputs.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Step 3: Request a returnStep 3: Request a return
You can use the returnRequest
mutation to create a return with its status set to REQUESTED
. This mutation should be used to create returns that need to be approved by the merchant.
If you create a return on an archived order, then the order is automatically unarchived.
To request a return, provide the ID of the order and the return line items as input to the mutation. The response returns the return ID and the return's status.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Approve a requestApprove a request
You can use the returnApproveRequest
mutation to approve a single requested return. This changes the return's status from REQUESTED
to OPEN
. Approving the return creates a reverse fulfillment order, and enables you to create a reverse delivery for the reverse fulfillment order.
To approve a request, provide the ID of the return to be approved. The response returns the return ID and the return's status.
Approving a return is a permanent action. After a return is approved, you can't change its status to REQUESTED
or DECLINED
.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Decline a requestDecline a request
You can use the returnDeclineRequest
mutation to decline a single requested return. This changes the return's status from REQUESTED
to DECLINED
. A declined return doesn't have reverse fulfillment orders. As a result, shipping can't be added to the declined return.
You can only decline a return if the return meets the following criteria:
- It must be in a
REQUESTED
state. - It can't have been refunded.
To decline a request, provide the ID of the return to be declined. The response returns the return ID and the return's status.
Declining a return is a permanent action. After a return is declined, you can't change its status to REQUESTED
or APPROVED
.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL query
JSON response
Anchor to Step 4 (Optional): Create a returnStep 4 (Optional): Create a return
You can skip this step if you've already requested a return.
If your workflow involves approving or declining requested returns outside of the Shopify platform, then you should create a return using the returnCreate
mutation.
You can create a return from an existing order that has at least one fulfilled line item that hasn't yet been refunded.
If you create a return on an archived order, then the order is automatically unarchived.
The returnCreate
mutation does the following:
- It creates a return in the
OPEN
state, and assumes that the return request from the customer has already been approved. You should only create a return if the merchant's intent is to approve a customer's return request. - It creates a reverse fulfillment order, and enables you to create a reverse delivery for the reverse fulfillment order.
- It creates a sales agreement with a
RETURN
reason, which links to all sales created for the return/exchange - It creates sales records that reverse the sales records for the items being returned
- It creates sales records for any exchange line items
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
The created return is marked as Return in progress in the order details view in the Shopify admin:

When a return is created with exchange items, those exchange items will create fulfillment orders with an ON_HOLD
status and AWAITING_RETURN_ITEMS
as the fulfillment hold reason. For more information on managing fulfillments see manage fulfillments.
Anchor to Step 5: Retrieve a returnStep 5: Retrieve a return
After you've created a return, you can use the return
query to retrieve the return by its ID. The response returns the order ID associated with the return and the return's status.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Step 6 (Optional): Remove return line items from the returnStep 6 (Optional): Remove return line items from the return
If a customer changes their mind about returning an item, you can remove that item from the return. Removing a return line item will revert that order line item back to being fulfilled and may change the order balance. If you remove the only return line item in the return, the return status will automatically change to CLOSED
.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Step 7 (Optional): Cancel a returnStep 7 (Optional): Cancel a return
If you create a return by mistake, have an error in the created return, or a customer has changed their mind about wanting to return an item, then you can cancel the return that you've created. Canceling a return restores an order's line items back to being fulfilled. To cancel a return, provide the ID of the return as input to the returnCancel
mutation.
You can only cancel a return if the return meets the following criteria:
- It must be in an
OPEN
state. - It can't have cancelled fulfillments.
- It can't have been refunded.
- It can't have dispositions.
- It can't have Shopify Shipping return label. Returns with manually-uploaded return labels and manually-provided tracking information (not PDFs) can be canceled.
Returns to Shopify Fulfillment Network (SFN) might be cancelable. If SFN rejects the cancelation request, then a "return failed" description displays in the Shopify admin.
When cancelling a return, you can expect that all sales records generated from the creation of a return will be reversed, nullifying the financial impact of the return on the order. Note: This will not affect the sales generated for exchange line items, nor will it cancel the fulfillments for any exchange line items.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Canceling a return removes it from the order details view in the Shopify admin:

Anchor to Step 8: Query a suggested financial outcomeStep 8: Query a suggested financial outcome
A suggested return financial outcome represents a financial outcome that Shopify suggests based on the items being processed. In your query provide the ID of the return and any return line items, exchange line items, and fees relevant to the calculation.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Step 9: Issue a refund and dispose return itemsStep 9: Issue a refund and dispose return items
When you refund an order, you send payment back to the customer. Using the returnProcess
mutation, you can issue a refund and associate it with the related return. You can refund an entire return or only part of an return. You may also choose not to refund at all and instead refund at a later time.
Although the refunding behavior of this mutation is similar to the refundCreate
mutation, with returnProcess
you ensure that the refund is attributed to the correct line item by specifying the intended return line item.
Additionally, the returnProcess
mutation also supports dispositions, allowing you to decide whether a returned item will be restocked into inventory as part of the processing step.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Step 10 (Optional): Close a returnStep 10 (Optional): Close a return
A Return will automatically close when all items have been processed processed and a disposition decision is made for all return items.
However, you can also use the returnClose
mutation to close a return at any time.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
A closed return is marked as Returned in the Shopify admin:

Anchor to Step 11 (Optional): Reopen a returnStep 11 (Optional): Reopen a return
If you need to reopen a closed return, then you can use the returnReopen
mutation. You can reopen a return only if it was closed.
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to WebhooksWebhooks
As of GraphQL Admin API version 2023-01 and higher, your app can subscribe to webhooks for event notifications related to returns, refunds, reverse fulfillment orders, and reverse deliveries. 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.
Return webhooks are available only in the GraphQL Admin API.
Example webhook responses
// Occurs when a return is requested. This means that the return's status is `REQUESTED`.
{
"id": 1,
"admin_graphql_api_id": "gid://shopify/Return/1",
"status": "requested",
"name": "1001-R1",
"order": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/Order/1"
},
// The `total_return_line_items` field represents the total number of line items in the return. In this example, the `return_line_items` field is an array with one return line item. `"total_return_line_items": 1` matches the number of `return_line_items`.
"total_return_line_items": 1,
// To confirm that you've retrieved all return line items, you can poll if `total_return_line_items` is bigger than `return_line_items.size`.
"return_line_items": [
{
"id": 1,
"admin_graphql_api_id": "gid://shopify/ReturnLineItem/1",
"fulfillment_line_item": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/FulfillmentLineItem/1",
"line_item": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/LineItem/1"
}
},
"quantity": 2,
"return_reason": "wrong_item",
"return_reason_note": "",
"customer_note": "I ordered the wrong item by accident. Could I get a refund or at least exchange it for store credit? Thanks."
}
]
}
// Occurs when a return is approved. This means that the return's status is `OPEN`.
{
"id": 1,
"admin_graphql_api_id": "gid://shopify/Return/1",
"status": "open",
"name": "1001-R1",
"order": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/Order/1"
},
// The `total_return_line_items` field represents the total number of line items in the return. In this example, the `return_line_items` field is an array with one return line item. `"total_return_line_items": 1` matches the number of `return_line_items`.
"total_return_line_items": 1,
// To confirm that you've retrieved all return line items, you can poll if `total_return_line_items` is bigger than `return_line_items.size`.
"return_line_items": [
{
"id": 1,
"admin_graphql_api_id": "gid://shopify/ReturnLineItem/1",
"fulfillment_line_item": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/FulfillmentLineItem/1",
"line_item": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/LineItem/1"
}
},
"quantity": 2,
"return_reason": "unwanted",
"return_reason_note": "",
"customer_note": "I ordered the wrong item by accident. Could I get a refund or at least exchange it for store credit? Thanks."
}
]
}
// Occurs when a return is declined. This means that the return's status is `DECLINED`.
{
"id": 1,
"admin_graphql_api_id": "gid://shopify/Return/1",
"status": "declined",
"decline": {
"reason": "final_sale",
"note": "Sorry, as we discussed on the phone, the return window passed."
}
}
// Occurs when a return has been fully or partially processed. The return's status is CLOSED when all items have been processed and a restock decision has been made.
{
"id":3788210232,
"admin_graphql_api_id":"gid://shopify/Return/3788210232",
"order_id":13789426221112,
"admin_graphql_api_order_id":"gid://shopify/Order/13789426221112",
"status":"open",
"return_line_items":[
{
"id":5415272504,
"admin_graphql_api_id":"gid://shopify/ReturnLineItem/5415272504",
"quantity":1,
"processed_quantity":1
}
],
"exchange_line_items":[
{
"id":125730872,
"admin_graphql_api_id":"gid://shopify/ExchangeLineItem/125730872",
"quantity":1,
"processed_quantity":0
}
]
}
// Occurs when a new refund is created without errors on an order, and includes returns data.
{
[...]
return: {
"id": 1,
"admin_graphql_api_id": "gid://shopify/Return/1"
}
}
// Occurs when a return is canceled. This means that the return's status is `CANCELED`.
{
"id": 1,
"admin_graphql_api_id": "gid://shopify/Return/1",
"status": "CANCELED"
}
// Occurs when a return is closed. This means that the return's status is `CLOSED`.
{
"id": 1,
"admin_graphql_api_id": "gid://shopify/Return/1"
}
// Occurs when a return is reopened. This means that the return's status is `OPEN`.
{
"id": 1,
"admin_graphql_api_id": "gid://shopify/Return/1",
"status": "OPEN"
}
// Occurs when a return is updated.
{
"admin_graphql_api_id": "gid://shopify/Return/1",
"return_line_items": {
"removals": [
{
"admin_graphql_api_id": "gid://shopify/ReturnLineItem/1",
"delta": 3
}
]
},
"restocking_fees": {
"updates": [
{
"admin_graphql_api_id": "gid://shopify/RestockingFee/1",
"shop_price_delta": {
"amount": 10,
"currency_code": "CAD"
},
"presentment_price_delta": {
"amount": 8,
"currency_code": "USD"
},
"return_line_item": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/ReturnLineItem/1"
}
}
],
"removals": []
},
"return_shipping_fees": {
"updates": [
{
"admin_graphql_api_id": "gid://shopify/ReturnShippingFee/1",
"shop_price_delta": {
"amount": 10,
"currency_code": "CAD"
},
"presentment_price_delta": {
"amount": 8,
"currency_code": "USD"
}
}
],
"removals": []
}
}
// Occurs when a disposition has been made.
{
"id": 1,
"admin_graphql_api_id": "gid://shopify/ReverseFulfillmentOrder/1",
// In this example, the `dispositions` field is an array with two dispositions.
"dispositions": [
{
"reverse_fulfillment_order_line_item": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/ReverseFulfillmentOrderLineItem/1"
},
"reverse_delivery_line_item": null,
"type": "RESTOCKED",
"location": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/Location/1"
},
"quantity": 1
},
{
"reverse_fulfillment_order_line_item": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/ReverseFulfillmentOrderLineItem/2"
},
"reverse_delivery_line_item": null,
"type": "MISSING",
"quantity": 1
},
{
"reverse_fulfillment_order_line_item": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/ReverseFulfillmentOrderLineItem/3"
},
"reverse_delivery_line_item": {
"id": 1,
"admin_graphql_api_id": "gid://shopify/ReverseDeliveryLineItem/1"
},
"type": "RESTOCKED",
"quantity": 2
}
],
// The `total_dispositions` field represents the total number of dispositions made on a reverse fulfillment order. `total_dispositions: 2` matches the number of `dispositions`.
"total_dispositions": 2
}
// Occurs when a reverse delivery is created or updated with delivery metadata, such as the delivery method, label, and tracking information that's associated with a reverse delivery.
{
"id": 2,
"admin_graphql_api_id": "gid://shopify/ReverseDelivery/2",
"return": {
"id": 3,
"admin_graphql_api_id": "gid://shopify/Return/3"
},
// To consume the webhook data and display return labels to buyers, you need the following information for return labels:
// - Supported file type(s)
// - Supported file size
// - URL prefix (for URL allow lists)
"shipping_deliverable": {
"label": {
"public_file_url": "https://www.example-host.com/label/1",
"created_at": "2022-05-18T10:28:33-04:0"
},
"tracking": {
"carrierName": "EX",
"tracking_number": "ABC11111111",
"tracking_url": "https://www.example-carrier.com/track/ABC11111111"
}
}
}
Anchor to Next stepsNext steps
- Learn how to build self serve returns with the Customer Account API.
- Learn how to manage exchanges with the GraphQL Admin API.
- Learn how to preview and refund duties with the GraphQL Admin API.
- Learn how to manage reverse fulfillment orders with the GraphQL Admin API.
- Learn how to manage reverse deliveries with the GraphQL Admin API.