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.

5 min readSume
All posts

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

Receiver requirements, read 2026-10-03.
RequirementSourceWhy
On-demand rendering enabledAstro guidePrerendered routes cannot read a request
prerender = false on the routeAstro guideNeeded in static mode
Public HTTPS URLSume webhooks guideSume requires it for webhook_url
Raw body before parsingSume webhooks guideSignature covers the exact bytes
Five-minute timestamp toleranceSume webhooks guideRejects 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

All Developers posts

Written by Sume