Adding API documentation
How to add or change an endpoint page on this site — the spec, the URL map, and the worked example end to end.
Every page in the API Reference section is generated from openapi.json.
The playground, the code samples in seven languages, the parameter tables, the
response tabs and the TypeScript definitions all come out of that one file.
That means: to change an endpoint page, edit the spec — not the page. The
.mdx files under content/docs/api-reference/endpoint/ are build output and
are overwritten on every build.
Prose pages work differently
Pages like Introduction and Errors are hand-written MDX and you edit them directly. This guide is about endpoint pages. See Writing prose pages at the bottom.
The one rule
Never change a public URL. Merchants have integrated against these links, support tickets reference them, and search engines have indexed them.
scripts/url-map.ts maps each operationId to its URL, and generation fails
if an operation is not in that map. npm run check:urls fails if any URL
would 404 or any internal link points at nothing. Both run in the build.
If you genuinely must move a page, add a redirect in next.config.ts in the
same commit.
Worked example: adding a refunds endpoint
Say the API has gained POST /api/v1/refunds and it needs a page.
Describe the operation in openapi.json
Add the path. The operationId is the key everything else hangs off, so pick a
stable one — it is effectively the page's permanent identifier.
"/api/v1/refunds": {
"post": {
"operationId": "createRefund",
"tags": ["collections-stk"],
"summary": "Refund a collection",
"description": "Return funds to the customer who paid.\n\nRefunds are asynchronous — the response confirms the request was accepted, and the outcome arrives on your `callbackUrl`.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/RefundRequest" },
"example": { "requestId": "cd3e5b37-...", "amount": 1000 }
}
}
},
"responses": {
"201": { "description": "The refund was accepted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Refund" } } } },
"400": { "description": "The collection cannot be refunded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
"401": { "$ref": "#/components/responses/Unauthorized" }
}
}
}summary becomes the page title and the sidebar label. description renders
as the page's introduction and supports full Markdown — headings, tables,
lists, links. This is where integration guidance belongs.
Add the schemas it references
Put shared shapes in components.schemas so they can be reused and so the
generated TypeScript definitions stay clean.
"RefundRequest": {
"type": "object",
"required": ["requestId", "amount"],
"properties": {
"requestId": {
"type": "string",
"format": "uuid",
"description": "The collection to refund.",
"examples": ["cd3e5b37-8f23-465e-a720-b2a78f2b62c1"]
},
"amount": {
"type": "number",
"description": "Amount to return. Must not exceed the original collection.",
"examples": [1000]
}
}
}Reuse what already exists: TransactionStatus, CurrencyCode, Organisation,
ErrorResponse, and the RequestId / CompanyId / DeviceId parameters.
Map the operationId to a URL
export const OPERATION_SLUGS: Record<string, string> = {
// ...
createRefund: "refunds/post",
};The value is the path under content/docs/api-reference/endpoint/, so this
publishes at /api-reference/endpoint/refunds/post.
Skip this and generation stops with an explicit error. That is on purpose — a new endpoint should never quietly pick its own URL.
Put it in the sidebar
Create content/docs/api-reference/endpoint/refunds/meta.json:
{
"title": "Refunds",
"icon": "Undo2",
"pages": ["post"]
}Then reference the folder from the parent
content/docs/api-reference/endpoint/meta.json, under whichever section
heading it belongs to.
icon is any lucide name in PascalCase.
Regenerate and restart
npm run generate:docsRestart the dev server after editing the spec
The spec is parsed and cached once at startup. Hot reload will keep serving the old schema — wrong response codes, missing fields — until you restart. If a change does not show up, restart before assuming it is wrong.
Making a page genuinely useful
The difference between a page that answers questions and one that raises them is almost entirely in the spec's detail.
Describe every property
The parameter table is built from description. A property with no description
renders as a bare name and type, which tells the reader nothing they could not
guess.
Give more than one example
Named examples become a dropdown above the code samples. Use them wherever the right payload depends on context:
"examples": {
"kenya": { "summary": "Kenya (KSH)", "value": { "currencyCode": "KSH", "...": "..." } },
"tanzania":{ "summary": "Tanzania (TZS)", "value": { "currencyCode": "TZS", "...": "..." } }
}Use enum for constrained values
An enum renders as a picker in the playground instead of a free-text box, and
documents the valid set without prose.
Document conditional requirements in the description
required is for fields required in every case. When a field is only
required sometimes — as with the currency-dependent fields on payouts — put a
table in the operation description. Marking them required in the schema
would make the playground reject valid requests.
Model callbacks as callbacks
Most write endpoints confirm asynchronously. A callbacks object documents the
webhook payload as a first-class part of the endpoint, rather than a loose code
fence readers have to hunt for:
"callbacks": {
"transactionResult": {
"{$request.body#/callbackUrl}": {
"post": {
"summary": "Refund result",
"requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CollectionCallback" } } } },
"responses": { "200": { "description": "Acknowledged." } }
}
}
}
}Say what you do not know
If the source material is ambiguous, write that into the description rather than guessing. A documented uncertainty is useful; a confident wrong answer costs someone a day.
Writing prose pages
Anything that is not an endpoint is hand-written MDX under content/docs/.
The file path is the URL — content/docs/guides/refunds.mdx serves at
/guides/refunds.
---
title: Handling refunds
description: One sentence. Used in search results, social previews and the sidebar.
icon: Undo2
---A page only appears in the sidebar once a meta.json lists it, either by name
or via ....
Components available without importing
<Callout type="warn" title="Heads up">
Types: info, warn, error, success.
</Callout>CardGroup is aliased to Cards, so pages carried over from Mintlify keep
working unchanged.
Commands
| Command | What it does |
|---|---|
npm run dev | Regenerate reference pages, then start the dev server |
npm run build | Regenerate, type-check and build for production |
npm run generate:docs | Rebuild reference pages from openapi.json |
npm run check:urls | Fail if a URL would 404 or an internal link is dead |
npm run types:check | tsc --noEmit |
Before you open a pull request
-
npm run check:urlspasses -
npm run buildsucceeds - The page renders in both light and dark mode
- The playground actually sends a request and returns a response
- Every new property has a
description - Links to other docs pages are root-relative (
/api-reference/...)
