Shopify webhook retry policy: 8 retries, 4 hours, then dropped

Shopify's current webhook retry policy was set on September 10, 2024: up to 8 retries over a 4-hour window using exponential backoff. After that, the event is dropped and the subscription may be removed.

Quick answer Shopify retries a failed webhook delivery up to 8 times over 4 hours using exponential backoff (policy updated September 10, 2024). Each attempt has a 5-second timeout. Any 2xx response is success; anything else is a failure. After 8 failed attempts the event is dropped permanently. If failures persist across multiple events, the webhook subscription itself is auto-removed and has to be re-registered.

The current policy at a glance

AspectValue
Max retries per event8
Total retry window4 hours
Backoff strategyExponential
Timeout per attempt5 seconds
Success status codes2xx (any)
Failure conditionsNon-2xx, timeout, TLS error, DNS failure, connection refused
Subscription auto-removalAfter persistent failure across multiple events
Notification on removalEmail to Partner emergency developer email
Recovery path after dropManual reconciliation via Admin API
Effective date of current policySeptember 10, 2024

Sourced directly from Shopify's docs

"Shopify retries failed webhook calls up to eight times in a four-hour period." — Shopify dev docs · Troubleshooting webhooks

"If your app doesn't respond within five seconds, then the delivery fails." — Shopify dev docs · Troubleshooting webhooks

"Webhooks will now be retried a total of 8 times over 4 hours using an exponential backoff schedule." — Shopify dev changelog · September 10, 2024

What this means in practice

The retry curve is front-loaded

Exponential backoff over 8 attempts in 4 hours puts most attempts in the first 30 minutes. The remaining attempts are spread thin across the back half of the window. By the time hour 2 rolls around, you've burned about 5 of 8 attempts. Outages longer than 2 hours have a low probability of catching the remaining retries.

The 5-second timeout is the most common failure mode

Shopify treats anything slower than 5 seconds as a failure regardless of the eventual response. That makes synchronous processing dangerous. If your handler does anything that occasionally crosses the threshold — a third-party API call, a slow DB write, an image resize — you'll see intermittent failures that look mysterious in logs because the work eventually completed. The fix is universal: read the raw body, persist it to a queue, return 200, then process async.

Subscription removal compounds the loss

The 8/4-hour rule is per event. If your endpoint is consistently failing across many events (e.g., every webhook returns 401 because of a botched HMAC secret rotation), the subscription itself gets removed. After that, future events stop firing — they aren't queued, they're not sent. Re-registration via the Admin API is required to resume delivery, and any data created during the gap has to be reconciled from the Admin API.

Compared to the previous policy

Before September 10, 2024, Shopify documented a longer retry window — closer to 19 attempts over 48 hours. The 2024 update compressed the curve dramatically.

Pre-Sept 10, 2024Current
Retries per event~198
Total window~48 hours4 hours
Tolerable outageUp to ~2 days~4 hours max

If you wrote your webhook reliability code before late 2024, the timing assumptions baked into your retry strategy may no longer be safe. Outages of 5+ hours that used to be recoverable through Shopify's curve are now permanent losses without a reconciliation layer.

A quirk worth knowing: API version fall-forward

Webhook payloads are versioned the same way as Admin API responses. Shopify releases a new API version every 3 months and supports each for at least 12 months, with 9 months of overlap between consecutive versions. If you subscribe a webhook with api_version = "2024-04" and that version becomes unsupported, Shopify falls forward to the oldest supported stable version (e.g., "2025-01"). The webhook still arrives, but the payload shape may have changed.

The signal is the X-Shopify-Api-Version response header in each webhook. Compare it to the version you intended to subscribe — any mismatch means you're on a fall-forward and your parser may quietly miss new fields or break on renamed ones.

Failure conditions in detail

  • 2xx — Success. Shopify considers the delivery complete and won't retry.
  • 3xx — Counted as failure. Shopify does not follow redirects.
  • 4xx — Failure. The most common in webhook contexts is 401 (HMAC verification failed). Every retry hits the same 401 unless your secret config changes.
  • 5xx — Failure. Generally retryable from Shopify's perspective since 5xx implies temporary upstream issues.
  • No response within 5 seconds — Timeout failure. Counted same as a 5xx.
  • TLS / connection errors — Failure. Cert expiry, hostname mismatch on a wildcard cert, connection refused.
  • DNS resolution failure — Failure. Less common but happens during DNS provider incidents.

What production-grade webhook handling looks like

Given the policy's tight constraints, the production pattern is roughly the same across every Shopify app that ships reliably:

  1. Respond 200 in under 100ms. The only synchronous work in the request lifecycle is HMAC verification and raw-body persistence. Everything else moves to a background job.
  2. Add your own retry layer. Sidekiq, BullMQ, AWS SQS, anything with exponential backoff over days, not hours.
  3. Reconcile against the Admin API. Hourly for high-value topics like orders/*. The only safety net for events Shopify dropped or never fired.
  4. Monitor subscription health. Daily cron calling webhookSubscriptions. Alert your engineers on any missing topic.
  5. Use X-Shopify-Event-Id for deduplication. The same value persists across retries.
  6. Watch X-Shopify-Api-Version. Detect fall-forward before your parser breaks.

Where HookRescue fits

HookRescue implements all of the above between Shopify and your existing handler. We extend the retry curve to 7 days, reconcile hourly against the Admin API, and re-register subscriptions before they get auto-removed. Your existing webhook handler doesn't change — we re-sign every payload with your client secret so HMAC verification keeps working exactly the same way.

Related