Webhook retry guide

Webhook retry logic that does not create duplicate side effects.

Retrying a webhook is easy. Retrying safely means classifying failures, slowing down with backoff, preserving delivery logs, and assuming the receiver may see the same event twice.

API request
HTTPS only
// Receiver-side idempotency shape
const inserted = await db.processedWebhook.createMany({
  data: { idempotencyKey: event.idempotencyKey },
  skipDuplicates: true
});

if (inserted.count === 0) {
  return Response.json({ ok: true, duplicate: true });
}

Backoff instead of loops

Retry temporary failures with increasing delays so a recovering endpoint is not flooded.

Idempotency by default

Use stable event keys so duplicate deliveries do not create duplicate business side effects.

Attempts you can inspect

Store every status code, response body, latency, and final failure state for debugging.

Start by classifying the failure

Not every webhook failure deserves the same retry behavior. Timeouts, connection errors, 429 responses, and 5xx responses are often temporary. Most 4xx responses usually need customer action, not an infinite retry loop.

A useful retry system separates temporary failures from permanent failures. It should retry when recovery is plausible and stop when the request is invalid, unauthorized, or unsafe.

Exponential backoff protects the receiver

Backoff increases the delay between attempts. The goal is not just to improve success rate. It is to avoid turning one customer outage into a burst of repeated HTTP calls.

A common shape is immediate delivery, then retry after a short delay, then progressively longer delays until the job succeeds or reaches its final failure state.

Receivers must expect duplicates

A sender can time out even if the receiver processed the request. From the sender side, retrying is correct. From the receiver side, processing the same event twice may be dangerous.

That is why important webhooks need stable event IDs or idempotency keys. The receiver should claim the key atomically before running irreversible work.

Delivery logs are part of the retry policy

A retry policy without logs is hard to support. Teams need to see when each attempt happened, what status code came back, how long the request took, and whether another retry is scheduled.

Webhook Scheduler records delivery attempts so developers can inspect the timeline from the dashboard instead of searching through application logs.

When to use a managed retry layer

Build retry logic yourself if webhook delivery is core infrastructure for your product. Use a managed scheduler when the requirement is reliable delayed HTTPS delivery with logs and retries.

For product-specific examples, see automatic webhook retries and billing retry workflows.

FAQ

Which webhook failures should retry?

Timeouts, connection errors, 429 responses, and 5xx responses are usually retryable. Most 4xx responses are usually terminal.

Why do webhook retries need idempotency?

Retries can deliver the same event more than once if the receiver processed the request but failed to return a response in time.

Does Webhook Scheduler store delivery attempts?

Yes. Delivery attempts include status, latency, errors, and response details so failed jobs can be inspected.

Ship delayed webhooks without maintaining queue infrastructure.

Start with the free plan, test a real delivery, then upgrade when the workflow becomes production critical.

Create a free account