Sume webhooks in a Cloudflare Worker: verify, queue, 204
A Worker that verifies a Sume delivery with verifyWebhook, hands the event to a queue with ctx.waitUntil, and replies 204 inside Sume's 10-second limit.

Verify the delivery with verifyWebhook, answer 204 right away, and hand the slow work to a queue through ctx.waitUntil. Sume gives each delivery attempt 10 seconds, retries up to 10 times 30 seconds apart, and does not follow redirects. A Worker that does its processing before it replies risks a timeout and a duplicate. The SDK helper uses WebCrypto, so it runs in a Worker without node:crypto.
What Sume expects from the receiver
The SDK page states that verifyWebhook is async, returns false instead of throwing, compares in constant time, and enforces the replay window before it computes the HMAC.
| Item | Behavior |
|---|---|
| Attempts | Up to 10, 30 seconds apart |
| Timeout | 10 seconds for each attempt |
| Redirects | Not followed |
| Expected reply | A fast 2xx |
| Dedupe key | job_id or request_id |
The Worker
The code reads the secret from the Worker environment and returns 500 if it is missing, so a deploy without the secret fails loudly instead of accepting forged calls. SUME_EVENTS is a queue producer binding that you declare in your Worker configuration. Replace the send call with any store that supports a unique key.
import { verifyWebhook } from "@sume-com/sdk";
export default {
async fetch(request, env, ctx) {
const secret = env.SUME_COM_WEBHOOK_SIGNING_SECRET;
if (!secret) return new Response("secret not configured", { status: 500 });
if (request.method !== "POST") return new Response(null, { status: 405 });
const body = await request.text(); // raw text before any JSON.parse
const ok = await verifyWebhook({ body, headers: request.headers, secret });
if (!ok) return new Response("bad signature", { status: 401 });
const event = JSON.parse(body);
const id = event.job_id ?? event.run_id ?? event.request_id;
// Answer inside the 10 second limit; do the slow work after the reply.
ctx.waitUntil(env.SUME_EVENTS.send({ event: event.event, id, body }));
return new Response(null, { status: 204 });
},
};Operational notes
Test the deployed URL with POST /v1/webhooks/test-deliveries. A 204 on the dummy webhook.test event shows the signature check, the parse and the reply all work.
- Set the secret with your platform's secret store, under the name SUME_COM_WEBHOOK_SIGNING_SECRET, the name used in the Sume docs.
- Do not call JSON.parse before you verify. Verify the raw text, then parse.
- Return 204 for event names you do not know, so a new event type does not cause retries.
- Keep polling as a backup for jobs whose terminal event never arrived.
What to store
Send the raw body along with the id, not a re-serialized object. If a later consumer needs to verify or replay the event, the original bytes are the only faithful copy. The consumer should insert with a unique key on the id, so a retried delivery that arrives while the first is still queued does not run the work twice.
For run webhooks, the receipt can be large. When it passes 1 MiB, the payload is null, the error code is payload_too_large, and a result_url tells you where to fetch the receipt.
Sources
Related posts
More in Developers
- Cloudflare Workers CPU time vs wall clock for a Sume webhook
A Sume webhook verifier on Workers spends CPU only on the HMAC and body read, not on waiting. See the limits and a WebCrypto verifier.
- Platform specs ask for bitrate and GOP: what Sume lets you set
YouTube, TikTok and Meta list bitrate, GOP and audio rates. Sume rejects codec and crf fields. Here is what you can control instead: size, fps, audio.
- Continue a 30 s shot: Video frames still as the next first frame
Extract a last-second still from a 30 s Sume clip with Video frames and send it as first_frame for the next shot. Price of the chain at 720p.
- Convert MAI-Transcribe-2 word offsets to Sume video caption words
Turn word timings in milliseconds into the seconds-based words array Sume video-captions accepts. A short Python converter plus the 60 s and 1,200-word limits.
Written by Sume