openapi(...) call in your Payload config. The docs UI is separate — add scalar() or swaggerUi() alongside it (see Docs UI):
payload.config.ts
Plugin options
Paths are relative to the API route
The plugin registers its endpoints as Payload endpoints, so everything mounts under your Payload API route (routes.api, /api by default). The specEndpoint you pass — and the path you pass to scalar()/swaggerUi() — are relative to that route. The defaults resolve to:
GET /api/openapi.json— the generated OpenAPI documentGET /api/docs— the interactive API reference
The lazy build model
openapi() does not build anything at config time. It stashes the resolved options, registers the CLI generator, and mounts the endpoints. The document itself is built per request (or per CLI run) from the fully sanitized Payload config.
That means plugin order does not matter: collections, globals, fields, and endpoints added by any other plugin are visible in the spec, whether that plugin runs before or after openapi() in your plugins array.
metadata.title and metadata.version are required. The plugin throws on boot if either is missing.Where to go next
- Metadata — title, version, description, and where the base URL comes from
- OpenAPI version — 3.2 by default, downconversion to 3.1/3.0
- Filters — choose entities and drop operations
- Security marking — public vs. secured operations
- Interactive auth — Authorize dialog in the docs UI
- Caching — when the document is rebuilt
- Extensions — add paths, components, tags, or transform the document
- Docs UI — Scalar and Swagger UI options