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.
- LinkedIn Live fails to process: use Baseline, not High or Main
LinkedIn says a Live stream that fails to process may need the Baseline H.264 profile, because High and Main add B-frames. Which a Sume render sets.
- List your failed TTS and STT jobs with the Sume jobs filters
GET /v1/jobs filters by status and type and pages 100 at a time with starting_after. A short loop to find every failed audio job.
- Sume docs for a coding assistant: llms.txt, llms-full.txt, .md
docs.sume.com serves a 73-link llms.txt index, one llms-full.txt file and any page as markdown by adding .md. Which to hand to a coding assistant, and when.
Written by Sume