Skip to content

Retries and the delivery log

Every event goes to each endpoint as its own delivery, tried on its own, so an endpoint that’s down never holds up the others or the change that caused the event. Deliveries go out after the change is saved: an event is never sent for something that didn’t happen.

An attempt succeeds when the endpoint answers 2xx within 5 seconds. Anything else fails it: another status, a redirect, a timeout, a connection or TLS error.

A failed delivery is tried again after 5 seconds, then 10, 20, 40 and so on, doubling each time up to an hour between tries: 12 tries in all, over about two and a half hours. After the twelfth, the delivery is given up and left for Digize’s operators, who can send it again.

Each try is signed again with its own time, and carries the same digize-delivery header and body id, so a receiver that took an earlier try can tell.

An endpoint whose attempts fail 50 times in a row, about four deliveries’ worth of retries, is turned off: its disabledAt is set, nothing more is sent to it, deliveries still waiting are dropped, and the workspace’s owners and admins get an email. Fix the endpoint, then add it again with POST /api/v1/webhooks (it gets a new secret) and remove the old one.

An endpoint that answers 410 Gone is removed straight away, and the removal is in the workspace’s audit log.

GET /api/v1/webhooks shows how each endpoint is doing:

Field
failures Attempts that failed since the last one that got through.
lastDeliveryAt When a delivery last got through.
disabledAt When the endpoint was turned off, or null.

Every attempt is also written to the workspace’s logs: the endpoint, the delivery and event ids, the event, the URL, the status (0 when nothing answered), whether it got through, how long it took and the error. That log isn’t readable from the API or the app yet.

To check an endpoint end to end, POST /api/v1/webhooks/{id}/ping sends it a settings.webhook.ping event, whatever events it chose, and answers the delivery’s id.