Workers KV jurisdictions: keep Sume job records in region
Cloudflare made Workers KV jurisdictions generally available on Oct 2, 2026. Here is how to key Sume job_id records into a region-scoped namespace.

Yes: if you store Sume job records in Workers KV and need them kept inside a region, use a jurisdiction-scoped namespace and key each record by job_id. Cloudflare's changelog says jurisdictions for Workers KV namespaces became generally available on Oct 2, 2026.
What changed
The Cloudflare entry says that when you create a namespace you can set a jurisdiction so the namespace's data is only durably stored within that region. This post does not restate which jurisdictions exist or how to create one; read the changelog entry and the linked Cloudflare docs for that. What matters for a Sume integration is where the data you hold about a job will live.
What Sume sends you
A job webhook is a terminal event. Sume documents job.completed, job.failed and job.canceled, and the payload carries request_id, job_id, status and, on success, payload.artifacts[] with id, url, type and content_type. Media URLs point at https://media.sume.com/artifacts/....
What to store
The Sume docs tell receivers to treat job_id as the idempotency key. That is also the natural KV key. Store only what you need to answer your own users: the job id, the status, and the artifact ids and URLs.
Keep in mind that the artifact itself stays on Sume's media host. A jurisdiction on your KV namespace governs your record of the job, not where Sume stores the file. Do not describe it to your customers as moving the media.
- Key:
job:<job_id> - Value: status, artifact ids, artifact URLs, the timestamp you received the event
- Never store: your API key, your webhook signing secret, signed URLs copied into logs
Receiver sketch
Verify the signature on the raw body first, then write the record, then answer 2xx. Sume retries up to 10 times with a 10 second timeout per attempt, so answer quickly and do slow work afterwards.
async function verify(raw, headers, secret) {
if (!secret) return false;
const ts = headers.get("x-sume-webhook-timestamp") ?? "";
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret),
{ name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
const sig = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(`${ts}.${raw}`));
const hex = [...new Uint8Array(sig)].map((b) => b.toString(16).padStart(2, "0")).join("");
return (headers.get("x-sume-webhook-signature") ?? "").split(",").some((e) => e.trim() === `sume-v1=${hex}`);
}
export default {
async fetch(request, env) {
const raw = await request.text();
if (!(await verify(raw, request.headers, env.SUME_COM_WEBHOOK_SIGNING_SECRET))) {
return new Response("bad signature", { status: 401 });
}
const evt = JSON.parse(raw);
await env.JOBS.put(`job:${evt.job_id}`, JSON.stringify({
status: evt.status,
artifacts: evt.payload?.artifacts ?? [],
received_at: Date.now(),
}));
return new Response("ok");
},
};Facts at a glance
| Item | Fact | Source |
|---|---|---|
| Cloudflare change | Workers KV namespace jurisdictions generally available, Oct 2, 2026 | Cloudflare changelog |
| Sume events | job.completed, job.failed, job.canceled | Sume webhook docs |
| Idempotency key | job_id | Sume webhook docs |
| Retries | Up to 10 attempts, 10 s timeout each | Sume webhook docs |
Keep a polling fallback
Delivery is an optimization. If all ten attempts fail, the job still finished on Sume's side, so keep GET /v1/jobs/{id}/status available to fill gaps in your KV table.
Sources
Related posts
More in Developers
- LangGraph custom image: keep SUME_API_KEY out of it
langgraph-cli 0.4.32 adds an --image-uri flag for self-hosted custom containers. Inject SUME_API_KEY as a runtime env var; never bake it into the image.
- Luma callback_url or polling: which Sume job mode matches
Luma's API docs list keyframes, loop and callback_url for ray-2. On Sume the equivalent choice is job mode: async, sync up to 30 s, subscribe or webhook.
- Luma API callback_url vs Sume callback_url: signing and retries
Luma's video API takes a callback_url, and so does Sume's /v1/videos. What Sume's callback is signed with, how often it retries, and a Python verifier.
- Luma callback: 3 retries, 5 s timeout, vs Sume webhooks
Luma retries a failed callback at most 3 times with a 5-second timeout. Sume retries job webhooks up to 10 times with a 10-second timeout and signs each body.
Written by Sume