Migration & integrations
Webhook
A webhook is a message Shopify sends to your server, or to Google Pub/Sub or Amazon EventBridge, when something happens in a store: an order is paid, a product is updated, a customer is created. Other systems react in near real time instead of polling. Deliveries can arrive twice, late or out of order, so a correct integration verifies the HMAC signature, ignores duplicates and runs a periodic reconciliation.
How do Shopify webhooks work?
A webhook subscription pairs a topic with a destination. The topic names a resource and an action, such as orders/paid, products/update or inventory_levels/update. The destination is an HTTPS URL, a Google Cloud Pub/Sub URI or an Amazon EventBridge ARN. When the event happens, Shopify sends the payload there with headers that identify it: X-Shopify-Topic, X-Shopify-Shop-Domain, X-Shopify-API-Version, X-Shopify-Webhook-Id, X-Shopify-Event-Id, X-Shopify-Triggered-At and, for HTTPS, X-Shopify-Hmac-Sha256.
There are three ways to create one:
- App-specific subscriptions in the app's shopify.app.toml file. Shopify recommends this route. The same subscriptions apply to every store that installs the app and survive an outage without being recreated.
- Shop-specific subscriptions through the GraphQL Admin API, when topics, URLs or filters differ from store to store.
- Admin webhooks, which a merchant creates under Settings, Notifications, Webhooks, in JSON or XML. They suit a quick connection to an outside tool, but the event cannot be changed after creation.
Each subscription can carry a filter expression that suppresses deliveries you do not need, and an include_fields list that trims the payload. On a busy store, filtering at the subscription is cheaper than discarding events in your own code.
What does Shopify guarantee about delivery?
Less than most people assume. Shopify's documentation is explicit on four points:
- Order is not guaranteed. A products/update can arrive before the products/create it follows. Sort by the X-Shopify-Triggered-At header or the payload's updated_at field.
- Duplicates happen. A network timeout or a retry can deliver the same webhook twice.
- Delivery itself is not guaranteed. Shopify tells app developers not to rely on webhooks alone.
- Deliveries can be late. Shopify suggests checking timestamps if a webhook arriving up to a day late would cause problems.
The timing rules are strict. Shopify allows one second to open the connection and five seconds for the whole request. Any response outside the 200 range counts as a failure, including a 3XX redirect. A failed delivery is retried 8 times over the next 4 hours, with longer gaps each time. After 8 consecutive failures, a subscription created through the Admin API is deleted, and warning emails go to the app's emergency developer address. Admin-created webhooks are also removed after repeated failures. Removal is silent from the integration's side: orders keep coming in, and nothing reaches your system.
How do you verify a Shopify webhook?
For HTTPS deliveries, Shopify signs the raw request body with HMAC-SHA256, using the app's client secret as the key, and sends the result base64-encoded in the X-Shopify-Hmac-Sha256 header. Your endpoint computes the same digest and compares the two with a timing-safe comparison. If they differ, reject the request. Without this check, anyone who finds the URL can post fake orders to it.
The usual bug is parsing the body before verifying it. JSON middleware changes the bytes, so the digest never matches. Verify against the raw body first, then parse. If you rotate the client secret, Shopify can take up to an hour to start signing with the new one.
Google Pub/Sub and Amazon EventBridge deliveries do not need HMAC checks, and the bus also takes care of timeouts and bursts. Shopify recommends Pub/Sub for that reason, with EventBridge as the alternative.
How do you build a webhook handler that holds up in production?
- Verify the HMAC before anything else.
- Make processing idempotent. Where that is not possible, store each X-Shopify-Webhook-Id and skip IDs you have already seen.
- Return a 200 response at once and put the work on a queue. Slow inline processing is how a busy ERP turns into a retry storm.
- Reconcile state rather than assuming a sequence. Fetch the current record if an update arrives for something you have not created yet.
- Run a scheduled reconciliation job that queries the Admin API for records changed since the last run, using updated_at filters. This catches whatever the webhooks missed.
- Watch the delivery metrics. Apps built in the Dev Dashboard or with Shopify CLI get delivery logs for the past 7 days, response times and failure rates. Shopify treats a failure rate above 0.5% as higher than average, and response times between four and five seconds as a warning sign.
Webhooks, Events, Flow or bulk operations: which should you use?
Webhooks are right when one change in Shopify should trigger one action elsewhere: an order paid goes to the warehouse, a refund goes to accounting. They cover the widest range of topics.
Events is Shopify's newer subscription model for apps. It is configured only in shopify.app.toml and covers a subset of Admin API resources, but lets you trigger on specific field changes, such as a variant price, and shape the payload with your own GraphQL query. Events and webhooks can run side by side in the same app.
Shopify Flow suits merchants who want an event to call an outside service without building an app.
Bulk operations are for volume. Loading a large catalogue from a PIM into Shopify is a batch job, and it works best when only changed products are re-sent. Webhooks do the opposite job: telling other systems what changed inside Shopify. Many integrations use both.
Which webhooks are mandatory?
Apps listed on the Shopify App Store must subscribe to three compliance topics: customers/data_request, customers/redact and shop/redact. They handle privacy requests to view or erase customer data. They can be set in the app configuration file or the Dev Dashboard, but not through the Admin API. Custom apps built for one store do not go through App Store review, but they still hold customer data and should be designed with these requests in mind.
What goes wrong in ERP and inventory integrations?
Most failures we see are not single broken requests. They are records that drift: orders appearing twice in the ERP, fulfilments that never registered, stock levels that slowly stop matching. Our ERP integration entry covers the wider design.
Matching logic is a common root cause. An integration has to decide whether an incoming record is new or one it already knows, usually by an ID, SKU, email or order number. Rules that are too loose merge records that should stay apart; rules that are too strict create duplicates. Whatever moves the data, webhooks or a scheduled connector, those matching and deduplication rules decide whether the sync stays correct. Store the Shopify ID on the other system's record wherever you can, and match on it first.
If you are planning a new integration or cleaning up one that drifts, our Shopify Plus migration team designs the event model, the reconciliation jobs and the monitoring together.
Need this done on your store?
Shopify developmentRelated terms
- API integrationAn API integration connects Shopify to another system — an ERP, a 3PL, a CRM — so data flows between them without manual re-entry. Direction and authority matter more than the plumbing: deciding which system owns inventory, and which merely reflects it, prevents the two from overwriting each other. Most integration bugs are ownership bugs, not transport bugs.
- Admin APIThe Admin API is Shopify's privileged GraphQL API for reading and writing store data — creating products, fulfilling orders, editing inventory. Unlike the Storefront API it must never be called from a browser, because its tokens can mutate the store. Apps, integrations, and back-office automations run against it, subject to rate limits that scale with plan.
- Shopify FlowShopify Flow is Shopify's free automation app, built around triggers, conditions and actions. A workflow starts when something happens in the store, such as an order being paid or stock running low, checks the data, then acts: tagging a customer, holding a risky order, sending an alert or updating another app. Flow is available on the Basic, Grow, Advanced and Plus plans.