Skip to main content
For every event your endpoint subscribes to, Relay sends one POST request with the event as a JSON body:
Any 2xx answer within 10 seconds counts as delivered. Anything else is a failed attempt: a 3xx, 4xx or 5xx, a timeout, a refused connection or a TLS error. Redirects are not followed.

Retries

A failed delivery is retried on a fixed schedule, up to 8 attempts in all, until one succeeds.
Sequence diagram between Relay and a customer webhook endpoint: attempt 1 fails with 503, Relay waits 1 minute, attempt 2 fails, Relay waits 5 minutes, attempt 3 succeeds with 200. If all 8 attempts fail, the delivery is marked failed and can be replayed.

The endpoint fails twice and answers 200 on the third attempt, so retries stop. After 8 failed attempts the delivery is marked failed.

All 8 attempts take about 45 hours. Each wait has up to 10% random jitter, so retries from many events don’t arrive at once.

Failed deliveries

When the last attempt fails, the delivery is marked failed and shows up under Webhooks → Failed in the dashboard. Fix your endpoint, then replay one or all of them:
If every delivery to an endpoint has failed for 5 days, Relay disables the endpoint and emails your account’s owners.

Order

Relay doesn’t guarantee order. A retried invoice.created can arrive after invoice.paid.
Sequence diagram between Relay and your webhook endpoint: at 10:00:01 invoice.created gets a 503 and is scheduled for retry in 1 minute; at 10:00:06 invoice.paid is delivered with 200; at 10:01:01 invoice.created is retried and delivered with 200. Each event keeps its created time, 10:00:00 and 10:00:05.

invoice.created fails its first attempt and is retried a minute later, after invoice.paid has already been delivered.

Use the event’s created time, or fetch the current state from your own database, rather than assuming the last event you received is the latest.

Answer fast

Answer 200 as soon as you have stored the event, then do the work in a background job. A handler that takes longer than 10 seconds fails even if it finishes the work, and the event is delivered again. See Idempotency for handling those duplicates.