Next.js 16.3.8 route handler: a GET-only Sume job status proxy
A Next.js route handler that proxies only GET /v1/jobs/{id}/status to Sume, validates the id and keeps the key server-side. Written for 16.3.8.

To show Sume job progress in a browser without exposing your key, add one route handler that forwards a single read, GET /v1/jobs/{id}/status, and nothing else. The Next.js September 2026 security release, which shipped fixes in 16.3.8 and 15.5.27 (Next.js September 2026 security release, read 2026-10-04), is a good moment to write it narrowly: a proxy that forwards whatever path it is given is the kind of surface an advisory eventually describes.
The handler below validates the job id, sends exactly one credential header, and marks the response as not cacheable. Sume documents x-api-key and Bearer as equivalent, and a request carrying both is rejected with a 401 (Authentication).
Why the allowlist is the point
A catch-all proxy such as /api/sume/[...path] lets a visitor choose the upstream path, the method and sometimes the headers. Your key then authorizes whatever they pick: submits that spend credits, reads of other jobs in the workspace, key listing if the scope allows it. A fixed route with one id parameter removes those choices.
The release notes also describe a cache poisoning issue for apps that combine a root-level catch-all page with statically generated or ISR routes. If you have such a page, keep the proxy under its own path segment and do not make job status a statically generated route.
| Input | Accepted | Reason |
|---|---|---|
| Method | GET only | No submit or cancel from the browser |
| Path | /api/sume-status/[id] | Fixed upstream path, no wildcard |
| Job id | Letters, digits, dash, underscore, up to 80 | Blocks path tricks like .. and slashes |
| Credential | x-api-key from the server env | One header, never forwarded from the client |
| Caching | no-store | Status changes while a job runs |
The route handler
Save it as app/api/sume-status/[id]/route.ts. It reads the key from the server environment and fails with a 500 when it is missing, so a misconfigured deploy is loud.
const ID = /^[A-Za-z0-9_-]{1,80}$/;
export async function GET(
_req: Request,
ctx: { params: Promise<{ id: string }> },
) {
const { id } = await ctx.params;
const key = process.env.SUME_API_KEY ?? "";
if (!key) return Response.json({ error: "server not configured" }, { status: 500 });
if (!ID.test(id)) return Response.json({ error: "bad job id" }, { status: 400 });
const upstream = await fetch(`https://api.sume.com/v1/jobs/${id}/status`, {
headers: { "x-api-key": key },
cache: "no-store",
});
const body = await upstream.text();
return new Response(body, {
status: upstream.status,
headers: {
"content-type": upstream.headers.get("content-type") ?? "application/json",
"cache-control": "no-store",
},
});
}Before you ship it
- Add your own authentication so only the user who started a job can read its status. The key is workspace-wide, so the proxy is the only access check.
- Return the upstream request id to the browser or log it. The error envelope carries
request_id. - Pass the upstream status through unchanged, including 429, so your client can honour
retry-after. - Upgrade to 16.3.8 or 15.5.27 as the release notes advise.
Sources
Related posts
More in Developers
- Node 24.21 MIMEType.parse: validate a Sume artifact content type
Node 24.21.0 adds a non-throwing MIMEType.parse. Use it, with a try/catch fallback for older Node, to check a Sume artifact's content_type before saving.
- Which Node versions to test the Sume SDK on: 22, 24 and 26
Node 26.10.0 is Current, 24.21.0 and 22.23.3 are LTS. A small CI matrix and smoke test for code that calls the Sume API with fetch and WebCrypto.
- Node 26.10 fs.openAsBlobSync: upload a local file with Sume uploadFile
Node 26.10 adds fs.openAsBlobSync. Open a file as a typed Blob and pass it to the Sume SDK's uploadFile to get a durable HTTPS URL for a Format input.
- Node 26.10 SQLite binds undefined as NULL: a Sume webhook job table
Node 26.10 binds undefined as NULL in node:sqlite. A Sume job-webhook handler can still be explicit with null and dedupe on job_id without a driver.
Written by Sume