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
- 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.
- "Avatar does not have a usable TTS voice": the 400 and its fixes
Sume TTS with avatar_id or avatar_handle returns 400 when the avatar has no TTS voice, or when voice.id disagrees with it. What each message means and the fix.
- Try Avatar 1.0 in the Sume playground before you write any code
Use the Sume Avatar playground to validate an avatar or avatar video payload, then move the same body into curl, the CLI or an agent without a rewrite.
Written by Sume