Delivery and retries
What happens when your endpoint is slow, down, or briefly wrong.
ProposedNot yet callable
This documents a design under review. Endpoints, payloads and field names may change before release.
Guarantees
- Delivery is at least once. A network timeout can produce a duplicate, so treat
idas an idempotency key and ignore ids you have already applied. - Respond
2xxwithin 10 seconds. Queue the work and acknowledge immediately rather than processing inline. - Your response body is ignored. Only the status code is read.
The practical shape of a handler: verify, write the event id to a table with a unique constraint, return 200, then process asynchronously. The unique constraint is what makes a duplicate harmless.
Retry schedule
Any non-2xx or a timeout is retried with exponential backoff. Five attempts spread over roughly 8 hours:
| Attempt | Delay after previous |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 6 hours, then marked failed |
A deploy that takes your handler down for ten minutes loses nothing — the retries cover it.
Ordering
Ordering is not guaranteed. A retried attendance.recorded can arrive after the attendance.updated that corrected it.
// Reject anything older than what you already hold.
if (existing && existing.updated_at >= event.created_at) return;Compare created_at before applying a change and last-write-wins becomes correct rather than a race.
When an endpoint is disabled
After 24 hours of continuous failure the endpoint is disabled and the institution’s admins are emailed. Failed deliveries are retained for 30 days and can be replayed once you have fixed the handler.
POST /v1/webhook_endpoints/whe_8f21c0/replay
{ "from": "2026-07-19T00:00:00Z", "to": "2026-07-19T12:00:00Z" }