app/api/persona/[...persona]/route.ts forwards every request under /api/persona/ to
runtime.handle() — the runtime owns matching, params, and 404/405 (with Allow). The adapter
adds no routes of its own.
Each HTTP method is a separate named export in Next.js, which is why the handler object is
destructured:
app/api/persona/[...persona]/route.ts
405 for that method before the runtime ever sees the request, so export all
five unless you deliberately want a method blocked.
Always-on routes (end-user scoped)
Every route except
GET /health requires an authenticated user (401 when the resolver returns
null or throws). For the exact SDK call each route proxies to, see the
Runtime routes reference.
Opt-in admin routes
The Project-level admin surface (agents CRUD, providers, skills, knowledge, stores, MCPs, audit logs, architect) is off by default — it’s gated behindcapabilities.* on the runtime. When a
capability is disabled its routes are simply absent (a request 404s or 405s, never 403). See
Runtime capabilities.
To expose the admin surface, create a second catch-all route with capabilities on and stricter
auth. toNextRouteHandlers is the primitive for that — it mounts an existing runtime rather than
creating one:
app/api/admin/persona/[...persona]/route.ts
How the adapter translates a request
The adapter maps the WebRequest a route handler receives to the runtime’s framework-neutral
contract before runtime.handle() runs. The behaviors to know:
Response translation
Error responses
- Runtime responses — including sanitized error envelopes
{"error":{code,message}}— are forwarded verbatim (status, headers, body). - Adapter translation failures (malformed JSON, unparsable multipart) respond
400 INVALID_REQUESTin the same envelope shape. runtime.handle()never throws for HTTP errors, so there is no third case to handle: anything the runtime can’t serve comes back as an error response, not an exception.
development vs
production).