2xx status within 10
seconds. Anything else — 4xx, 5xx, connection refused, DNS failure,
timeout — triggers the retry schedule.
Retry schedule
Each delivery gets one initial attempt plus five retries — six attempts total — spaced so a receiver outage of up to ~15 hours can recover without dropping events.| Attempt | Delay from previous |
|---|---|
| 1 (initial) | — |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 12 hours |
Retries reuse the same
delivery_id. Persist that ID on your side and
short-circuit on duplicates — the same event landing in your receiver
twice should be a no-op, not a double-count.What’s in the delivery log
Every attempt — successful or failed — is recorded and visible on the endpoint’s detail page:- HTTP status code (or
nullif the request never got a response) - Request body (truncated if large)
- Response body (truncated)
- Duration in milliseconds
- Attempt number
- Whether this row was dead-lettered
- Network error string when the request didn’t complete (e.g.
ETIMEDOUT,ECONNREFUSED)
Manual replay
A dead-lettered delivery can be replayed from the admin portal once you’ve fixed the receiver. Replay resets the attempt counter and schedules a fresh attempt immediately. Under the hood it calls:What NOT to rely on
Test deliveries don’t retry
The Send test button fires a one-shotwebhook.test delivery. It
doesn’t participate in the retry schedule — a failed test delivery is
dead-lettered on the first failed attempt so the UI can surface the error
immediately.