Synthetic Industry

Troubleshooting guide · updated 2026-10-11

The sender says webhook delivery failed: timeouts, retries, deleted subscriptions and missed events

Answer quickly, expect repeats, and know how to find and replay events that arrived while your endpoint was down.

Two different failures from the sender's side

A sender judges your endpoint by what it receives back, and within a time limit. A delivery fails if you do not answer in time, or if you answer with something that is not a success. GitHub says a server should respond with a 2XX within 10 seconds, otherwise it drops the connection and treats the delivery as failed. Shopify documents a one-second connection timeout and a five-second timeout for the entire request, and counts any non-2xx response, including a redirect, as a failure. Your own logs may show the work completing fine after the sender has already given up.

  • Look at the sender's delivery log for the status and the time taken.
  • Compare it with your own log: did the work finish after the limit?
  • Check for a redirect, for example from http to https or from a bare domain to www; some senders count that as a failure.

Answer first, work second

The fix for timeouts is to separate acknowledging from doing. GitHub suggests queuing the payload so the server can acknowledge straight away and process it in the background without blocking later deliveries. The receiver verifies the signature, writes down that the delivery arrived, answers with a success status, and hands the work to something that can take as long as it needs. The important detail is the order: record before you answer. If you answer first and then crash before recording, the sender believes it succeeded and the event is gone.

  • Verify, record durably, answer, then process.
  • Keep the answer path short, with no calls to other systems.
  • Make the background work safe to run twice, because a crash can repeat it.

Retries mean repeats

Senders retry when they think a delivery failed, and sometimes when it did not. Shopify says it retries 8 times over the next 4 hours when there is no response or an error, and recommends that you process deliveries idempotently or, if you cannot, store each X-Shopify-Webhook-Id and skip ones you have seen. GitHub names its X-GitHub-Delivery header as a way to ensure each delivery is unique per event. Whichever sender you use, find the identifier it documents, keep a record of identifiers handled, check it before acting, and return success for a repeat without repeating the action. Remembering a header identifier handles the sender's own retries; it does not by itself stop someone replaying a captured request with the header changed, and the signature guide explains which identifier to trust for that.

  • Store the delivery identifier atomically, so two copies arriving together do not both pass.
  • Treat the same identifier as the same event, and a different identifier with similar content as a new one.
  • Return a success status for a repeat so the sender stops retrying.

When your endpoint was down

Do not assume a missed event will come back. GitHub states that it does not automatically redeliver failed deliveries; it offers a way to list deliveries and redeliver them through its REST API, where a failed delivery is one whose status is not OK, and it recommends redelivering missed webhooks once your server is back up. Shopify retries for about four hours and then, after eight consecutive failures, deletes a subscription that was created through the Admin API, so a long outage can remove the subscription as well as lose events. Other senders differ, so read the sender's own pages.

After an outage, reconcile instead of hoping. List what the sender says it delivered or what changed in the period, compare that with the identifiers you handled, and process only the difference, once each. If the sender's delivery log is short-lived, do this promptly.

  • Write down the start and end of the outage from your logs.
  • Check whether your subscription still exists, as well as whether it delivered.
  • Use the sender's delivery list or its normal listing endpoint to find what you missed.

What this guide does not cover

This guide does not promise that no event is ever lost; no receiver can promise that without the sender's cooperation. A reconciliation against the sender's delivery log is a separate piece of work. The paid receiver outcome covers fast acknowledgement and repeat-safe handling for one event type. For a system that has to find changes by asking, the polling outcome covers a checkpointed job that neither misses nor repeats records. Both are accepted by tests against synthetic data, not by a promise about live behaviour.

Sources and limits

  • GitHub: best practices for using webhooks Checked 2026-10-11.
    • A server should respond with a 2XX within 10 seconds, or GitHub drops the connection and treats the delivery as failed.
    • GitHub suggests queuing payloads so the server can acknowledge at once and work in the background, and says to redeliver missed webhooks once the server is back up.
    • GitHub presents the X-GitHub-Delivery header as a way to ensure that each delivery is unique per event.
  • GitHub: handling failed webhook deliveries Checked 2026-10-11.
    • GitHub does not automatically redeliver failed webhook deliveries.
    • Deliveries can be listed and redelivered through the REST API, where a failed delivery is one whose status is not OK.
  • Shopify: HTTPS webhook subscriptions Checked 2026-10-11.
    • Shopify documents a one-second connection timeout and a five-second timeout for the whole request, and treats any non-2xx response, including a redirect, as a failure.
    • Shopify retries 8 times over the next 4 hours, and after 8 consecutive failed attempts deletes a subscription created through the Admin API.
    • Shopify recommends idempotent processing and de-duplicating deliveries by the X-Shopify-Webhook-Id header.