Webhook receiver was down: replay missed Sume job webhooks
After a receiver outage, list completed jobs and POST /v1/jobs/{job_id}/webhook/redeliver one by one. Sume has no bulk cancel-before-cutoff call.

List the jobs that finished while your receiver was down, then call POST /v1/jobs/{job_id}/webhook/redeliver for each. Redeliver is per call and works after the automatic attempts are exhausted. Sume has no single call that cancels or replays everything before a cutoff time.
Sume behavior is from Webhooks and the OpenAPI spec, read 2026-09-30. The Svix September 2026 changelog is the reason people ask: it describes cancelling pending deliveries created before a cutoff.
What happens to deliveries while the receiver is down?
Network errors and non-2xx responses are retried until attempts are exhausted: up to 10 attempts total, with a fixed delay (30s by default) and a 10s timeout per attempt. Ten refused attempts leave a failed delivery and a job that still reached its real terminal state. "Delivery is an optimization, never the only recovery path."
How do I find what I missed?
GET /v1/jobs accepts status (queued, processing, completed, failed, canceled), results are newest-first and capped at 100 per page, and data.next_cursor goes back as starting_after. Absence of next_cursor ends the loop. Compare job ids against what your receiver stored; job_id is the idempotency key.
How do I redeliver them?
Each call re-POSTs the job's real terminal event (job.completed, job.failed or job.canceled) with a fresh timestamp and signature. It needs jobs:write, and returns 409 if the job is still running or was created without a webhook_url. Redeliver does not change the destination URL.
const base = "https://api.sume.com/v1/jobs";
const headers = { Authorization: "Bearer " + process.env.SUME_API_KEY };
let cursor: string | null = null;
do {
const qs = new URLSearchParams({ status: "completed", limit: "100" });
if (cursor) qs.set("starting_after", cursor);
const res = await fetch(base + "?" + qs.toString(), { headers });
const page = await res.json();
for (const job of page.data.jobs) {
if (await alreadyStored(job.id)) continue; // your dedupe on job_id
const r = await fetch(base + "/" + job.id + "/webhook/redeliver", {
method: "POST",
headers,
});
if (r.status === 409) continue; // no webhook_url, or still running
}
cursor = page.data.next_cursor ?? null;
} while (cursor);What has no Sume equivalent?
| Need | Sume |
|---|---|
| Replay one job's terminal event | POST /v1/jobs/{job_id}/webhook/redeliver |
| Replay everything before a time | Loop the list and redeliver per job |
| Cancel pending deliveries before a cutoff | Not documented |
| Recover without webhooks | Poll status_url per job |
Should I redeliver or just poll?
If your pipeline already polls, read the results directly and skip redelivery. If downstream steps are driven by webhook handlers, redeliver so they run once, and rely on job_id dedupe so a replay of something you did receive is harmless. Mixing up redeliver with "Send test" is common; see send test vs redeliver.
Sources
Related posts
- Sume webhook not received? How to debug delivery and signatures
- Webhook send test vs redeliver: which one replays a real job?
- Webhook retry: fixed delay vs exponential backoff, with numbers
- Webhook signature mismatch: compare the secret fingerprint first
- How to cancel an AI video generation job or run with the Sume API
More in Developers
- Webhook signature mismatch: compare the secret fingerprint
Before filing a ticket for a Sume signature mismatch, compare the secret fingerprint header with the dashboard value. It is safe to paste into a ticket.
- What not to log from an AI API: keys, signed URLs, private media
Safe to log: request ids, job ids, status and sanitized media metadata. Unsafe: API keys, signed URLs, raw private media URLs and excess user content.
- webcrypto_modern_algorithms flag: verifying a Sume webhook
Sume's verifyWebhook runs on plain WebCrypto in Workers. The docs list no compatibility flag for it, so webcrypto_modern_algorithms is not a step to add.
- xAI video status done/expired vs Sume completed/failed
xAI's Grok Imagine video status values are pending, done, expired and failed. Sume uses pending, in_progress, completed, failed and cancelled. Port a poll loop.
Written by Sume