NookDocs renders interactive API reference pages directly from your OpenAPI (or AsyncAPI) spec. Your config tells the renderer three things:
Where the spec lives (
api.openapi)Where real requests go (
api.baseUrl)How the playground authenticates (
api.auth)
Everything else — routing, try-it UI, schema flattening, code samples — the platform handles.
Quick start
{
"api": {
"baseUrl": "https://api.example.com/v1",
"openapi": "openapi.json",
"playground": "interactive",
"auth": {
"type": "bearer",
"name": "Authorization"
}
}
}Commit openapi.json to your docs base directory — the api.openapi path is relative to the base (the repo root for a single-repo project, or a subfolder for a monorepo). On next sync, every endpoint in the spec becomes a page under the navigation entries you reference via /api-reference/<tag>/<operation-id> paths (see Navigation for how to surface them in the sidebar).
Fields
api.baseUrlstringPrefixed to every endpoint path in the generated pages + playground. Omit for specs whose servers[] already carries full URLs. If both are set, api.baseUrl wins.
api.openapistring | string[]OpenAPI 3.x spec path — relative to your docs base (e.g. openapi.json) or absolute URL (https://api.example.com/openapi.json). Supports JSON and YAML. Pass an array to merge multiple specs into one reference tree.
api.asyncapistring | string[]AsyncAPI 3.x spec (channels, pub/sub, WebSocket) — same path rules as openapi. Roadmap: the key is accepted and validated today, but no pages are generated from it yet. Set it now if you want the path recorded; nothing renders until support ships.
api.playground'interactive' | 'simple' | 'none'default: "interactive""interactive"— full "Try it" with live requests againstbaseUrl. Pre-fills auth headers, shows response bodies inline, copies as curl."simple"— form-preview only, no network. Useful for APIs with destructive endpoints or private environments. Roadmap"none"— read-only docs. Skip the playground entirely; readers copy the snippet.
api.auth.type'bearer' | 'apiKey' | 'basic'Pre-fills the auth header in the playground. Omit for public APIs.
api.auth.namestringHeader name. Default Authorization for bearer + basic. Explicit for apiKey (e.g. X-API-Key, X-Api-Token).
api.proxybooleandefault: falseWhen true, playground requests route through https://<your-slug>.nookdocs.site/api/proxy/* instead of hitting your baseUrl directly. Use this when your API doesn't set CORS headers for the docs origin — browsers block the direct call; the proxy strips the CORS barrier.
Multiple specs, one reference
Large APIs often split endpoints across files (public vs admin vs webhooks). Point openapi at an array:
{
"api": {
"openapi": [
"specs/public.yaml",
"specs/admin.yaml",
"specs/webhooks.yaml"
]
}
}The platform merges them into one tree, tagged by operation. If two specs declare the same operationId, the LAST entry wins — we emit a build warning so you catch it.
Authentication in the playground
The playground reads api.auth and pre-fills the request headers:
bearer→Authorization: Bearer <token>with an input for the token.apiKey→<name>: <key>with an input for the key.basic→Authorization: Basic <base64(user:pass)>with inputs for user + pass.
The token — and path parameter values like a project id — carry over when the reader switches endpoints, so they only type them once per session. Both live only in the reader's browser (sessionStorage: cleared when the tab closes, never sent to our servers). For per-user personalized tokens, see Personalization (planned).
Navigation integration
API pages auto-slot into navigation groups that declare an openapi field. Example:
{
"navigation": [
{
"tab": "API Reference",
"groups": [
{
"group": "Projects",
"openapi": "openapi.json",
"pages": ["/api-reference/projects/list", "/api-reference/projects/create"]
}
]
}
]
}The pages can reference auto-generated paths (/api-reference/<tag>/<operation-id>) or you can skip pages and the renderer auto-fills every endpoint that matches the group's openapi filter.
See the full Navigation reference for tab-scoped OpenAPI bindings, filtering by tag, and per-version API docs.
Troubleshooting
SDK code samples
NookDocs surfaces SDK usage directly in the per-endpoint code card (the right column on every API reference page). Reader picks a language tab and sees the real client.projects.list() call instead of a raw fetch example.
Source: the x-codeSamples OpenAPI extension — a ReDoc convention that Speakeasy, Stainless, and Fern all populate automatically when they generate SDKs. You can also hand-write samples directly in your spec.
paths:
/projects:
get:
x-codeSamples:
- lang: javascript
label: Node.js
source: |
import { NookDocs } from "@nookdocs/sdk";
const client = new NookDocs({ apiKey: process.env.CODIV_API_KEY });
const projects = await client.projects.list();
- lang: python
source: |
from nookdocs import Client
client = Client(api_key=os.environ["CODIV_API_KEY"])
projects = client.projects.list()On the endpoint page the code card tab row becomes:
cURL · Node.js · SDK | Python · SDK | cURL · Python · JavaScript · PHP · Go · Java · Ruby
^ from x-codeSamples ^ auto-generated HTTP templatesTabs labeled "· SDK" come from the spec; the rest are our per-language HTTP templates as a fallback for languages the tenant didn't cover.
Supported lang values
lang | Displayed as | Prism grammar |
javascript, typescript | JavaScript / TypeScript | javascript / typescript |
node, nodejs | Node.js | javascript |
python, py | Python | python |
go, golang | Go | go |
ruby | Ruby | ruby |
php | PHP | php |
java | Java | java |
csharp, c#, dotnet | C# / .NET | csharp |
rust | Rust | rust |
swift | Swift | swift |
kotlin | Kotlin | kotlin |
bash, shell, curl | Bash / cURL | bash |
Unknown slugs pass through verbatim and use the slug itself as both label and Prism grammar.
Label disambiguation
When a single language has multiple samples for the same endpoint (e.g. separate examples for "List unwatered plants" vs "List potted plants"), set label on each entry — the tab row shows the label instead of just the language name.
No config needed
x-codeSamples lives in the OpenAPI spec itself; the nookdocs.config.json#api block doesn't need any SDK-specific keys. Push the spec with samples, next sync picks them up, tabs appear automatically.