OpenAPI and Scalar
One module reads the collections, globals and routes you already wrote, emits an OpenAPI 3.1 document, and serves a browsable Scalar reference beside it.
Someone wants to call your API. A partner, a colleague, an agent. This page is how you hand them the whole surface without writing a spec by hand.
It is probably already on
The starters put openApiModule in modules.ts for you. Open yours and check.
import { openApiModule } from "@questpie/openapi";
export default [openApiModule] as const;Add it if it is missing, then run questpie generate. Codegen has to see the
module before its two routes exist.
Point it at your base path
The starters mount the fetch handler at /api. The generator does not know
that. It prefixes every documented path with its own basePath, which defaults
to /. The scaffolded config/openapi.ts never sets it. So a fresh app
documents //posts, not /api/posts.
One line fixes it.
import { openApiConfig } from "@questpie/openapi";
export default openApiConfig({
info: { title: "My API", version: "1.0.0" },
basePath: "/api",
scalar: { theme: "purple" },
});openApiConfig() hands your object straight back. It exists for the types.
Codegen discovers the file, and the spec route reads it when it builds the
document. If your handler sits at the root, write basePath: "", not "/".
What you get
Two endpoints, under whatever base path your fetch handler uses.
| Endpoint | Serves |
|---|---|
GET /api/openapi.json | The OpenAPI 3.1 document, as JSON |
GET /api/docs | The Scalar reference UI, rendered from that document |
Start the app and open http://localhost:3000/api/docs. Every collection,
global and route is listed, each with a try-it panel. The page pulls Scalar
from jsDelivr, so it needs network access to render.
`/api/docs` ignores `config/openapi.ts`
Only the spec route reads that file. The Scalar route always renders the
defaults: title QUESTPIE API, theme purple, paths under /. Mount your
own docs route to get your config back. See Serving it
yourself.
What lands in the document
Five sources merge into one file.
| Source | What it contributes | Tag |
|---|---|---|
| Collections | The CRUD set, plus count, batch writes, versions and revert | Collections: <name> |
| Globals | Get, update, schema, versions and revert | Globals: <name> |
| Routes | One operation per method, typed by your Zod schemas | Routes: <segment> |
| Better Auth | Its own document, or four fallback endpoints | Auth |
| Search | POST /search and POST /search/reindex/{collection} | Search |
Every document also carries four shared component schemas and two security schemes. Generated paths lists each one.
The document is built once
/api/openapi.json builds the document on the first request and caches it for
the life of the app instance. It answers with an ETag and a one-hour
Cache-Control, and returns 304 when your If-None-Match matches. So a
change to config/openapi.ts needs a restart, not just another request.
Listing an endpoint does not open it
Both routes are ordinary QUESTPIE routes with no access rule. Anyone who can reach them can read your whole API shape. That does not make the endpoints callable. Every collection, global and route in the document is still checked against its own access rules when the call arrives.
The two security schemes say how to authenticate. They say nothing about what you are allowed to do.
A public route says so in the spec
.access(true) on a route emits security: [] on that operation. That opts
it out of the document's security scheme. A function rule, false, or no rule
at all inherits the scheme instead.
Where each topic lives
| Topic | Page |
|---|---|
| Every config option and its default | Configuration |
| The exact paths a collection, global or route emits | Generated paths |
| Mounting the routes yourself, or generating in a build step | Serving it yourself |
| Naming and tagging one operation | Route metadata |
| Who may call what the document lists | Access control |
Next
MCP is the other half. OpenAPI describes your API to whoever reads it. MCP hands the same surface to an agent as callable tools.