REST API reference authoring
How we maintain the hand-written REST API section, keep it aligned with OpenAPI, and avoid accidental destructive generation.
The public REST reference lives under content/docs/api/ in the docs app. Narrative copy and examples are authored manually in MDX with a fixed section layout—not <APIPage /> autogenerated wrappers. The committed apps/docs/openapi.json is the machine-readable contract and validation artifact, not the prose source of truth.
Safe workflow (default)
-
Normal docs build (
pnpm run build) runsbuild:pre, which does not re-export OpenAPI fromapps/apior rewriteopenapi.json. It uses whatever is already committed (and builds the search registry). -
When the API contract changes, update the artifact deliberately:
- From
apps/api:pnpm run openapi:export(writesapps/docs/openapi.json). CI must stay green: the exported file must match the repo (verify-openapiin GitHub Actions). - Optional: from
apps/docs, sync export + security normalization in one step:pnpm run build:pre:sync(setsDOCS_SYNC_OPENAPI=1).
- From
-
Do not run mass REST regeneration unless you actually need scaffolding updates. Safe mode only creates missing operation pages:
CONFIRM_BOOTSTRAP=1 pnpm run api:regenerate-rest-referenceAlias:
pnpm run api:bootstrap(same script; still requiresCONFIRM_BOOTSTRAP=1). To overwrite existing operation pages too, opt in explicitly:CONFIRM_BOOTSTRAP=1 BOOTSTRAP_OVERWRITE=1 pnpm run api:regenerate-rest-referenceThen edit pages for clarity: examples, edge cases, links to guides, and wording.
-
Run
pnpm lintinapps/docs—it checks OpenAPI tone rules, REST parity (every public merchant operation has a doc), required headings, internal links, and policy (no provider-ingress paths or vendor-internal identifiers in public docs/OpenAPI).
Policy: provider internals
- Inbound provider webhooks (card processor / mobile-money ingress) are not part of the public merchant API. They must not appear in
openapi.json, REST MDX, or high-level guides. Lint enforces this. - Describe merchant-facing outbound webhooks and your integration surface only.
Frontmatter (required for each operation page)
Each file must include:
| Field | Example | Notes |
|---|---|---|
title | Short human title | Mirrors OpenAPI summary initially |
description | One line | Search / meta |
method | get | Lowercase HTTP verb |
path | /accounts/{id} | Must match OpenAPI path key exactly |
operationId | AccountsController_findOne | Matches Nest operationId |
full | true | Keeps wide API layout |
Required sections (headings)
Lint enforces these headings:
## Overview, ## Authentication, ## Endpoint, ## Request, ## Responses, ## Errors, ## Example, ## OpenAPI
(French pages may use the localized heading set; see lint rules.)
What we exclude
/agent/**routes are not listed in the public REST reference (parity check skips them). Document agent APIs elsewhere if needed.
Legacy URLs
Older bookmarks used flat paths like /api/AccountsController_findAll. The app redirects those to the canonical grouped path /api/accounts/AccountsController_findAll.
Scripts reference
| Script | Role |
|---|---|
lib/scripts/pre-build.ts | Registry build; optional OpenAPI export when DOCS_SYNC_OPENAPI=1 (build:pre:sync). Does not overwrite REST MDX. |
lib/scripts/bootstrap-manual-api-reference.ts | Regenerates operation scaffolding + meta.json from openapi.json; default is missing-only (CONFIRM_BOOTSTRAP=1), full overwrite requires BOOTSTRAP_OVERWRITE=1. |
lib/scripts/manual-api/render-operation-mdx.ts | Template for one operation page |
lib/scripts/manual-api/_expected-public-operations.json | Generated list of METHOD /path strings (bootstrap output) |