Hi everyone,
we are currently investigating an issue related to exchange returns in Shopify.
The issue occurs when the original order contained either a discount code or a sale-priced item. In these cases, the exchange should be free for the customer, but Shopify appears to calculate an incorrect price difference during the return/exchange process.
For example, instead of processing the exchange with no additional payment required, Shopify may show a small outstanding amount, such as €2. Once the return/exchange is processed, the customer can receive a payment request or invoice for that amount, even though the merchant intended the exchange to be free.
From what we can see, the problem seems to be related to how Shopify calculates the exchange value when discounts are involved. It is not always clear whether Shopify uses the original item price, the discounted item price, the current product price, or the prorated discount amount when calculating the exchange difference.
The main questions are:
-
How does Shopify calculate the exchange value when the original order contained a discount code?
-
How are prorated discounts handled during an exchange?
-
Is there a way to override or adjust the exchange item price before processing the return?
-
Is there a way to prevent Shopify from sending a payment request when the merchant wants the exchange to be free?
-
What is the recommended workflow for handling free exchanges on discounted orders?
The expected behavior would be that merchants can process a free exchange without triggering an incorrect outstanding balance or payment request for the customer.
Has anyone else experienced this behavior, or is there an official recommended approach for handling exchanges when the original order included discounts or sale prices?
Thanks in advance.
EDIT: At the moment there is no way to edit values inside a return?!
Without any exchange the return-form “amount” is editable. This is also required for exchanges, many merchants are claiming the current behaviour as a big issues. Because there isn’t a way to edit the amounts within exchanges. Merchants reported that some of their customers are receiving email notifications from the shopify backend with a payment requests what causes unsatisfied customers.
Hey @Stefan_Neuser! You’re right that discounts and sale prices are the key details here, but we would need to see how the original order and return are represented before saying whether the amount to collect is expected or something we should raise with the relevant team.
Since this is a public forum, please do not post customer PII. The safest option is to share the redacted response from this Admin GraphQL query. The important parts are the original line prices, discount allocations, tax lines, current outstanding amount, and the return/exchange line items.
query OrderReturnExchangeDebug($orderId: ID!) {
order(id: $orderId) {
id
name
createdAt
currencyCode
presentmentCurrencyCode
taxesIncluded
totalDiscountsSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
currentSubtotalPriceSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
currentTotalTaxSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
currentTotalPriceSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
totalOutstandingSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
discountApplications(first: 20) {
nodes {
__typename
allocationMethod
targetSelection
targetType
value {
... on MoneyV2 {
amount
currencyCode
}
... on PricingPercentageValue {
percentage
}
}
}
}
lineItems(first: 50) {
nodes {
id
name
sku
quantity
currentQuantity
originalUnitPriceSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
discountedUnitPriceSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
originalTotalSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
discountedTotalSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
discountAllocations {
allocatedAmountSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
discountApplication {
__typename
allocationMethod
targetSelection
targetType
value {
... on MoneyV2 {
amount
currencyCode
}
... on PricingPercentageValue {
percentage
}
}
}
}
taxLines {
title
rate
priceSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
}
variant {
id
title
product {
id
title
}
}
}
}
returns(first: 10) {
nodes {
id
name
returnLineItems(first: 50) {
nodes {
id
quantity
... on ReturnLineItem {
fulfillmentLineItem {
id
lineItem {
id
name
sku
}
}
}
}
}
exchangeLineItems(first: 50) {
nodes {
id
quantity
processableQuantity
processedQuantity
unprocessedQuantity
variantId
lineItems {
id
name
sku
quantity
currentQuantity
originalUnitPriceSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
discountedUnitPriceSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
discountedTotalSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
discountAllocations {
allocatedAmountSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
}
taxLines {
title
rate
priceSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
}
}
}
}
}
}
}
}
Use the affected order GID as the variable.
{
"orderId": "gid://shopify/Order/1234567890"
}
Please redact names, addresses, emails, phone numbers, customer notes, and any other customer details before posting the response.
Once we can see those price, discount, tax, and exchange fields, we can tell whether the amount is coming from discount allocation, tax, return shipping/restocking fee, current exchange item pricing, or whether it looks like something we need to raise with the relevant team. Thanks!
Hey, there are no customer data in my post, is from our dev-store to reproduce the issue. I will come back to you with the data.
The issue is not that the amounts are not correct. It’s about being able to edit them before processing the return.
@Dieter_Frei you’re right that the native admin UI doesn’t expose an editable amount field on a return once an exchange line is attached, the calculated outstanding is what gets sent through.
I took a look and the developer-facing path for this has existed since 2024-07. ExchangeLineItemInput accepts an appliedDiscount field that takes either a fixed amount or a percentage. Apply 100% at returnCreate time and the exchange line nets to zero, so there’s no balance to collect from the customer. The same field exists on CalculateExchangeLineItemInput if you want to preview the financials with returnCalculate first.
mutation FreeExchange($returnInput: ReturnInput!) {
returnCreate(returnInput: $returnInput) {
return { id }
userErrors { field message }
}
}
{
"returnInput": {
"orderId": "gid://shopify/Order/1",
"returnLineItems": [
{
"fulfillmentLineItemId": "gid://shopify/FulfillmentLineItem/1",
"quantity": 1,
"returnReasonDefinitionId": "gid://shopify/ReturnReasonDefinition/640710815"
}
],
"exchangeLineItems": [
{
"variantId": "gid://shopify/ProductVariant/1",
"quantity": 1,
"appliedDiscount": {
"value": { "percentage": 100 },
"description": "Free exchange"
}
}
]
}
}
The older ReturnReason enum is deprecated, so returnReasonDefinitionId is the current pattern, and you can pull the IDs from the returnReasonDefinitions query. One small schema asymmetry to watch for is that returnReasonDefinitionId lives on ReturnLineItemInput (used by returnCreate) but not on CalculateReturnLineItemInput, so just omit the reason when previewing with returnCalculate.
@Stefan_Neuser still keen to see the order/return debug output when you get a chance, so we can confirm whether the residual €2 is expected discount-allocation behavior or worth raising separately. The PII note in my earlier reply was just a standard heads-up since the thread is public, not a flag that anything you shared was a problem!