Shopify webhook subscription removed: causes, detection, recovery

When Shopify removes a webhook subscription, new events stop arriving entirely — there's nothing to retry because nothing was ever sent. Most teams discover this days later from a support ticket.

Quick answer Shopify removes a webhook subscription after 8 failed delivery attempts within a 4-hour window. After removal, new events for that topic stop arriving entirely — there's nothing to retry because nothing is being sent. To recover: query webhookSubscriptions via the Admin API, identify which topics are missing, re-register them with webhookSubscriptionCreate, then reconcile any data created during the gap from the Admin API.

Symptoms

  • A topic that used to fire every few minutes has been silent for hours.
  • You manually trigger an event in the Shopify admin (e.g., create a draft order) and your endpoint receives nothing.
  • Customers report data your system never recorded — but only data created after a specific time.
  • Older events for the topic are still in your DB, but the timeline has a clean cutoff.
  • A "your webhook is failing" warning email from Shopify is sitting in your Partner account inbox.

Why removal happens

The current Shopify retry policy retries failed deliveries 8 times across 4 hours using exponential backoff. The same logic applies per-event. The subscription-level removal kicks in when failures persist across multiple events — the docs describe it as auto-removal "after 8 failed delivery attempts" with the broader behavior of removal after sustained failure. The key insight: even brief outages can pile up. If your endpoint returns 5xx for an hour during a deploy, every event that fired in that hour starts its 8-retry curve. By the end of the 4-hour window, dozens of events have hit their retry limit and the subscription removal threshold is met.

A practical pattern that triggers removal:

HourEvent
09:00Long deploy starts. Endpoint returns 502 for 90 minutes.
09:00–10:3020+ webhooks fire during the outage; each starts its 8-retry curve.
10:30Endpoint healthy again. Some retries succeed.
10:35Shopify warning email sent to Partner emergency developer email.
13:00Earliest events exhaust their 8-retry curve. Removal threshold approaches.
14:00Subscription auto-removed. New events stop firing.
Next dayCustomer reports a missing order. You investigate and find the silent cutoff.

Recovery

Step 1: List current subscriptions and find the gap

query {
  webhookSubscriptions(first: 50) {
    edges {
      node {
        id
        topic
        endpoint {
          ... on WebhookHttpEndpoint { callbackUrl }
          ... on WebhookEventBridgeEndpoint { arn }
          ... on WebhookPubSubEndpoint { pubSubProject pubSubTopic }
        }
        format
        apiVersion { handle }
      }
    }
  }
}

Diff against your expected topics list. Whatever is missing is what got removed.

Step 2: Re-register with webhookSubscriptionCreate

mutation reRegister {
  webhookSubscriptionCreate(
    topic: ORDERS_CREATE,
    webhookSubscription: {
      callbackUrl: "https://your-app.com/shopify/webhooks",
      format: JSON
    }
  ) {
    webhookSubscription { id topic apiVersion { handle } }
    userErrors { field message }
  }
}

The new subscription gets a new ID. The old one is gone — there's no "undelete." Run this for each missing topic.

Step 3: Reconcile data created during the gap

The events that fired between the moment the subscription was removed and the moment you re-registered were never sent. They aren't waiting somewhere. The only path is the Admin API — pull every relevant record from the gap window, diff against your local store, and replay anything missing through your handler with synthesized payloads. Bulk operations are designed for this and don't count against the standard rate limits.

Full step-by-step in recover missed Shopify orders.

Step 4: Audit-log the recovery

When customers later ask why an order has a processed_at hours after the placed_at, you need an answer. Tag every replayed event with a marker (a custom header, a flag in your DB) so future audits can identify it as reconciled vs real-time.

Prevention

  • Daily subscription health check. A small cron job that calls webhookSubscriptions and alerts your engineering channel if any expected topic is missing. Don't rely on the Partner email.
  • Endpoint timeout monitoring. Track p95/p99 webhook handler response time. If it ever approaches 5 seconds, refactor to async processing immediately.
  • Anomaly alerts on retry counts. If your average attempt count per event suddenly climbs above 1.5, something is failing and you have a few hours before subscriptions start getting removed.
  • Partner email forwarding. Forward the Partner emergency developer email to a Slack channel or PagerDuty so the warning actually reaches an engineer.
  • Mandatory privacy webhooks too. customers/data_request, customers/redact, and shop/redact are required by Shopify. If they fail and get removed, you have a compliance problem on top of a delivery problem.

Where HookRescue fits

HookRescue watches your delivery success rate per shop and re-registers subscriptions automatically when they get removed. Failures get retried for 7 days instead of 4 hours, so transient outages rarely accumulate enough failures to trip the removal threshold in the first place. And if removal does happen, hourly reconciliation against the Admin API catches any data created during the gap and replays it through your handler with full HMAC integrity. The audit log shows you exactly which events were synthesized and when.

Related