# Multi-spec sites and overrides

## Multiple specs in one site

Any number of navigation groups can use `openapi`, each pointing at its own spec — for example, a public REST API and an internal admin API, documented in the same site:

```json
{
  "navigation": [
    "index",
    {
      "group": "REST API",
      "openapi": { "src": "rest-api.yaml", "path": "/api/rest" }
    },
    {
      "group": "Admin API",
      "openapi": { "src": "admin-api.yaml", "path": "/api/admin" }
    }
  ]
}
```

Each group's `path` is also its namespace on disk for the generated build output, so **every `openapi` group in a `writedocs.json` must use a distinct `path`** — the build fails with a clear error naming both groups if two collide.

An `openapi` group can also be nested — inside another hand-authored group, inside a tab, inside a version, at any depth — the same as an ordinary group can be. Useful for something like a tab specifically for "API Reference" that itself splits into multiple specs:

```json
{
  "navigation": {
    "tabs": [
      { "tab": "Guides", "pages": ["index"] },
      {
        "tab": "API Reference",
        "pages": [
          { "group": "REST", "openapi": { "src": "rest-api.yaml", "path": "/api/rest" } },
          { "group": "GraphQL", "openapi": { "src": "graphql-api.yaml", "path": "/api/graphql" } }
        ]
      }
    ]
  }
}
```

## Hand-written overrides

Sometimes one specific operation deserves real prose — a longer explanation, extra examples, a warning about a gotcha — while every other operation is fine auto-generated. Write the page yourself under `docs/`, and set its `openapi` frontmatter field to the exact `"METHOD /path"` the spec uses:

```mdx title="docs/api/get-pet.mdx"
---
title: Get a pet by ID
description: Retrieve a single pet's details, with troubleshooting notes for the common 404 case.
openapi: "GET /pets/{petId}"
---

This endpoint 404s if the pet was soft-deleted rather than removed outright — check the
`X-Deleted-At` response header before assuming the ID is simply wrong.
```

The build matches this page against the spec by that key. When it matches:

- **This page is served instead of the generated stub** for that one operation — your prose renders above the same Try-it playground and parameter/response reference the generated version would have had.
- **Every other operation in the spec still gets its normal generated page.**

<Callout type="note">
  Override matching is by operation key (`"METHOD /path"`), shared across every `openapi` group in the site — not scoped to one specific spec. In practice a method+path colliding across two genuinely unrelated specs mounted in the same site is rare enough this hasn't needed to be more precise.
</Callout>

Reference the page's slug in `writedocs.json`'s navigation like any other hand-written page — it doesn't need special treatment there, only the `openapi` frontmatter field on the page itself.

### Naming the spec on the page

A page can also name its spec itself, before the method - the form Mintlify uses:

```yaml
openapi: "/openapi.yaml GET /pets/{petId}"
```

The spec path is relative to the folder `writedocs.json` is in. A spec named this way doesn't need an `openapi` group in `writedocs.json`: the build reads it for the pages that name it, and each page shows its operation's playground and reference. If the same spec also has an `openapi` group, the page overrides that operation's generated page, as above.