What counts as a failure
Section titled “What counts as a failure”| Response | Outcome |
|---|---|
2xx | Success. |
408, 429, any 5xx | Retryable. |
Any other 4xx | Permanent failure — status failed, no retries. |
| Timeout, connection error, DNS failure | Retryable. |
1xx, 3xx | Retryable. The endpoint is misbehaving, not refusing. |
The distinction matters: a 404 from your endpoint means the route does not
exist, and retrying for five hours will not create it. A 500 means your app
broke on a request it accepted, so retrying is exactly right.
Return a 2xx as soon as the payload is safely on your side and do the work
afterwards. A handler that finishes the job before answering will eventually hit
the timeout, and a timeout is a failure.
The retry schedule
Section titled “The retry schedule”The default schedule is 30s, 2m, 10m, 1h, 4h: five retries after the first
attempt, covering about five and a half hours. Each delay carries ±20% jitter so
that a destination coming back up is not hit by every queued retry at once.
The schedule is per destination and can be changed through the API — up to 10 intervals, each between 1 second and 24 hours. A short schedule fails fast; a long one holds a backlog longer. How exponential backoff is tuned in practice covers what the providers themselves do, if you are picking your own intervals.
When the last interval has been tried and failed, the delivery becomes
exhausted and moves to the dead-letter queue.
The circuit breaker
Section titled “The circuit breaker”Five consecutive retryable failures open a destination’s circuit. While it is open, deliveries to that endpoint pause for a cooldown that starts at 60 seconds and doubles on each re-open, up to 10 minutes. One probe is then let through:
| State | Shown as | Meaning |
|---|---|---|
closed | — | Normal. Everything is being attempted. |
open | Circuit open | Cooling down. Deliveries wait. |
half_open | Recovering | One probe in flight. Success closes the circuit, failure re-opens it. |
Any response that proves the endpoint is reachable — a 2xx, or even a 4xx —
closes the circuit and resets the counter. Nothing is lost while a circuit is
open; deliveries queue and resume.
Dead letters
Section titled “Dead letters”The source’s Dead letters tab lists deliveries that ended as exhausted or
failed, with the last error and last response status for each, and a summary
per gateway. Filter by all, exhausted or failed.
This is the list to work through after an outage: fix the endpoint, then replay. A dead-letter queue is what keeps an outage from becoming permanent data loss — the reasoning behind it is worth reading before you design the runbook around it.


Replaying
Section titled “Replaying”One event. Open the event and resend it. New deliveries are created and run the normal retry schedule. Disabled gateways are included — a resend is an explicit operator action, not automatic traffic.
A backlog. Replay in bulk per gateway, optionally narrowed to a status and a
time window. The default targets exhausted deliveries, which is the usual “my
endpoint was down for two hours” case:
curl -X POST https://app.webhooker.eu/api/v1/deliveries/resend-bulk \ -H "Authorization: Bearer $WEBHOOKER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "connection_id": "…", "statuses": ["exhausted", "failed"], "since": "2026-09-18T00:00:00Z" }'{ "created": 143 }Replay is only possible while the events are still inside your retention window.