Shopify Gift Cards & POS Sync: Navigating Webhooks & Keeping Balances in Harmony

Hey everyone! As a Shopify expert who spends a lot of time digging into the community forums, I often come across really insightful discussions that highlight common challenges store owners face. Recently, a thread caught my eye about syncing Shopify gift card balances with external POS or ERP systems. This isn't just a technical detail; it's crucial for a seamless customer experience and accurate accounting, especially for omnichannel retailers. Let's dive into what we learned from our community members, 'amf-devs' and 'lumine,' on this topic.

The Challenge: Keeping Gift Cards in Sync Across Systems

The original poster, 'amf-devs,' laid out a very clear scenario that many of you might recognize. They're building an integration to connect a Shopify store with an external POS/ERP. Their goal? To ensure that when a customer buys a gift card on Shopify, the same card and its balance can be redeemed in the physical store. And critically, whenever that balance changes — whether it's redeemed online, manually adjusted by an admin, or used elsewhere — they wanted the POS to reflect the exact new balance. The reverse also needed to work: a redemption at the physical POS should update Shopify. Here's their desired flow, with part 1 already working:

  1. Customer buys a gift_card: true product on the Shopify storefront. Shopify issues the GiftCard natively (emails the code, lists it under Products → Gift cards). :white_check_mark: already working
  2. Our app mirrors the issued balance into the external POS so the same code can be redeemed at the physical store.
  3. Whenever the balance changes — customer redeems at Shopify checkout, admin manually adjusts, or another channel debits — we want to push the new balance to the POS so the two sides stay in sync.
  4. Reverse direction: when the customer redeems part of the balance at the physical POS, we call giftCardDebit on the Shopify side so the storefront balance reflects the spend.

The Expected Solution (and the Twist!)

'amf-devs' logically assumed that Shopify's webhooks would be the perfect mechanism to keep these systems in sync. Specifically, they were looking for gift_cards/create (fired when a new gift card is issued) and gift_cards/update (fired when the balance changes). This makes total sense! However, here's where the plot thickened. When they tried to subscribe to these webhooks using both the Admin REST API and GraphQL, Shopify rejected them outright:

REST (POST /admin/api/2024-10/webhooks.json with topic: "gift_cards/create"):

422 Unprocessable Entity
"Invalid topic specified: gift_cards/create. Does it exist?
Is there a missing access scope?"

GraphQL (webhookSubscriptionCreate with topic: GIFT_CARDS_CREATE):

INVALID_VARIABLE — Expected "GIFT_CARDS_CREATE" to be one of [list of valid topics]

This was confusing, right? Especially since, as 'amf-devs' mentioned, some community threads and even Shopify's own AI assistant seem to reference these topics. It led to a natural question: do these webhooks even exist anymore, or are they hiding behind a specific plan tier?

The Community Weighs In & The Current Reality

Another community member, 'lumine,' initially chimed in, confirming that gift_cards/create and gift_cards/update are indeed real webhook topics, and that gift_cards/update is the one you'd want for balance changes. 'lumine' also highlighted a critical best practice: always treat the webhook as a "go re-read" signal, not the absolute source of truth. Webhooks can arrive out of order or get collapsed, so you should always query the gift card via GraphQL (giftCard(id)) to get the authoritative balance. This is super important advice for any integration!

However, given 'amf-devs's direct experience with the API rejections, it seems that while these webhooks might exist for certain legacy integrations or specific Shopify Plus plans (as 'lumine' hinted at with "Plus-gated historically"), they are not generally available through the standard Admin API for app developers trying to subscribe today. This is a crucial distinction and something to be aware of if you're building a new integration in the current API version.

So, How Do We Sync Gift Cards Now? The Recommended Pattern

If direct gift_cards/create and gift_cards/update webhooks aren't an option for most of us, what's the recommended pattern for keeping your Shopify-issued gift card balances in sync with an external system? 'amf-devs' themselves proposed a solid workaround, which, combined with 'lumine's advice, forms a robust strategy:

  1. Detecting Gift Card Issuance: Instead of a dedicated create webhook, you'll need to listen to the orders/paid webhook. When an order is paid, check its line items for any product where gift_card: true. Once you identify a gift card purchase, you can then query the resulting GiftCard via GraphQL using its order_id. This allows you to get the full details of the newly issued gift card.
    Example query: giftCards(query: "order_id:X")
  2. Tracking Redemptions: Similarly, for redemptions happening on the Shopify side (e.g., at checkout), the orders/paid webhook is your friend again. The gift_cards array embedded within the orders/paid payload will contain information about any gift cards used in that transaction. This gives you a clear signal that a balance has changed due to redemption.
  3. Handling Other Balance Adjustments (and the 'Go Re-Read' Principle): This is where it gets a bit trickier without a direct update webhook. For things like manual admin adjustments or other debits/credits that aren't tied to an orders/paid event, you'll need to implement a polling mechanism. This means periodically querying the giftCards endpoint and filtering by updated_at to find any gift cards that have changed since your last check.
    Example query: giftCards(query: "updated_at:>")
    Remember 'lumine's advice here: whenever you detect any change or get a signal, always re-fetch the gift card's full details using giftCard(id) to ensure you have the absolute latest, authoritative balance from Shopify. This protects against any potential timing issues or partial updates.

The Reverse Flow: POS to Shopify

For the reverse direction — when a customer redeems part of their balance at your physical POS and you need to update Shopify — the good news is that the giftCardDebit mutation works as expected! 'amf-devs' confirmed this. You'll need the write_gift_card_transactions scope for this. As for Shopify informing your system after your own debit is processed, without a direct update webhook, your best bet is to either re-query the gift card's balance immediately after the giftCardDebit call, or rely on your periodic polling mechanism to pick up the change.

Essential Scopes for Gift Card Integrations

Just a quick reminder: to make all of this work, your app will definitely need the necessary gift card-related scopes granted: read_gift_cards, write_gift_cards, read_gift_card_transactions, and write_gift_card_transactions. 'amf-devs' already had these, which confirms they're on the right track regarding permissions.

So, while the direct gift_cards/create and gift_cards/update webhooks might not be readily available for many Shopify integrations today, the community has clearly outlined a robust, albeit slightly more complex, pattern to achieve that crucial balance sync. It involves combining orders/paid webhooks with targeted GraphQL queries and a smart polling strategy. The key takeaway, as 'lumine' wisely pointed out, is always to treat Shopify as the single source of truth for the gift card balance and design your integration to always 'go re-read' that authoritative data. This approach ensures your external POS or ERP system stays perfectly in harmony with Shopify, providing a smooth experience for both you and your customers. Happy syncing!

Share:

Start with the tools

Explore migration tools

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

Explore migration tools