API Playground
An OpenAPI-driven API reference — one page per operation, generated at sync time, with an interactive "Try it" panel and auto-generated code samples.
An OpenAPI-driven API reference — one page per operation, generated at sync time, with an interactive "Try it" panel and auto-generated code samples.
Point Papervine at an OpenAPI (or AsyncAPI) spec and it generates a full, interactive API reference: one page per operation, request/response schema docs, runnable requests, and copy-paste code samples in several languages.
Generation, the three-pane layout, and an interactive Try it all work today. The optional server-side request proxy (for CORS and secret injection) is the maturing edge — until it lands, “Try it” sends the request straight from the browser, so it succeeds against any API that permits cross-origin calls and shows a friendly notice when one doesn’t.
The spec is referenced from your docs.json by a path relative to your
docs root — it lives in your repo alongside your MDX, and Papervine reads it through the same
content layer it uses for every page:
{
"openapi": "openapi.json"
}
Because the spec is loaded through that shared content layer — not fetched from a hardcoded location — it resolves identically whether you’re previewing locally with the CLI or viewing a synced site served from storage. Papervine accepts OpenAPI 3.0+ (YAML or JSON) and AsyncAPI.
When the site syncs, Papervine parses the spec and generates pages — one page per operation. Each operation page includes:
<ParamField>, plus a schema explorer.<ResponseField>.Because generation happens at sync time, the reference is just more pages in your site — searchable, themeable, and indexed for the AI assistant like any other content.
In the left sidebar, operations are grouped by their OpenAPI tag — each tag becomes a
collapsible nav group (its operations listed in spec order), so a large API reads as a tidy
set of sections rather than one long flat list. Operations with no tag stay as plain entries.
Each operation also gets a colored HTTP-method badge (a green GET, a blue POST, a red
DEL), so readers can scan the API surface at a glance.
An endpoint page mirrors the familiar API-reference shape:
A green Try it button sits on the endpoint bar in the center column. It opens a full-screen playground that covers every kind of input an OpenAPI operation can take, organized into collapsible sections:
bearerFormat when the spec
declares one), and an API key its header or query value. Credential values (password, token, API
key) are masked, with an eye toggle to reveal them. Whatever you enter is folded into the
request the right way (Basic base64, Bearer …, or the named header/query) at send time, and
remembered for the tab — see below. When your spec offers a choice of schemes, the reader
gets a picker — see Endpoints that accept more than one scheme.Accept header is added
automatically from what the operation produces (preferring application/json) — many APIs
reject a request or return HTML without it, and specs rarely declare Accept as a parameter.
It’s editable like any other header, and skipped if the spec already declares its own.The top bar carries an editable URL (server base + path) and an operation switcher for jumping to sibling endpoints — the playground stays open across the jump, so you can work through several endpoints without reopening it. The right half shows a live request sample — cURL, JavaScript, or Python, regenerated as you type — and, once you press Send, the response status and JSON.
An open playground is reflected in the URL as ?playground=open, which makes it linkable:
send someone …/get-user?playground=open and the page opens with the playground ready to run.
Closing it takes the parameter back off, so the link always matches what’s on screen.
“Try it” sends straight from the reader’s browser, so the API must allow cross-origin (CORS) requests for a live call to succeed; otherwise the response panel shows a friendly notice and you can copy the request sample instead. The optional request proxy is what removes that constraint.
OpenAPI’s security is a list of alternatives: each entry is one way to satisfy the endpoint,
and the keys within an entry are all required together. The two shapes mean different things, and
the playground renders them differently:
security:
- BasicAuth: []
- BearerAuth: []
For the first, the Authorization section shows a picker — BasicAuth / BearerAuth — and only
the selected scheme is sent, because two schemes would otherwise collide in a single
Authorization header. Credentials for each alternative are kept independently, so switching back
and forth doesn’t lose what you typed, and your pick is remembered across endpoints along with
the credentials themselves.
For the second, both schemes render together and both are folded into the request — which works
when they target different places (an API key header plus a bearer token, say). If both want the
Authorization header, only one value can go there: the playground flags it inline rather than
silently sending the last one. That combination can’t be expressed in a single HTTP request, so
it’s worth a second look at the spec.
An empty entry (- {}) is OpenAPI’s way to say the endpoint also works unauthenticated; it appears
in the picker as No auth — though the playground starts on the first alternative that actually
asks for a credential, so a reader with a token doesn’t send an anonymous request by default. A
requirement naming a scheme that components.securitySchemes never defines is dropped rather than
shown as an open endpoint.
Alternatives that differ only by OAuth2 scope collapse into one entry, since scopes change neither the input nor the request the playground builds.
A scheme declared under components.securitySchemes but never referenced by a security
requirement — at the root or on the operation — renders nothing. If you added a scheme and the
playground doesn’t show it, that’s the first thing to check.
Every operation is its own page, so credentials typed on one endpoint would be gone by the next one. They aren’t: the playground remembers what you entered for the rest of the browser tab, and prefills the Authorization section on every other endpoint of the same spec. A reader working through a Basic-auth API types their username and password once.
The remembered values are scoped two ways:
sessionStorage, so they’re gone when the tab closes rather than
sitting in the browser indefinitely the way a localStorage entry would. A Forget control in
the Authorization header row clears them immediately.BasicAuth on one docs site can’t prefill a same-named scheme on another — even
for two sites served from a shared origin.This is a convenience for the reader’s own credentials, which stay in their browser. It is not a way to hand readers access to your API — for that, either have your identity provider assert them (below) or keep the secret server-side with the request proxy.
A browser playground is client-side by nature: whatever a reader types is in page memory and is sent from their browser, whether or not it’s remembered. Remembering widens when it can be read, not who can read it — any script running on the docs origin could reach it either way. So prefer a scoped, revocable credential (an API key or short-lived token) over a password-equivalent one for playground use, and reach for the proxy whenever the request must carry a real secret.
For docs behind reader authentication, the signed reader payload carries an
apiPlaygroundInputs field: the path for a reader’s credentials to arrive from your identity
provider at login, so the playground is filled in before they type anything at all. The field is
accepted on the token today; prefilling the playground from it is not wired up yet.
The playground supports the auth schemes declared in your spec, configured per tenant:
Authorization header.Browsers block many cross-origin API calls. To avoid CORS failures — and to inject secrets safely without exposing them to the reader’s browser — requests can optionally route through a Papervine proxy endpoint rather than going direct. This is opt-in per tenant.
Routing through the proxy is what lets you keep API credentials server-side. When “Try it” must send a secret, prefer the proxy over a direct browser request so the key never reaches client-side code.
For every endpoint, Papervine auto-generates ready-to-run snippets so readers can leave the
page with working code. They carry the endpoint’s auth the way the spec declares it — the
Authorization header for Basic and Bearer, or the named header or query parameter for an API key
— with the credential itself shown as a placeholder, so the snippet beside the playground and the
request the playground sends agree:
curl https://api.example.com/v1/widgets \
-H "Authorization: Bearer $TOKEN"
The generation pipeline builds on established open-source tooling — openapi-types for
the spec model, Scalar as useful prior art, and
openapi-sampler for example payloads.