Mastering Shopify Discounts: Unlocking Actual Money Values in GraphQL (Beyond REST)

Hey store owners and developers! As we navigate the powerful world of Shopify APIs, it’s common to hit a few head-scratchers, especially when transitioning between different API versions or paradigms. Just recently, I saw a great question pop up in the Shopify Community from Tom_Raney, and it sparked a fantastic discussion that I think many of you will find super helpful. It’s all about how to reliably get those crucial discount code amounts when you’re querying Shopify’s GraphQL API, particularly if you’re used to how the REST API handles things.

Tom’s core challenge was pretty straightforward: he wanted to see the actual monetary value of each discount code applied to an order when using GraphQL. He pointed out that the REST API’s order update webhook provides a neat discount_codes array, looking something like this:

“discount_codes”: [
   {
      "amount": "10.00",
      "code": "discounttest",
      "type": "fixed_amount"
   },
   {
      "amount": "19.99",
      "code": "foo",
      "type": "percentage"
   }
]

This is super clear, right? You get the code, the type, and the exact amount discounted. But when Tom tried to replicate this with GraphQL, he hit a snag. The discountCodes array in GraphQL just gave him an array of strings (the codes themselves), and the discountApplications attribute, while useful, often only listed percentages, not the final calculated value. Here’s an example of what he was seeing:

{
   "index": 1,
   "allocationMethod": "ACROSS",
   "__typename": "DiscountCodeApplication",
   "value": {
      "percentage": 10.0,
      "__typename": "PricingPercentageValue"
   },
   "targetType": "LINE_ITEM",
   "targetSelection": "ALL",
   "code": "foo"
}

Notice how that value field shows a percentage? That’s the rule, not the final money amount. This can be a real head-scratcher when you need precise financial data.

Tom also brought up a fantastic secondary question about rounding. If he were to calculate the discount himself (which he really didn’t want to do, and for good reason!), he observed that Shopify seemed to truncate rather than round to the nearest penny. For instance, 10% of $199.98 is $19.998. If you round, you get $20.00, but Shopify often shows $19.99. What’s the rule there?

The GraphQL Discount Breakdown: Applications vs. Allocations

Thankfully, Robert_Kanaan, another expert in the community, jumped in with a detailed and incredibly helpful explanation that cleared things right up. He highlighted a crucial distinction in Shopify’s GraphQL API that’s easy to miss:

  • discountApplications: This field describes the intent or the rules of the discount. Think of it as “what discount was applied” – was it a percentage, a fixed amount, a free shipping rule?
  • discountAllocations: This is the golden ticket! This field represents the actual money amount that was discounted, broken down per line item or shipping line. It’s Shopify’s finalized result after all the complex calculations, entitlements, and rounding have been applied.

Robert explained that to get that webhook-style result, where you see the actual monetary value for each discount, you need to query the discountAllocations on both your order’s lineItems and shippingLines. Then, you can group and sum these allocations by the related discount application (using its index or code).

How to Retrieve Discount Amounts with GraphQL

Here’s a step-by-step approach based on Robert’s excellent advice:

  1. Focus on discountAllocations: Instead of looking at discountCodes or solely discountApplications for the final amount, target discountAllocations within your lineItems and shippingLines.
  2. Construct Your GraphQL Query: You’ll need to fetch the order, then iterate through its line items and shipping lines, pulling out their respective discount allocations. Here’s a robust example query provided by Robert:

    query OrderDiscounts($id: ID!) {
      order(id: $id) {
        id
        name
        discountCodes
    
        currentTotalDiscountsSet {
          shopMoney {
            amount
            currencyCode
          }
        }
    
        lineItems(first: 100) {
          nodes {
            id
            name
            discountAllocations {
              allocatedAmountSet {
                shopMoney {
                  amount
                  currencyCode
                }
              }
              discountApplication {
                index
                targetType
                value {
                  __typename
                  ... on PricingPercentageValue {
                    percentage
                  }
                  ... on MoneyV2 {
                    amount
                    currencyCode
                  }
                }
                ... on DiscountCodeApplication {
                  code
                }
              }
            }
          }
        }
    
        shippingLines(first: 25) {
          nodes {
            title
            discountAllocations {
              allocatedAmountSet {
                shopMoney {
                  amount
                  currencyCode
                }
              }
              discountApplication {
                index
                targetType
                value {
                  __typename
                  ... on PricingPercentageValue {
                    percentage
                  }
                  ... on MoneyV2 {
                    amount
                    currencyCode
                  }
                }
                ... on DiscountCodeApplication {
                  code
                }
              }
            }
          }
        }
      }
    }
    

    This query gets you the order details, the raw discount codes, the total discount amount (currentTotalDiscountsSet), and crucially, the detailed allocations for both line items and shipping lines. Remember, if you have more than 100 line items, you’ll need to paginate the lineItems query.

  3. Process and Sum the Allocations: Once you have the query results, you’ll need to iterate through the discountAllocations for each line item and shipping line. You’ll sum up the allocatedAmountSet.shopMoney.amount for each distinct discount application. Robert suggested grouping by discountApplication.index or, for code-based discounts, by discountApplication.code. The idea is to aggregate all parts of a single discount that might be spread across multiple items.

    lineItems.nodes[].discountAllocations[].allocatedAmountSet.shopMoney.amount
    shippingLines.nodes[].discountAllocations[].allocatedAmountSet.shopMoney.amount
    

    grouped by:

    discountApplication.index
    

    or, for code discounts:

    discountApplication.code
    

    When Robert tested this method against a real order, the GraphQL allocation total perfectly matched the REST/webhook-style discount_codes.amount. It’s a solid approach!

    Understanding Shopify’s Rounding Rules

    Now, let’s tackle Tom’s great question about rounding. This is where Robert’s advice really shines: don’t try to recreate Shopify’s calculation or rounding logic yourself.

    Why? Because Shopify’s allocation fields already contain the *finalized result*. This amount has gone through all of Shopify’s internal entitlement rules, allocation methods (like 'ACROSS' or 'EACH'), line splitting, quantity handling, shipping/line targeting, and, yes, currency rounding. Trying to replicate this complex logic yourself is fraught with peril and can lead to discrepancies.

    As Robert observed, Shopify often allocates at a far more granular level than simply applying a percentage to the order subtotal and rounding once at the very end. This detailed, line-item-level allocation is precisely why you might see $19.99 instead of $20.00 for a 10% discount on $199.98. The system is doing its calculations with precision, distributing the discount across individual items before summing them up, resulting in the final, correct amount.

    So, the best practice here is to trust the discountAllocations.allocatedAmountSet.shopMoney.amount values provided by the API. They are the truth, as far as Shopify is concerned!

    Navigating the nuances between REST and GraphQL can feel like learning a new language, but once you understand the core concepts – like the distinction between discount applications and allocations – it becomes much clearer. The community discussion around Tom’s question is a perfect example of how diving into the specifics with expert input can save you a lot of time and headache. Keep those questions coming!

Share:

Start with the tools

Explore migration tools

See options, compare methods, and pick the path that fits your store.

Explore migration tools