- Contributing
- Adding an API to the API Reference
Adding an API to the API Reference
The API Reference is generated automatically from OpenAPI specifications at build time. There is no hand-written page per endpoint — you add a spec, register it in one config file, and the renderer produces the landing card, overview page, one page per tag group, one page per endpoint, the schema documentation, the sidebar, and the search records for you.
Both OpenAPI 3.x and Swagger/OpenAPI 2.0 are supported, in either JSON or YAML (.json, .yaml, or .yml). Swagger 2.0 documents are converted at build time, with build warnings for anything that cannot be converted faithfully.
There are two moving parts:
| File | What it controls |
|---|---|
public/openapi/*.{json,yaml,yml} | The spec files themselves (raw or build-fetched) |
src/config/api-reference.ts | The single source of truth — which specs are shown, their slug, title, order, and product grouping |
src/config/api-sources.tsis the only site-specific file. Everything undersrc/lib/api-ref/andsrc/components/api-ref/is generic and reads from it.
Step 1 — Get the spec into public/openapi/
Section titled “Step 1 — Get the spec into public/openapi/”Pick one of the two options below.
Option A — Add a raw spec file (manual)
Section titled “Option A — Add a raw spec file (manual)”Use this when the spec is not published at a public URL, or you want to pin an exact version.
- Save the OpenAPI spec (JSON or YAML) into
public/openapi/, for example:public/openapi/my-api.json # or my-api.yaml / my-api.yml - That’s it for this step — the file is served as-is and is also what the “Download OpenAPI spec” button links to. Continue to Step 2.
Option B — Fetch the spec at build time (auto-fetch)
Section titled “Option B — Fetch the spec at build time (auto-fetch)”Use this when the spec is hosted at a public URL and you want each build to pull the latest version.
-
Open
scripts/fetch-openapi.mjsand add an entry to theSOURCESarray:const SOURCES = [// ...existing sources...{name: "My API", // log label onlyurl: "https://app.mk.io/doc/openapi_my.json", // public spec URLfile: "my-api.json", // written to public/openapi/},]; -
The fetch runs automatically in
prebuild(beforeastro build). It is safe by design:- Uses ETag / If-Modified-Since caching — unchanged specs are skipped.
- On a fetch failure, it keeps the existing file and warns, rather than breaking the build (it only hard-fails if there is no local copy at all).
- Has a 30-second timeout per request.
-
Commit the fetched
public/openapi/my-api.jsonso the site still builds if the upstream URL is ever unavailable.
Step 2 — Register the spec in the config
Section titled “Step 2 — Register the spec in the config”Open src/config/api-sources.ts and add an entry to API_SPEC_SOURCES:
export const API_SPEC_SOURCES = [ // MK.IO APIs { slug: 'media-api', title: 'Media API', file: 'media.json', product: 'MK.IO' }, { slug: 'live-api', title: 'Live API', file: 'mkio-live-api.json', product: 'MK.IO' }, { slug: 'templates-api', title: 'Templates API', file: 'mkio-templates-api.json', product: 'MK.IO' }, { slug: 'management-api', title: 'Management API', file: 'management.json', product: 'MK.IO' }, // Beam APIs { slug: 'infrastructure-api', title: 'Infra API', file: 'infra.json', product: 'MK.IO Beam' }, { slug: 'fleets-api', title: 'Fleets API', file: 'fleet.json', product: 'MK.IO Beam' }, { slug: 'channels-api', title: 'Channels API', file: 'beam-channels-api.json', product: 'MK.IO Beam' },]Each entry has five fields:
| Field | Required | What it does |
|---|---|---|
slug | yes | URL segment: the API lives at /api-reference/{slug}. Use kebab-case; must be unique. |
title | yes | The display name in the sidebar, landing-page card, and breadcrumbs. |
file | yes | The file name inside public/openapi/ (raw from Step 1A, or fetched in Step 1B). .json, .yaml, and .yml are supported. |
product | yes | The top-level section label — the small-caps heading in the sidebar, the landing-page section, and the product pill. Omit it and the API falls under a default “APIs” section. |
group | no | Optional collapsible sub-group within the product section (e.g. 'Content'). APIs sharing the same product + group collect under one expandable sidebar item. See Nesting specs under a category. |
After this, run pnpm dev (or pnpm build) and the API appears with a full set of generated pages. No other file needs to change.
Controlling how it appears
Section titled “Controlling how it appears”Sidebar title
Section titled “Sidebar title”The sidebar title is the title field in API_SPEC_SOURCES. Change it there — it updates the sidebar, the landing card, and the breadcrumb together.
Order in the sidebar and on the landing page
Section titled “Order in the sidebar and on the landing page”Both the API Reference sidebar and the landing page list APIs in the exact order of the API_SPEC_SOURCES array. To move an API up or down, move its entry in the array. Product sections appear in the order in which their first member appears.
Within a single API, endpoint groups (tags), endpoints, and schemas always follow the order defined in the OpenAPI spec — they are never re-sorted alphabetically. If the order looks wrong, fix the tags / path order in the spec itself.
The product pill and product heading
Section titled “The product pill and product heading”The product field does two things at once:
- Renders the small-caps section heading in the sidebar (e.g.
MK.IO) and the section heading on the landing page. - Renders the pill shown next to the API title (e.g. the
MK.IObadge).
To change the pill/heading text, change the product value. The value is used verbatim, so keep capitalisation consistent across entries that should share a group ('MK.IO', 'Beam', 'Platform').
Grouping many specs under one sidebar section
Section titled “Grouping many specs under one sidebar section”To group specs under one top-level section — for example, every Platform API under a single Platform section — give them all the same product value:
export const API_SPEC_SOURCES = [ { slug: 'media-api', title: 'Media API', file: 'media.json', product: 'MK.IO' }, { slug: 'live-api', title: 'Live API', file: 'mkio-live-api.json', product: 'MK.IO' },
// These three sit under one "Platform" section: { slug: 'platform-accounts', title: 'Accounts API', file: 'platform-accounts.json', product: 'Platform' }, { slug: 'platform-billing', title: 'Billing API', file: 'platform-billing.json', product: 'Platform' }, { slug: 'platform-audit', title: 'Audit API', file: 'platform-audit.json', product: 'Platform' },]All specs sharing a product value are listed under one section heading (in array order), each as its own expandable API row. It does not merge spec files into one page — if you need a single page spanning several files, merge them into one OpenAPI document before Step 1.
Nesting specs under a category within a section
Section titled “Nesting specs under a category within a section”For a large product family, add a level of nesting with the optional group field. Specs that share the same product and group collapse into one expandable category inside that product section — collapsed by default, and each spec inside still expands to its own endpoints.
For example, ~10 Platform specs organised into Content and Subscriber categories:
export const API_SPEC_SOURCES = [ // ...MK.IO entries...
// Platform → Content (one collapsible category) { slug: 'content-search', title: 'Search API', file: 'platform/content-search.yaml', product: 'Platform', group: 'Content' }, { slug: 'content-metadata', title: 'Metadata API', file: 'platform/content-metadata.yaml', product: 'Platform', group: 'Content' },
// Platform → Subscriber (another collapsible category) { slug: 'subscriber-accounts', title: 'Accounts API', file: 'platform/subscriber-accounts.yaml', product: 'Platform', group: 'Subscriber' }, { slug: 'subscriber-billing', title: 'Billing API', file: 'platform/subscriber-billing.yaml', product: 'Platform', group: 'Subscriber' },
// A Platform spec with no group sits directly under the section (not nested) { slug: 'platform-status', title: 'Status API', file: 'platform/status.yaml', product: 'Platform' },]This renders the sidebar as three levels of nesting:
PLATFORM ← product (section heading) ▸ Content ← group (collapsible category, collapsed by default) ▸ Search API ← API spec (collapsible → its endpoints) ▸ Metadata API ▸ Subscriber ← group ▸ Accounts API ▸ Billing API Status API ← ungrouped spec: a normal API row under the sectionNotes:
- Keep entries for the same
grouptogether in the array — a category appears at the position of its first member, and members are listed in array order. - A category auto-expands when it contains the page you’re currently viewing; otherwise it starts collapsed.
groupis optional and independent per entry — mixing grouped and ungrouped specs in the same product section is fine (seeStatus APIabove), so this doesn’t change how any existing single-level APIs behave.- The landing page shows the same structure: each
groupbecomes a sub-heading of its product section. - Sub-folders under
public/openapi/(e.g.platform/content-search.yaml) are fine —fileis just the path relative topublic/openapi/.
(Optional) The top-nav “API Reference” dropdown
Section titled “(Optional) The top-nav “API Reference” dropdown”The header dropdown under API Reference is a curated shortlist and is not generated from the config. If you want the new API to appear there too, add it manually to the apiItems array in src/components/nav/SiteHeader.tsx.
What you get automatically
Section titled “What you get automatically”Once registered, the API gets:
- A landing-page card at
/api-reference, grouped under its product. - An overview page at
/api-reference/{slug}with description, base URL, endpoint list, a Schemas link, and a Download OpenAPI spec button. - One page per tag group and one page per endpoint, each with parameters, request/response schemas, multi-language code samples (cURL, JavaScript, Python, Go, Java, C#), and the interactive request builder.
- Schema documentation at
/api-reference/{slug}/schemasplus one page per component schema. - Sidebar entries, search records, and a static Markdown summary at
/api-reference/{slug}.md.
Verifying your change
Section titled “Verifying your change”pnpm dev # preview locally at http://localhost:3000/api-referencepnpm test:api-ref # unit tests for the rendererpnpm build # full build; watch for [api-ref] and [openapi-fetch] warningsBuild warnings prefixed [api-ref] flag spec problems (unresolved $refs, circular schemas, unconvertible Swagger 2.0 constructs). They do not fail the build — the renderer degrades gracefully — but they tell you what a given spec does not fully support.