Retries and failure
Any 2xx is success; everything else is retried, up to eight attempts over about 21 hours. Endpoints that keep failing are paused, not dropped.
Any 2xx is a success. Everything else is a failure and will be retried: a 4xx, a 5xx, a timeout, a DNS failure, a TLS failure. A 3xx is a failure too, because redirects aren’t followed.
The schedule
| Attempt | Sent | Cumulative |
|---|---|---|
| 1 | immediately | 0 |
| 2 | after 30 s | ~30 s |
| 3 | after 2 min | ~2.5 min |
| 4 | after 10 min | ~12 min |
| 5 | after 30 min | ~42 min |
| 6 | after 2 h | ~2.7 h |
| 7 | after 6 h | ~8.7 h |
| 8 | after 12 h | ~21 h |
then the delivery is DEAD |
- Each interval carries full jitter, so deliveries that failed together don’t retry together.
- A
Retry-Afterheader on your response is honoured, capped at that attempt’s interval. - Timeouts: five seconds to connect, ten seconds for your response. Design against ten.
- On a failure, up to 2 KB of your response body is stored and returned by the delivery API.
Delivery states
| State | Meaning |
|---|---|
PENDING |
Queued |
IN_FLIGHT |
Being sent |
SUCCEEDED |
You returned 2xx |
FAILED |
Will be retried |
DEAD |
Eight attempts exhausted; replayable |
CANCELLED |
The endpoint was deleted before it could be sent |
When an endpoint keeps failing
After 20 consecutive failures, an endpoint moves to AUTO_PAUSED and you’re notified. A 410 Gone counts double, because that’s your server saying the URL is dead.
Nothing is lost while an endpoint is paused: events still fan out and the backlog grows. POST /webhook/endpoint/{reference}/resume resets the failure counter and sends the backlog. Fix the receiver first.
Pausing on purpose is the right move before a deploy that touches the receiver: POST /webhook/endpoint/{reference}/pause, deploy, resume.