Skip to documentation

Webhooks

Retries and replays

How failed deliveries are retried, when an endpoint is disabled, and how to replay an event.

What counts as a failure

An attempt succeeds when your endpoint answers with a 2xx status within 15 seconds. Everything else fails: a 3xx redirect (never followed), a 4xx or 5xx status, a timeout, a connection error, or a hostname that resolves to a private address. When no HTTP response came back, the delivery log shows the status as No response and the reason in the response body, for example No response within 15 seconds.

Automatic retries

Each event gets up to 8 attempts. The wait before each one is:

text
1st: immediately
2nd: 5 seconds later
3rd: 5 minutes later
4th: 30 minutes later
5th: 2 hours later
6th: 5 hours later
7th: 10 hours later
8th: 10 hours later

Retries stop at the first 2xx, when the webhook is disabled or deleted, or after the 8th attempt. Until the last attempt has failed, the delivery's Result is Pending and the REST event status is pending or attempting; after it, Failed and failed.

Endpoint health

Opensend records when a webhook's attempts started failing without a success in between. When a further attempt fails five days or more after that point, the webhook is disabled and its pending retries stop. In the dashboard it shows as Disabled. Fix the receiver, then choose Enable from the webhook's ... menu; the failure clock starts over. Events that fired while it was disabled are not delivered later.

Replay an event

Once your receiver is fixed you can send an event again:

  • In the dashboard, open the webhook, click the delivery in the Deliveries table, and click Replay. The button is disabled while the webhook is disabled.
  • Through the API, call replay event. A disabled webhook returns 422.
bash
curl -X POST https://api.example.com/webhooks/YOUR_WEBHOOK_ID/events/YOUR_EVENT_ID/replay \
  -H "Authorization: Bearer $OPENSEND_API_KEY"
json
{"object":"webhook_event","id":"YOUR_EVENT_ID"}

A replay is one attempt with the original payload and the same svix-id. It is not retried on its own, and it does not cancel or restart the original event's automatic retries. In the dashboard a replay appears as its own row in Deliveries; in the REST event list it does not, but its attempt appears under the original event's attempts.

The delivery log

The webhook's page has a Deliveries table with Event, Status (the latest HTTP status), Attempts, and Sent columns, filtered by status (Succeeded or Failed) and by event type. A delivery's own page shows the endpoint, Result (Succeeded, Pending, or Failed), Sent, Attempts, Duration of the latest attempt in milliseconds, the Request body, and the Response body of the latest attempt.

Through the API, list events returns id, type, created_at, and status (pending, attempting, success, or failed), newest first. Retrieve an event adds next_attempt_at and the payload. List event attempts returns every automatic attempt and replay with http_status_code, response, and sent_at. Both lists accept limit (default 20, maximum 100) and after; before returns 422.

Stored response bodies are cut at 4 KiB. Events, deliveries, and attempts are deleted after 90 days.