Delivery, retries & idempotency
Retry schedule, at-least-once delivery, endpoint auto-disable, and how to dedup on event id.
Webhook delivery is at-least-once, not exactly-once. Build your handler assuming any event can arrive more than once.
Retry ladder
Success is any 2xx. On anything else (non-2xx, timeout, connection error), the delivery retries on a fixed schedule:
| Attempt | Delay after the initial attempt |
|---|---|
| 1 | immediate |
| 2 | +30 seconds |
| 3 | +2 minutes |
| 4 | +10 minutes |
| 5 | +30 minutes |
| 6 | +2 hours |
| 7 | +6 hours |
| 8 | +12 hours |
Eight attempts over roughly 21 hours. No ordering guarantee across different events; each is delivered independently.
If attempt 8 still fails, the delivery is marked failed and retries stop. After that, only a manual redelivery (dashboard Redeliver, or POST /v1/webhook-deliveries/{id}/redeliver) sends it again. Manual redeliveries are flagged manual: true and show up as a fresh attempt (attempt keeps incrementing), so the delivery log is a complete history of every attempt for that event.
Dedup on event id, not delivery id
Retries and manual redeliveries of the same event carry the same socialfetch-event-id (and the same id in the envelope). That's your dedup key.
In production, a unique constraint on event_id in the table your handler writes to is usually enough — let the database reject the duplicate insert.
Endpoint health & auto-disable
- Any
2xxresets the endpoint's failure streak. - HTTP
410 Gonedisables the endpoint immediately (stop sending). - Otherwise, an endpoint auto-disables after 100 consecutive failures or 3 days of continuous failure, whichever comes first. Disabling sends an email, posts a status notice to affected monitors, and shows a dashboard banner.
Monitors keep running when an endpoint is disabled
A disabled endpoint doesn't pause attached monitors. Checks still run, still bill, and still record events — only outbound delivery stops. Events stay queryable through the pull API. Re-enabling resumes delivery for new events; old undelivered events don't replay automatically. Pull them or redeliver manually within the retention window.
Pull API: the backstop
Events are queryable independent of webhook delivery — useful if you can't host an endpoint, or want a source of truth that doesn't depend on your uptime:
Cursor-paginated, up to 100 per page, within the 30-day retention window. A monitor with no webhookEndpointId is a valid pull-only monitor: poll the event log instead of receiving pushes.
Retention
Events and delivery logs (headers, payload, response snippet, timing, attempt number) are retained for 30 days. Redelivery and the pull API stop working for older events — export anything you need longer.
Where to go next
Receiving & verifying webhooks
Verify signatures before you act on any event.
Testing webhooks locally
Watch retries and redelivery in the test inbox before you go live.
Billing for monitors
Retries don't re-bill — only the original poll charges credits.
Webhook deliveries API reference
Redelivery, delivery log filters, and cursor tailing.