Astro API route for Sume webhooks: export const prerender = false
An Astro endpoint can receive Sume job webhooks if it is rendered on demand. Set prerender false, read the raw body, and verify the sume-v1 signature.

A static Astro site cannot receive a webhook, because a prerendered file has no request to read. The Astro endpoints guide says an endpoint exports handlers such as POST, typed with APIRoute, that request is a full Request object and that responses are new Response(...). In static mode the route needs export const prerender = false, and on-demand rendering must be enabled for the project, read 2026-10-03.
The receiver
Create src/pages/hooks/sume.ts. Read the raw text first because Sume's signature covers {timestamp}.{raw_body}, as the Sume webhooks guide describes. Reuse the verifier from the SvelteKit post, which accepts any sume-v1= entry in a comma-separated header and refuses an empty secret.
The handler below assumes that function lives in src/lib/verify.ts.
import type { APIRoute } from "astro";
import { verify } from "../../lib/verify";
export const prerender = false;
export const POST: APIRoute = async ({ request }) => {
const raw = await request.text();
const ok = verify(
raw,
request.headers.get("x-sume-webhook-timestamp"),
request.headers.get("x-sume-webhook-signature"),
process.env.SUME_WEBHOOK_SECRET
);
if (!ok) return new Response("bad signature", { status: 401 });
const event = JSON.parse(raw);
return new Response("ok");
};Checklist before you register the URL
| Requirement | Source | Why |
|---|---|---|
| On-demand rendering enabled | Astro guide | Prerendered routes cannot read a request |
prerender = false on the route | Astro guide | Needed in static mode |
| Public HTTPS URL | Sume webhooks guide | Sume requires it for webhook_url |
| Raw body before parsing | Sume webhooks guide | Signature covers the exact bytes |
| Five-minute timestamp tolerance | Sume webhooks guide | Rejects replays |
Handling the event
Events are terminal: job.completed, job.failed, job.canceled. Acknowledge fast, dedupe on the job id, and fetch the result with GET /v1/jobs/:id/result once result_ready is true. The result route returns 409 job_not_completed before the job is done, so a webhook that arrives before your own poll is not a problem.
If your host environment does not expose process.env to server routes, read the secret with the adapter's own mechanism; the Astro page does not cover secrets, so check your adapter's docs.
Sources
Related posts
More in Developers
- Async, webhook or sync: pick a Sume communication mode by job length
Use sync only for jobs that finish inside its 30 second cap, such as many images. Use async plus polling or webhook for video, and keep polling as the backup.
- attachment_too_large 413: 30 MB per image, 500 MB per run
A Format run 413 attachment_too_large means one image is over 30 MB or the set is over 500 MB. It is a different 413 from payload_too_large (4 MiB body).
- Audio detach in sync mode: 30 seconds, then a 202 you poll
Audio detach defaults to async. With mode sync it waits up to 30 seconds for a 200, or returns 202 to poll. Why a timeout is not a failure and how to retry.
- Audio detach file size: 16 kHz mono WAV vs 48 kHz stereo
A 900-second Sume audio detach is about 29 MB as 16 kHz mono WAV, 173 MB as 48 kHz stereo WAV and 14 MB as 128 kbps MP3. The arithmetic and choices.
Written by Sume