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://api.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://api.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 all failed deliveries for the endpoint.

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.

Rate limit

10/min per endpoint for manual replays (REPLAY_RATE_LIMITED on the 11th). Prevents accidental floods after a long outage.

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://api.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 so your handler can tell it apart from a real event. 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

  • Replays get a new delivery_id. Your dedup key still works, but the new id won't match any previous seen: 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_LIMITED cap, not your regular burst limit.