Cloudflare Queues: add a dead letter queue for Sume webhooks
Cloudflare Queues retries a message 3 times by default, then deletes it unless a dead letter queue exists. Set one up for the events Sume sends to your Worker.

If a Cloudflare Worker puts Sume webhook events on a Queue, add a dead letter queue to that consumer. By default a message is retried 3 times, and without a dead letter queue it is then deleted permanently. A dead letter queue keeps the failed messages; if no consumer reads it, they persist for 4 days, which is your window to replay them.
The Cloudflare facts are from Dead Letter Queues, read 2026-10-10. The Sume facts are from Run webhooks and Verifying webhooks.
The design goal is simple: no paid result is ever lost because a downstream step had a bad minute.
Why put a queue behind the webhook?
Sume gives a delivery 10 seconds per attempt and tries up to 10 times. A Worker that verifies the signature, writes one message and returns 2xx finishes well inside that, and Sume stops retrying. Everything slow, such as fetching the result or updating a database, happens in the queue consumer, where Cloudflare's retries apply instead of Sume's.
That split has a catch: once you return 2xx, Sume considers the event delivered. If your consumer then fails for good, nobody retries it for you unless you set up the dead letter queue.
| Layer | Retries | If it finally fails |
|---|---|---|
| Sume to your Worker | Up to 10 attempts, 10 second timeout, redirects count as failures | Redeliver with POST /v1/format-runs/{run_id}/webhook/redeliver |
| Queue to your consumer | 3 retries by default | Deleted permanently without a dead letter queue |
| Dead letter queue | Holds failed messages | Persist for 4 days if no consumer reads the queue |
What goes in the message?
Verify first, then enqueue only the identifiers: the request_id (equal to the run id), the status and the outcome. The envelope's payload is the run receipt, and it is null with payload_too_large when the receipt would pass 1 MiB, so the consumer should fetch the result from the result URL rather than trust the body.
Check the signature before the enqueue, not in the consumer. A forged event that reaches the queue costs storage and a retry cycle, and the consumer can no longer see the raw body and timestamp in the form the signature covers. Keep the headers you need, or reject early.
Dedupe on request_id. The docs say it is the stable key, since a retried delivery carries the same one. A consumer retried three times must therefore be written so a second run of the same message does nothing new.
How do I recover dead messages?
Give the dead letter queue a small consumer that logs the message to storage and alerts a person, or leave it consumerless and read it within the 4 day window. Then use the Sume redeliver endpoint, which needs the formats:write scope, to send the event again to the current webhook URL. The webhook_delivery object on the run receipt shows the URL, status and attempt count, which tells you whether Sume ever succeeded.
Test the path before you need it. Send a test delivery with POST /v1/webhooks/test-deliveries, which sends a webhook.test event signed like a real one, and confirm it travels through the Worker, the queue and the consumer. Then break the consumer on purpose and watch the message land in the dead letter queue. A recovery path you have never run is a guess.
Treat the 4 day figure as a deadline, not a store. A message you have not dealt with by then is gone, and the receipt on Sume's side is the record you fall back on.
Sources
Related posts
More in Integrations
- Workflows createBatch: 100 instances, one per Sume job?
Cloudflare Workflows now creates up to 100 instances per call. Why a 100-job Sume wave fits only on Scale, and why to pass your own instance IDs.
- Cloudflare Workflows: sleep and poll a Sume run, no open request
A Cloudflare Workflow can submit a Sume run, step.sleep for minutes, then check status again. Here are the step limits that bound how long you can poll.
- Codex default_tools_approval_mode = writes for Sume MCP
Codex sets approval per MCP server and per tool. Which of auto, prompt, writes and approve suits Sume's read and paid tools, and what output_token_limit does.
- Cursor remote MCP has no envFile: where the Sume key goes
Cursor's envFile works for stdio servers only. For Sume's remote MCP, read the key from your shell with a headers entry, or skip keys and use OAuth.
Written by Sume