API Reference Pages

An API reference in Leed is a documentation set whose pages are generated from an OpenAPI spec rather than written. It gets the same navigation, the same URLs, the same theming and the same search as any other set — what differs is where its content comes from, and that nobody edits it by hand.

What an API set is

An API set is a page type whose Type of Page is API Documentation. Everything the rest of this category describes applies to it unchanged: it has exactly one bound left menu, its folder names set its URLs, and links to its pages are page references that survive a move. What a Documentation Set Is is the shared model, and Page Types covers the record itself.

Two things are specific to it:

  • The pages are generated. They are produced from your spec on your machine, reviewed locally, and then uploaded into the CMS.
  • The set is Content Locked, permanently. Editing a generated page in the CMS is refused with API pages are generated from a spec and can’t be edited in the CMS. This is not the Content Locked checkbox you can toggle on any other page type — for an API set it is enforced by the backend regardless of the stored flag, and there is no role that lifts it. The Content Locked toggle on the page type panel shows as on and cannot be turned off.

Versioning by page type

An API set’s path may nest and carry a version — docs/api/3.7.0 — and every page of the set lives under it. A new version is a new set: create a second page type at docs/api/3.8.0, import into it, and both versions stay live at their own URLs with their own navigation. Page ids are scoped by page type, so the same spec can be imported into both sets without the two colliding.

Two versions can share a display name, because only the path carries the version. That is why retiring one makes you type the path rather than the name (see Retiring a set).

Building the set: four steps

The flow is four steps, in order. Create the page type in the CMS — the Create Page Type dialog offers API Documentation — or from the CLI with leed settings pagetype create --type api; either way the new set gets its own left menu and a search index. There is no CMS control that imports pages, so the remaining steps are CLI-only.

StepCommandWhat it producesWhat it checks first
1. Create the setleed settings pagetype create --type api, or the CMSA page type in the CMS with its bound left menuThat you are signed in
2. Stageleed import openapi <spec>Pages and a menu staged into your checkout under src/<path>/, plus a manifest recording what was stagedThat the spec is a readable .json, .yaml or .yml, and within the size cap
3. Build and reviewleed site buildA local render of the pages you are about to uploadNothing — this step exists so you look
4. Applyleed import applyPages in the CMS, merged into the set’s menu, and the spec staged for commitThe two guards below
leed settings pagetype create --type api --name "Public API" --slug docs/api/3.7.0
leed import openapi ./openapi.yaml --page-type-id <pageTypeId> --page-type-path docs/api/3.7.0
leed site build --serve
leed import status --page-type-id <pageTypeId>
leed import apply --page-type-id <pageTypeId>

The first staging run needs --page-type-path, because nothing in your checkout records the new set’s path yet; an explicit --page-type-path always wins. leed import status shows what is staged, how many of those pages the CMS already holds, and anything that would block apply. To abandon a staged set instead, run leed import clean.

flowchart TD
    Spec[OpenAPI spec on disk] --> Create["leed settings pagetype create<br/>(page type in the CMS)"]
    Create --> Stage["leed import openapi<br/>staged pages + manifest"]
    Stage --> Build["leed site build<br/>you review the real output"]
    Build --> G1{"Spec unchanged<br/>since staging?"}
    G1 -- No --> R1["Re-run leed import openapi, then build"]
    G1 -- Yes --> G2{"A recorded build<br/>newer than the staging?"}
    G2 -- No --> R2["Run leed site build<br/>(builds run with -d are not recorded)"]
    G2 -- Yes --> Apply["leed import apply"]
    Apply --> CMS["Pages in the CMS<br/>+ menu + staged spec files"]
    CMS --> Publish["Publish the set"]
    R1 --> Stage
    R2 --> Build

The two guards before import

Apply refuses unless both hold, and each says which one failed.

  • The spec must be the one you staged from. Its checksum is recorded at staging time and re-checked at apply. If the file moved or changed, you get The OpenAPI spec changed or is missing since you staged it. — because the upload is re-derived from the file on disk, and a changed file would upload pages nobody reviewed.
  • A build must have happened since you staged. Otherwise: Build and review the generated set before importing., naming when the last recorded build actually was. This guard is the whole reason the flow has a review step rather than being one command.

What apply does

Apply first checks the whole set against the CMS without writing anything — an id held by another page, a page the menu references zero times or twice, a page whose path disagrees with its menu position — and if anything fails, refuses the set with every violation listed and nothing created. Then it uploads the pages in batches of at most twenty, and reports every page individually.

OutcomeMeaningSafe to re-run?
ImportedThe page was created, or the body of an unpublished draft was replaced from the specYes — the manifest records it
SkippedThe page exists and may not be written — it has been published, holds pending suggestions, or has moved — so nothing was changedYes
FailedThat page could not be written; the reason is reported per pageYes — a re-run retries only what is outstanding

It ends on a summary in the form Import summary: X imported, Y skipped, Z failed (of N)., plus whether the menu was applied. Apply never overwrites a published page. Page ids are derived from the page type, the operation and its version, so re-importing a spec addresses the same pages: an unpublished page has its body replaced, and a published one is skipped and left exactly as it is. Only the body is ever replaced — title, slug and folder stay as the CMS holds them. Run leed import status first to see how many of the staged pages the CMS already holds.

On a partial failure the manifest and the staged files stay in place so the re-run can resume, and the command names the manifest path. On full success it removes the staged files and the manifest, because the CMS is now authoritative.

Where the spec itself goes

The source spec is uploaded and staged, not committed on its own. It rides along into the site repository with the pages when they publish, so the spec and the pages it produced always land together. Files above 25 MB are refused.

What a reader gets on an endpoint page

An endpoint page renders in two columns. The main column carries the operation itself:

  • Security — the schemes the operation accepts, with their scopes
  • Parameters, grouped by where they go: path, query, header and cookie
  • Request body, with a selector when the operation accepts more than one content type
  • Responses, with a selector for the status code and content type, each showing the schema and an example

The side column carries the code samples for the same operation, as a tab strip.

A generated endpoint page with its sidebar, parameter sections and code sample column

Everything else on the page — breadcrumbs, previous and next, the sidebar, search — is the ordinary documentation reading experience, described at Documentation Reading Experience. An API page has no on-page table of contents; its mini bar shows breadcrumbs instead.

To add your own content above an API page’s Previous and Next links — a feedback prompt, a support link — create _includes/api-page-cta.hbs in your site. It is picked up automatically on every plan, and it is separate from _includes/docs-page-cta.hbs, which does the same for written documentation pages. On an API page it renders twice, once for the wide layout and once for the narrow one, and both copies are visible unless your partial hides one.

Code sample languages

Samples are generated in four languages — cURL, TypeScript, Python and Go — and rendered through the reserved API Languages tab group, which supplies each tab’s display title and icon.

Two constraints are worth knowing before you touch that group:

  • It is created and repaired for you. Leed creates it if it is missing and fills in any icon that has gone absent. It is also the one tab group hidden from the editor’s tab-group menu, because it is not a general-purpose language group — for a hand-written page, make a group of your own. Tab Groups for Consistent Examples is the page for that.
  • Do not rename or trim it. Its entries are matched to the generated tabs by name. Remove or rename one and that tab still renders — as a bare label with no icon, because the lookup no longer finds it.

The menu is generated with the pages: a folder per resource group, holding a Methods folder with that group’s endpoints, and — when the group has named subgroups — a Resource folder with one folder per subgroup, each holding its own Methods folder. Endpoints are sorted by name. Apply merges the generated menu into the set’s bound menu rather than replacing it, reusing folders that already match. Each endpoint leaf carries an icon that encodes its HTTP method — that is what renders the method badge in the sidebar, and it is also how a reader’s AI client reads the method back out of your navigation.

The Documentation tree for an API set, with method-badged endpoint leaves

The rest of the menu behaves exactly as it does for a written set, including the folder-name-to-URL rule — see Folders Set Your URLs before you reorganize one.

Retiring a set

Settings → Page Types is the only entry point, deliberately: this destroys a whole set rather than acting on one page, so it lives with the set’s settings and nowhere else.

ArtifactRemoved?Recoverable?
Every page in the setYesNo
The committed OpenAPI spec filesYesNo
The set’s navigation menuNo — it is kept as an ordinary menu, its entries for the deleted pages are removed, and it is renamed with an “(unbound)” suffix if it carries the set’s nameDelete it yourself if you no longer need it
The set’s live URLsThey stop resolving at the next deploymentOnly by rebuilding the set
The delete-API-set confirmation dialog with the typed-confirmation field

Where the command detail lives

This page owns the product model. Every flag on every command in the flow, with its defaults and its failure messages, is at OpenAPI Commands, and the workflow written from the CLI’s side — including what to do when a guard refuses — is at Importing an OpenAPI Spec. None of it works until the CLI is installed and signed in: Installing the Leed CLI.

Once the set is live, your readers’ AI clients can query it directly, method and all — Docs MCP Tool Reference covers the tools that read an API set.

ESC