WritedocsWritedocs

API reference

Point a navigation group at an OpenAPI spec, and Writedocs writes the API reference: a page for every endpoint, grouped by tag, with its parameters, request body, responses, code examples and a Try it playground. There are no page files to write or keep up to date - change the spec, and the pages follow.

Set it up

Put the spec in your project, and give a group openapi in place of pages:

{
  "navigation": [
    "index",
    {
      "group": "API reference",
      "openapi": {
        "src": "openapi.yaml",
        "path": "/api"
      }
    }
  ]
}
src string required

The spec’s path from the project folder: an OpenAPI 3.0 or 3.1 file, in YAML or JSON.

path string required

The address the pages go under - see Page addresses. Each OpenAPI group needs its own.

renderer "writedocs" | "scalar" default: writedocs

How readers see the group: "writedocs", a page per endpoint as described on this page, or "scalar", the whole API on one page with Scalar’s API reference - see Scalar’s API reference.

This site’s Example API group, in this tab’s sidebar, is set up exactly like this - its pages are generated from a sample spec.

The spec must be a file in the project - a URL isn’t fetched. writedocs validate checks every spec in the navigation: a spec that’s missing or doesn’t parse is an error, and one that parses but isn’t valid OpenAPI is a warning.

Previewing your changes

With writedocs dev running, save the spec and the open tab reloads with the change, usually within a few seconds - no restart needed:

  • A changed summary, description, parameter, schema or example shows on the endpoint’s page; a changed summary also renames it in the sidebar.
  • An endpoint you add appears in the sidebar, under its tag, and its page is ready. One you remove or rename leaves the sidebar, and its old address shows “Page not found”.
  • An edit to a file the spec points to with $ref - a shared schema in its own file, say - counts as an edit to the spec.
  • Pointing a group’s openapi at another spec, or giving it another path, in writedocs.json regenerates the pages the same way.

While you’re typing, the spec may not parse for a moment. The terminal says where, and every page of the preview shows the same error until the spec parses again; the preview keeps running, and the pages come back on their own once it’s fixed:

✗ openapi.yaml:12:5  bad indentation of a mapping entry

A page of your own for an endpoint, added while the preview runs, takes the endpoint’s place at the next edit to the spec, or when you restart writedocs dev.

What each page shows

  • The endpoint - its method and path, title (the operation’s summary) and description. Descriptions are Markdown, as OpenAPI specifies.
  • Authorization - the security schemes the endpoint accepts.
  • Parameters - path, query and header parameters, with their type, whether they’re required, their default and description.
  • Request body - every field, with nested objects that open and close.
  • Responses - each status code, with its fields and an example.
  • Code examples - the request in several languages, ready to copy, beside the page.
  • Try it - a playground that sends a real request to your API - see Try it playground.

The page also has the Copy page menu, and its Markdown copy, llms-full.txt and the MCP server include the endpoint written out in full.

Page addresses

An endpoint’s page is served at the group’s path, then the endpoint’s first tag, then its method and path:

EndpointTagsAddress, with path: "/api"
POST /customersCustomers/api/customers/post-customers/
GET /customers/{id}Customers, Admin/api/customers/get-customers-id/
GET /healthnone/api/get-health/

To choose an endpoint’s address yourself, give it a page of its own with a slug.

In search results and link previews, the page’s description is the endpoint’s description as plain text, cut to about 160 characters - or, when it has none, its summary and request: List all customers - GET /customers.

Limits

  • allOf schemas are merged into one. For oneOf and anyOf, the page shows the first option only - describe the others in its description.

The sidebar

The group lists the endpoints under one group per tag, in the order the tags first appear in the spec. An endpoint takes its first tag; endpoints with no tag go in a group called Other. Each endpoint shows its method next to its name.

Writing a good spec

The pages are only as good as the spec. What helps most:

  • A summary for every operation - it’s the page’s title and its name in the sidebar.
  • A description for operations, parameters and fields.
  • example or examples values, for the response examples and the playground’s starting values.
  • tags, to group the endpoints.
  • servers, for the address the playground sends requests to.

Scalar’s API reference

With "renderer": "scalar", the group is one page instead of a page per endpoint: Scalar’s API reference, at the group’s path, inside your site - the top bar, tabs, footer, colors, font and light/dark theme are your site’s. The reference takes your site’s look too: its list of endpoints looks like your sidebar, and its titles, text and spacing like your other pages.

{
  "group": "API reference",
  "openapi": {
    "src": "openapi.yaml",
    "path": "/api",
    "renderer": "scalar"
  }
}

Each group chooses for itself: one API can use Scalar’s reference and another the page-per-endpoint reference, in the same site.

What the reader sees

  • One page with every endpoint, grouped by tag, with Scalar’s own list of endpoints at its side. Each endpoint has its own address on that page, like /api/#tag/customers/POST/customers, made from its first tag, method and path - it stays the same from one build to the next while those don’t change.
  • The sidebar. When the group is all there is in its part of the navigation - an API tab, say - Scalar’s list of endpoints takes the place of your sidebar. When the sidebar has other pages, the two stand side by side. On phones, your sidebar is in the site’s menu, as on every page, and Scalar’s list in a menu of its own at the top of the reference.
  • Scalar’s Try it. Every endpoint has a Test Request button that opens Scalar’s API client on it. Requests follow api.proxy: straight to your API, then through Writedocs’ proxy if the browser blocks them - never Scalar’s hosted proxy. What a reader types as credentials stays in that browser tab, and is forgotten when the tab closes.
  • A spec download button, except in a protected section.
  • Search is the site’s. Searching for an endpoint finds it, and the result opens it on the reference page. Scalar’s own search box, its AI assistant, its developer tools and its theme switch are turned off.
  • While it loads, the page shows the reference’s outline in your site’s colors: the list of endpoints, your API’s title and description as gray bars, and the Server, Authentication and Client Libraries boxes, with a soft shine passing over them (still, for readers whose system asks for less motion). The reference then takes its place, without the page moving. Screen readers hear that the reference is loading.
  • If the reference can’t load - the reader’s connection dropped, say - the page lists the endpoints instead, each linking to its page, with a Try again button.

What stays the same

Writedocs still builds the page of each endpoint described above, at its usual address, and everything that reads those pages works as for any OpenAPI group:

  • Search finds each endpoint by its title and description, and opens it on the reference page.
  • llms.txt, llms-full.txt, the MCP server and the Markdown copies have every endpoint, written out in full. The reference page’s own Markdown copy lists the endpoints, each linking to its page.
  • Links to an endpoint’s address - from your own pages, or from other sites - open the endpoint on the reference page.

Those pages aren’t listed in the sidebar or in Previous/Next links, and they tell search engines not to index them: the reference page is the one indexed, and the one in sitemap.xml. A reader whose browser has JavaScript turned off stays on the endpoint’s page, which shows everything.

Weight

The reference is drawn in the reader’s browser. Opening it downloads about 1.2 MB of compressed code the first time - the browser keeps it for later visits - and the page carries your spec. Measured on a laptop with an empty cache: with 7 endpoints, the endpoints show in about 0.4 seconds, and in about 8 seconds on a slow mobile connection; with 800 endpoints, in about 0.8 and 10 seconds - meanwhile the page shows the reference’s outline (above). A page-per-endpoint reference shows its endpoint in well under half a second either way. Choose Scalar’s reference knowing your readers’ connections.

With api.playground

api.playground picks the Try it of the page-per-endpoint references. A group with "renderer": "scalar" always uses Scalar’s client, built into its reference, whatever api.playground says; your other OpenAPI groups follow api.playground.

Limits

  • path can’t be /, and no page of your own can be at it - the reference is a page at that address. writedocs validate reports both, with the line in writedocs.json:

    ✗ 1 error in writedocs.json
    
      writedocs.json:7  (navigation.tabs.1.pages.0.openapi.path)
        writedocs.json's "Orbit API" group has openapi.renderer "scalar" and openapi.path "/" - the reference is a page at that path, so give it one of its own, like "/api".
  • A page of your own for an endpoint in this group isn’t shown: links to it open the endpoint on the reference page, and its text is still found by search and included in llms-full.txt.

  • No JavaScript, no reference. The reference page then lists the endpoints, each linking to its page.

  • In a protected section, the reference page - with your spec in it - is protected like the section’s other pages.

More