Replay failed webhook deliveries
When your endpoint was down or buggy, events queue up in webhook_deliveries with status: "failed". Replay them once you've fixed the issue.
Via the dashboard
Dashboard → Webhooks → your endpoint → Deliveries — each failed delivery has a Replay button. Replay sends a fresh attempt with the original payload and a new X-Sendoka-Delivery-Id.
Via API — one delivery
curl -X POST https://www.sendoka.com/api/v1/webhooks/whk_01HN.../deliveries/whd_01HN.../replay \
-H "Authorization: Bearer $SENDOKA_API_KEY"
Via API — bulk replay
curl -X POST https://www.sendoka.com/api/v1/webhooks/whk_01HN.../replay-failed \
-H "Authorization: Bearer $SENDOKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"since": "2026-04-20T00:00:00Z"}'
since is optional — omit it to replay every failed delivery the endpoint
still has. Deliveries are not kept forever, so that is a bounded window (see
How far back you can replay).
Response:
{ "queued": 47, "endpoint_id": "whk_01HN..." }
Each queued delivery fires asynchronously. Watch the deliveries list — they flip to delivered or failed.
One call re-queues at most 100 deliveries (oldest first). If more are failed, call again once the first batch drains.
How far back you can replay
Delivery rows are deleted by a nightly sweep, counted from when the event fired:
- Failed (and still-pending) deliveries are kept for 90 days, so an outage can be replayed for up to 90 days after it. Older ones are gone and cannot be replayed; their events are not re-sent.
- Delivered deliveries are kept for 30 days, then disappear from the deliveries list too.
If you need a longer history, keep your own copy of the events you receive.
Rate limit
10/min per endpoint for manual replays (REPLAY_RATE_LIMITED on the 11th), shared by the single and the bulk replay. Prevents accidental floods after a long outage. Live and test keys each have their own 10: a test key replaying test-mode deliveries never uses up the budget a live key needs to recover the same endpoint's live backlog.
If you need to replay thousands, space the calls or contact support to raise the cap.
Test-fire synthetic events
Send a fake event to check that your endpoint is wired up correctly:
curl -X POST https://www.sendoka.com/api/v1/webhooks/whk_01HN.../test-fire \
-H "Authorization: Bearer $SENDOKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event": "message.delivered"}'
Also available from the dashboard (Webhooks → your endpoint → Send test event) or the CLI:
sendoka events trigger --endpoint whk_01HN... --event message.delivered
Payload uses fixtures with data.test: true and "environment": "test" (so X-Sendoka-Environment: test) so your handler can tell it apart from a real event; a data object in the request is merged over the fixture but cannot change either marker or the synthetic message_id. Signed with your real secret so your verification path runs end-to-end. Rate limited at 20/min per endpoint (TEST_FIRE_RATE_LIMITED), shared across API, dashboard, and CLI.
Gotchas
- Test keys replay test deliveries only. With a
sok_test_*key, both replay routes (like the delivery list) reach only deliveries whose payload says"environment": "test"; a live delivery is a404, and a bulk replay leaves live failures for a live key. Replay live events with a live key. - Replays get a new
delivery_id. Your dedup key still works, but the new id won't match any previousseen:entry — by design. - Payload is unchanged. Replay does not re-fetch the underlying message state. If the bounce was later resolved, the replay still shows the original bounce payload.
- Replays count against your 429
REPLAY_RATE_LIMITEDcap, not your regular burst limit.