Shopify

Beyond the First Discount: Mastering Shopify Order Queries with Webhooks & Tags

Hey there, fellow store owners and developers! Ever found yourself scratching your head trying to pull specific data from Shopify, only to hit a brick wall with the API? You’re definitely not alone. We recently saw a fantastic discussion in the Shopify community that really highlighted a common challenge: accurately tracking orders that use a specific discount code, especially when customers are stacking multiple discounts.

It all started with @Bellets, who was building a dashboard for ambassadors. The goal was simple: show each ambassador all the orders made using their custom discount code. Sounds straightforward, right? Well, here’s where the Shopify GraphQL API threw a curveball.

Flowchart depicting Shopify webhook triggering an external app to tag an order based on discount codes
Flowchart depicting Shopify webhook triggering an external app to tag an order based on discount codes

The GraphQL Discount Code Dilemma: Why Direct Queries Fall Short

As @Bellets explained, the problem surfaced when an order used more than one discount code, included the one they were searching for. The GraphQL API, in its default search behavior, often only indexes the first discount code applied to an order when using the general query parameter. So, if your ambassador's code was the second, third, or fourth one, that order wouldn't show up in a direct query. Talk about frustrating when you're trying to give your ambassadors accurate data!

The immediate thoughts that often come to mind – and were rightly dismissed by our community experts – were either grabbing all orders and filtering them server-side (a massive undertaking for 3500+ orders that grow daily, as @Bellets noted) or creating a local database cache. Both of these approaches have significant drawbacks in terms of scalability, maintenance, and keeping your local data small and current. Imagine the API calls and processing power needed to constantly sync thousands of orders!

Why the GraphQL query Parameter Has Limitations

The Shopify GraphQL API is incredibly powerful, but its general query parameter is designed for efficient, indexed searches on primary fields. When it comes to complex data structures like the discountCodes array (which contains multiple objects, each with its own properties like code, amount, etc.), the search index typically only keys off the first entry or a simplified representation. This is a common pattern in database indexing to maintain performance. While you can fetch the entire discountCodes array for an order, you can't reliably filter by a specific code within that array using the top-level query parameter alone.

The Community's Brilliant Solution: Webhooks & Order Tags!

This is where the collective wisdom of the Shopify community truly shines. The proposed solution is elegant, scalable, and leverages Shopify's built-in capabilities: using webhooks to react to order changes and applying order tags for efficient querying.

Step 1: Proactive Data Management with Webhooks

Instead of constantly querying for data, you let Shopify tell you when something relevant happens. Set up two crucial webhooks:

  • orders/create: Triggers when a new order is placed.
  • orders/updated: Triggers when an existing order is modified (e.g., discounts are added/removed, order status changes).

When one of these webhooks fires, your application receives a JSON payload containing the full order details. This is your opportunity to inspect the order's discountCodes array.

Step 2: Inspect & Tag Orders

Within your webhook handler, you'll implement a simple logic:

  1. Access the discountCodes array from the incoming order data.
  2. Iterate through each discount code object in the array.
  3. Check if any of the code properties match your target discount code (e.g., an ambassador's unique code).
  4. If a match is found, use the Shopify API's tagsAdd mutation to apply a specific tag to that order. For example, if the ambassador's code is AMBASSADOR123, you could tag the order as ambassador-AMBASSADOR123.

// Pseudo-code for webhook handler logic
function processOrderWebhook(orderData) {
  const targetDiscountCode = 'YOUR_AMBASSADOR_CODE'; // Replace with the actual code
  const ambassadorTag = `ambassador-${targetDiscountCode}`;

  if (orderData.discountCodes.some(dc => dc.code === targetDiscountCode)) {
    // Check if the tag already exists to avoid redundant updates
    if (!orderData.tags.includes(ambassadorTag)) {
      // Use Shopify Admin API to add the tag to the order
      // Example (Node.js with Shopify API client):
      // shopify.api.rest.Order.set({
      //   session: session,
      //   id: orderData.id,
      //   body: { order: { tags: [...orderData.tags, ambassadorTag].join(',') } },
      //   data_type: DataType.JSON,
      // });
      console.log(`Order ${orderData.id} tagged with ${ambassadorTag}`);
    }
  }
}

Step 3: Querying with Tags – The Scalable Solution

Once your orders are properly tagged, querying becomes incredibly efficient. You can now use the GraphQL API's query parameter to filter by your custom tag, which is natively indexed by Shopify:


query GetAmbassadorOrders($first: Int!, $after: String) {
  orders(first: $first, after: $after, query: "tag:ambassador-YOUR_AMBASSADOR_CODE") {
    pageInfo {
      hasNextPage
      endCursor
    }
    edges {
      node {
        id
        name
        processedAt
        totalPriceSet {
          shopMoney {
            amount
            currencyCode
          }
        }
        discountCodes {
          code
          amount
        }
        customer {
          firstName
          lastName
        }
      }
    }
  }
}

This query will return only the orders that have been tagged with ambassador-YOUR_AMBASSADOR_CODE, regardless of whether it was the first, second, or third discount applied. This is precisely what @HamidEjaz recommended, and it completely bypasses the original GraphQL dilemma.

Handling Existing Orders: The One-Time Bulk Operation

What about the 3500+ orders @Bellets already had? For historical data, you'll need a one-time bulk operation. Use Shopify's bulkOperationRunQuery to export a minimal set of data for all existing orders, specifically their IDs and the discountCodes array. Then, process this export on your server, identify the orders that contain your target discount code, and use the Shopify API to apply the appropriate tags to them. After this initial sync, your webhooks will keep everything current.

Why This Approach is Superior

  • Scalability: You're not constantly fetching and filtering large datasets. Shopify handles the indexing and filtering based on tags.
  • Accuracy: It correctly identifies orders where the discount code is present, regardless of its position in the stack.
  • Real-time Updates: Webhooks ensure your data is always current, reflecting new orders and updates almost instantly.
  • Reduced API Overhead: Fewer large queries mean less strain on your API rate limits and faster response times for your dashboard.
  • No Local Cache Needed: As @HamidEjaz pointed out, "no local order cache needed, the tag lives on the shopify order." This simplifies your application architecture significantly.

This powerful combination of webhooks and order tags provides a robust and efficient solution for tracking specific discount code usage across all orders. It's a prime example of how thoughtful integration development can overcome API limitations and deliver precise data for critical business functions like ambassador dashboards or campaign performance tracking.

Considering starting your own e-commerce journey on Shopify? Sign up for Shopify today and unlock powerful tools for your business. If you're looking to migrate your existing store to Shopify or need expert assistance with complex integrations like this, don't hesitate to reach out to the specialists at Shopping Cart Mover. We're here to ensure your e-commerce platform works exactly as you need it to.

Share:

Use cases

Explore use cases

Agencies, store owners, enterprise — find the migration path that fits.

Explore use cases