docs.json reference
Every configuration field, with a working example for each.
docs.json reference
docs.json at your project root is the single source of configuration.
Add "$schema": "./docs.config.schema.json" (run fiskil schema to generate
the file) and your editor autocompletes everything below; fiskil validate
is the authority, and it runs automatically before dev, build, and
publish.
At a glance
| Key | Type | Required | Purpose |
|---|---|---|---|
name | string | — | Site name: page titles, search, social cards |
description | string | — | Site-wide meta description |
siteUrl | URL | — | Canonical origin; enables the sitemap |
ogImage | path | — | Site-wide social share image |
theme | object | Yes | Colors — the only required key |
logo | object | — | Header wordmark, light/dark |
products | array | — | Top-level product switcher |
i18n | object | — | Locales and translation behavior |
openapi | object | — | API references from OpenAPI specs |
fonts | object | — | Custom typography (Fonts) |
seo | object | — | De-indexing, structured data, meta tags (SEO) |
redirects | array | — | URL redirects (Redirects) |
errors | object | — | Custom 404 page (Custom 404) |
integrations | object | — | Analytics (PostHog) |
Unknown top-level keys are ignored rather than rejected — adding new sections in future versions is never a breaking change for your file.
name, description, siteUrl, ogImage
{
"name": "Acme",
"description": "Developer documentation for the Acme platform.",
"siteUrl": "https://docs.acme.com",
"ogImage": "/og.png"
}namefeeds the title template (Page title | Acme Docs), the generated home, andllms.txt. Defaults to "Docs".siteUrlis what makes the sitemap non-empty and absolute URLs resolvable — set it as soon as you know your domain.ogImagemust be an absolute path underpublic/.
theme
The one required key. A single color rebrands the whole site; the rest is optional refinement.
{
"theme": {
"colors": {
"primary": "#0033A9",
"light": "#4D79FF",
"dark": "#00227A",
"status": { "warning": "#B45309" },
"accents": ["#00AFCC", "#E4E729"]
}
}
}| Field | Required | What it drives |
|---|---|---|
colors.primary | Yes | Links, active states, brand moments |
colors.light | — | Dark-mode emphasis; falls back to primary |
colors.dark | — | Buttons and hover; falls back to primary |
colors.status | — | Callout palette: info, warning, error, success, idea |
colors.accents | — | Up to 4 section-accent colors, exposed to your pages as --color-accent-1..4 (plus generated soft/gradient tints) |
Colors are 3- or 6-digit hex. See Branding for how these flow into components.
logo
{
"logo": {
"light": "/logo/wordmark.svg",
"dark": "/logo/wordmark-dark.svg"
}
}Replaces the text site name in the header. Paths are under public/;
dark is optional and falls back to light. Favicons are convention, not
config — drop favicon.svg, favicon.ico, icon.png, or
apple-touch-icon.png into public/ and the tags are emitted automatically.
products
{
"products": [
{ "id": "payments", "label": "Payments API" },
{ "id": "terminals", "label": "Terminals" }
]
}Each product is a top-level content area at /{id}/... with its own section
tabs and sidebar. id is lowercase letters, digits, and hyphens; it's also
the folder name under content/docs/. A product id may not collide with a
locale code.
i18n
{
"i18n": {
"locales": ["en", "es", "pt-BR"],
"default": "en",
"fallback": "show-default-with-banner",
"localeLabels": { "pt-BR": "Português" },
"translations": { "es": { "search.placeholder": "Buscar..." } },
"searchLanguages": { "pt-BR": "portuguese" }
}
}| Field | Required | Notes |
|---|---|---|
locales | Yes (within i18n) | Locale codes like en or pt-BR |
default | Yes (within i18n) | Served unprefixed; must be in locales |
fallback | — | Untranslated pages show the default-locale content with a language banner (show-default-with-banner, the default and currently the only implemented behavior) |
localeLabels | — | Language-switcher names; unlisted locales show the uppercased code |
translations | — | Override any built-in UI string per locale |
searchLanguages | — | Search stemmer per locale, only when the ISO code isn't auto-mapped |
Content layout and workflow live in Locales.
openapi
{
"openapi": {
"apis": [
{
"product": "payments",
"label": "Payments API",
"specs": [{ "spec": "payments.json", "useFirstTagOnly": true }]
}
]
}
}Each entry in apis mounts a generated API reference at
/{product}/{section} (section defaults to api-reference). A reference is
exactly one of: flat specs, versioned versions, or grouped groups.
The full model — per-spec options, versioning, groups, sidebar sections —
has its own chapter: API docs.
seo
{
"seo": { "noindex": ["/internal", "/es"] }
}Path prefixes listed in noindex are excluded from the sitemap, disallowed
in robots.txt, and marked noindex in page metadata — one setting, all
three surfaces. Matching respects path boundaries (/es never matches
/essentials). Per-page control exists too: noindex: true in frontmatter.
More in SEO.
integrations
{
"integrations": {
"posthog": {
"apiKey": "phc_your_publishable_key",
"apiHost": "https://eu.i.posthog.com"
}
}
}Keys here are publishable client tokens — safe to commit. apiHost is
optional (defaults to PostHog US cloud). Pageviews, including client-side
navigations, are tracked automatically. Details in
Analytics.
Validation
Two layers keep the file honest:
- Editor:
fiskil schemawritesdocs.config.schema.jsonfor IntelliSense (--checkverifies it's current in CI). - Authoritative:
fiskil validateenforces everything the JSON Schema can't express — cross-references like everyopenapi.apis[].productmatching a declared product, unique version ids, one default version, and mutual exclusivity ofspecs/versions/groups.