Did Shopify change the webhook retry policy?

Shopify shortened its webhook retry window on September 10, 2024. Every blog post older than that is now out of date. Here's what changed and what to update in your runbook.

Last reviewed · Verified against Shopify dev docs.

Did Shopify change the webhook retry policy?

Quick answer Yes — Shopify shortened the retry window on September 10, 2024. The current policy is 8 retries over 4 hours with exponential backoff (shopify.dev changelog: updates-to-webhook-retry-mechanism). Older posts that cite 19 retries or a 48-hour window were accurate before that date and are now stale. If your runbook is older than September 2024, update it.

What changed on September 10, 2024

The changelog entry is short. The relevant sentence:

Webhooks will now be retried a total of 8 times over 4 hours using an exponential backoff schedule.

Two practical consequences that aren't spelled out in the changelog but follow directly:

  1. Your full retry budget is shorter. A handler that's down for half a day no longer recovers on its own from the queue — the window closed.
  2. Subscription auto-removal triggers faster. The troubleshooting doc says it plainly: "Shopify retries failed webhook calls up to eight times in a four-hour period, but if failures persist past that point the webhook subscription is removed." Whatever your prior assumption was about how long you could be down before losing the subscription, halve it.

What the prior policy looked like

The exact prior values are not quoted on shopify.dev. They were widely community-documented as 19 retry attempts over 48 hours — that's what most blog posts still cite. Treat that as community recollection, not Shopify's words. The official record only documents the current policy and the date it took effect.

The deprecation of the longer window matters for two reasons:

  • If you copy-pasted retry-aware logic from a 2022 or 2023 post, your backoff assumptions about when events become "permanently lost" are now too generous.
  • SLA wording in your customer agreements that referenced "48-hour Shopify retry" is now technically incorrect.

The new X-Shopify-Triggered-At header

Shipped alongside the retry-window change. It carries the timestamp Shopify originally fired the event, regardless of how many retries it took to land. Useful when:

  • Your handler does freshness-sensitive work (auto-cancel an unpaid order older than X minutes). A payload that took 3 hours to arrive should not trigger the cancel path.
  • You want to chart end-to-end latency from Shopify's source-of-truth time to your ingest time, not your handler-receive time.

Example check before processing:

triggered = Time.iso8601(request.headers["X-Shopify-Triggered-At"])
if Time.now - triggered > 30.minutes
  Rails.logger.warn("late delivery: #{Time.now - triggered}s")
  # decide per-topic whether to skip stale logic
end

What this changes about how you should run webhooks

Runbooks

Any documented playbook that says "Shopify retries for 48 hours, so we have until tomorrow to fix the handler" is wrong. Cut every "X hours until permanent loss" estimate to a quarter of what it used to be. The realistic deadline is closer to 4 hours from the first failure for new events to keep arriving, and the same 4-hour clock decides whether your subscription survives.

Monitoring

If you alert on "no webhooks in N minutes," the threshold for N matters more now. Before the change you might have gone half a day before discovering something was wrong and still recovered. Now, by the time you've gone half a day, the subscription's gone and you're doing Admin API reconciliation instead of a simple replay.

Reconciliation cadence

Hourly Admin API reconciliation went from nice-to-have to load-bearing. Once the retry budget closes, the Admin API is the only source of truth for what Shopify actually recorded. Polling once a day means the longest gap between a missed event and recovery is 24 hours. Polling hourly caps it at an hour.

Quick audit checklist

Five things to check before this week's release:

  1. Search your codebase for any literal "48" or "19" near the word "retry" or "webhook." Update or delete.
  2. Check your customer-facing docs (status pages, support articles, SDK readmes) for the same. Customers cite your docs back to you in tickets — keep them honest.
  3. Confirm your monitoring alerts fire well inside the 4-hour window. A "no webhook in 6 hours" alert is now too late.
  4. Make sure something — a cron, a worker, a service — re-registers a webhook subscription that's been auto-removed. The 4-hour window doesn't reset when you fix the handler; it just stops sending.
  5. If you don't already reconcile against the Admin API, today's a good day to start. The retry window is too short to assume retries alone will save you.

Where HookRescue fits

We sit between Shopify and your handler. Failed deliveries get retried by us for 7 days instead of 4 hours, so transient outages stop ending in dropped events and removed subscriptions. We also re-register subscriptions when Shopify deletes them and pull from the Admin API hourly to backfill anything that slipped through. The September 2024 change made the recovery side of the equation more important, not less — we're built around it.

Related problems