{"openapi":"3.1.0","info":{"title":"Mermaid API","version":"1.0.0-beta","description":"Mermaid API validates and renders Mermaid diagrams for programs: agents, LLM tool calls, CI pipelines and products. Two endpoints: **validate** says whether diagram code is valid and why not; **render** turns it into SVG, PNG or PDF, always with the latest Mermaid. The operations below are the contract; this guide is what they do not say by themselves. Mermaid API is part of [Mermaid](https://mermaid.ai); keys are created in the [console](https://api.mermaid.ai/console). Agents: [llms.txt](https://api.mermaid.ai/v1/llms.txt) lists every document.\n\n## Beta\n\nMermaid API is in beta. Request and response fields may be added, renamed or removed; defaults, limits and ceilings may move; the Mermaid version bumps without notice, so the same code may render differently over time. What does not change: the `/v1` prefix, the error structure, every error code once shipped, and bearer authentication. Breaking changes are announced, not versioned: each is listed in the changelog at the end of this guide with its date and what a caller must do. Every response carries `x-mermaid-api-phase: beta` until general availability. Do not build a production dependency on it yet.\n\n## Authentication\n\nEvery `/v1` call except the reference endpoints needs an API key: `Authorization: Bearer <key>`. Keys are created in the [console](https://api.mermaid.ai/console) by any Mermaid Chart user, shown once at creation, and have no expiry by default. A key is `<prefix>.<secret>`, the prefix `mmd_` and twelve hex digits; the prefix appears in listings, the secret is stored only as a hash. A refused key is 401 with `www-authenticate: Bearer` and one of `ERR_KEY_MISSING`, `ERR_KEY_UNKNOWN`, `ERR_KEY_REVOKED`, `ERR_KEY_EXPIRED`: fix the key, do not retry. The examples below take the key from `$MERMAID_API_KEY`.\n\n## Validate\n\n`POST /v1/validate`, a valid diagram:\n\n```bash\ncurl -s \"https://api.mermaid.ai/v1/validate\" \\\n  -H \"Authorization: Bearer $MERMAID_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"code\": \"flowchart TD\\n  A[Start] --> B[Done]\"}'\n```\n\n```json\n{ \"valid\": true, \"diagramType\": \"flowchart-v2\" }\n```\n\n## Render\n\n`POST /v1/render` in bytes mode, a PNG written to a file:\n\n```bash\ncurl -s \"https://api.mermaid.ai/v1/render\" \\\n  -H \"Authorization: Bearer $MERMAID_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -o diagram.png \\\n  -d '{\"code\": \"flowchart TD\\n  A[Start] --> B[Done]\", \"format\": \"png\", \"png\": {\"scale\": 2, \"background\": \"white\"}}'\n```\n\nJSON mode, an SVG with a Mermaid config:\n\n```bash\ncurl -s \"https://api.mermaid.ai/v1/render\" \\\n  -H \"Authorization: Bearer $MERMAID_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Accept: application/json\" \\\n  -d '{\"code\": \"flowchart TD\\n  A[Start] --> B[Done]\", \"format\": \"svg\", \"config\": {\"theme\": \"forest\"}}'\n```\n\n```json\n{ \"format\": \"svg\", \"contentType\": \"image/svg+xml\", \"content\": \"PHN2ZyB4bWxucz0i...\", \"diagramType\": \"flowchart-v2\", \"mermaidVersion\": \"12.0.0\", \"requestId\": \"req-3f2a9c1b7d4e\", \"cacheStatus\": \"miss\" }\n```\n\nAn invalid diagram, answered 400:\n\n```bash\ncurl -s \"https://api.mermaid.ai/v1/render\" \\\n  -H \"Authorization: Bearer $MERMAID_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"code\": \"flowchart TD\\n  A --> B\\n  C ==>> D\", \"format\": \"svg\"}'\n```\n\n```json\n{ \"error\": { \"code\": \"ERR_DIAGRAM_INVALID\", \"message\": \"Parse error on line 3:\\n...TD  A --> B  C ==>> D\\n---------------------^\\nExpecting 'AMP', 'COLON', ..., got 'TAGEND'\", \"details\": { \"name\": \"Error\", \"line\": 3, \"column\": 4 } } }\n```\n\n## Mermaid config\n\n`config` on both endpoints is the standard [Mermaid config](https://mermaid.js.org/config/schema-docs/config.html) object, any subset; omitted keys take Mermaid's defaults, so theme, look, layout and every premium theme are set as Mermaid's own documentation says. Three rules:\n\n- **Forbidden keys** are refused with 422 `ERR_REQUEST_FORBIDDEN_CONFIG` and `details.keys` naming every one: `secure`, `securityLevel`, `startOnLoad`, `suppressErrorRendering`, `dompurifyConfig`. Remove them rather than expecting a silently different render.\n- **Size keys are clamped**, not refused: `maxTextSize` to 200,000 characters and `maxEdges` to 2,000 (a value that is not a positive integer is 422 `ERR_REQUEST_INVALID`). Raise them within the ceiling for large diagrams you know are legitimate; Mermaid's own defaults apply when unset, and code longer than the effective `maxTextSize` is invalid.\n- **Directives cannot override the service**: Mermaid's protected keys are pinned by the service, so an `%%{init}%%` directive inside the diagram code cannot change them either.\n\n## Response headers\n\n| Header | On | Meaning |\n| --- | --- | --- |\n| `x-request-id` | every response | The request id; quote it when reporting a problem. A caller-supplied one (6 to 48 letters, digits, `-`, `_`, `=`) is echoed. |\n| `x-mermaid-api-phase` | every response | The release phase, `beta` during the beta. |\n| `ratelimit-policy` | every response for an accepted key | The burst limit in force, an IETF RateLimit field: `\"burst\";q=<limit>;w=<window seconds>`. Absent while the burst limit is not being enforced. |\n| `ratelimit` | every response for an accepted key | Where the call stands against it: `\"burst\";r=<remaining>;t=<seconds to reset>`. Absent with the policy. |\n| `retry-after` | 429, and a 402 the allowance's reset will cover | Seconds to wait before the next call. |\n| `www-authenticate` | 401 | `Bearer`: the scheme the endpoint takes. |\n| `content-type` | every JSON body | `application/json`. |\n\n## Render cache\n\nA render identical to a recent one is served from the render cache: same diagram code, effective Mermaid config, format, format options and Mermaid version. The cache is shared across callers and keeps a render for 24 hours; a cache hit costs the same as a miss. Beyond that bounded cache nothing of a diagram is persisted after the request: no code, no output, no config; usage records hold metadata only.\n\n## Limits\n\nEvery keyed call costs a whole number of **API credits**, some none, and spends the key owner's balance. A key belongs to a Mermaid Chart user (a personal key, spending their own balance) or to a Mermaid Chart organisation (an organisation key, spending the organisation's); the two balances are separate.\n\n- **Allowance**, per key owner across all their keys: the API credits per calendar month (UTC) the owner's Mermaid Chart plan gives, the personal allowance for a user (unless a super admin set another) and the organisation allowance for an organisation. Creating several keys does not raise it.\n- **Balance**: what remains of the allowance this month plus the owner's purchased API credits. A call is charged its cost when the service did the work: a 2xx, or a render refused for invalid diagram code. A refusal or a service failure costs nothing, and a render cache hit costs the same as a miss. The allowance pays first; once it is spent, purchased credits pay, the purchase that expires soonest first. A call whose cost exceeds the whole balance is 402 `ERR_LIMIT_BALANCE` with `cause` `balance`, `ownerType`, the allowance `remaining`, the `purchasedRemaining` and the reset in `details`; a call that costs nothing is never refused for balance. Calls in flight at the same time are charged as they finish, so together they may spend a little past the balance.\n- **Spend limit**, per key owner, set in the console: the most purchased API credits their keys may spend in a calendar month (UTC); none by default, and zero stops calls once the allowance is spent. A call that purchased credits could pay but the spend limit forbids is 402 `ERR_LIMIT_BALANCE` with `cause` `spend_limit` and `retry-after` until the first instant of next month, when the spend limit resets and the allowance refills.\n- **Burst limit**, per key: the calls per rolling minute the owner's Mermaid Chart plan gives, refused or not, unless a super admin set another for the key. Exceeding it is 429 `ERR_LIMIT_BURST` with `retry-after` the seconds until the window clears. The `ratelimit-policy` and `ratelimit` headers on every response for an accepted key say what applies and what remains, so a caller can pace itself before the first 429.\n\nWhat each Mermaid Chart plan gives:\n\n| Plan | Personal allowance per month | Organisation allowance per month | Burst per key per minute |\n| --- | --- | --- | --- |\n| Basic | 250 | 0 | 20 |\n| Plus | 2,500 | 5,000 | 60 |\n| Premium | 10,000 | 25,000 | 120 |\n| Enterprise | 25,000 | 100,000 | 300 |\n\nA change of plan reaches the limits within an hour and applies as a whole: API credits already spent this month still count, so after a downgrade the balance may be zero at once. While Mermaid Chart cannot be asked, the last plan the service knew applies, or Basic for an owner it never looked up. The numbers may change.\n\nWhat each endpoint costs now, by its call class; a super admin may change a cost or move an endpoint to another class, and this table, each operation's `x-cost` and the balance endpoint follow at once where the change was made and within about a minute everywhere else:\n\n| Endpoint | Call class | API credits |\n| --- | --- | --- |\n| `GET /v1/balance` | `free` | 0 |\n| `POST /v1/render` | `basic` | 1 |\n| `POST /v1/validate` | `basic` | 1 |\n\nThe allowance and burst defaults are service configuration and may change during the beta.\n\n`GET /v1/balance` answers the balance before a call has to be refused: `ownerType`, whose balance it is (`user` or `organisation`), the `month`, the `allowance`, what was `spent`, what `remaining`, and `resetAt`, the first instant of next month (UTC). `spendLimit` is the owner's spend limit (`null` with none), `purchasedSpent` the purchased API credits spent this month, and `autoTopUp` the owner's auto top-up setting: `enabled`, and when on the credit `pack` and the `threshold` in API credits. `purchased` gives the API credits left from purchases, `remaining`, and `soonestExpiry`, when the first of them expire (`null` with none); purchased credits last twelve months from their purchase. `costs` lists every keyed endpoint with its `method`, `path`, `callClass` and `cost` in API credits, as the table above. Asking costs nothing and is answered even when nothing remains, so an agent can check before each costly step.\n\n```bash\ncurl -s \"https://api.mermaid.ai/v1/balance\" \\\n  -H \"Authorization: Bearer $MERMAID_API_KEY\"\n```\n\n## Request size and deadlines\n\n- A request body over 1,048,576 bytes is 413 `ERR_REQUEST_TOO_LARGE`. Diagram code larger than the `maxTextSize` ceiling above is invalid before that.\n- A render gets at most 30 seconds; past that the answer is 504 `ERR_RENDER_TIMEOUT`, at the latest two seconds later. Set the caller's timeout above that.\n- Validate has no deadline of its own beyond the size limits: parsing is fast.\n\n## Errors\n\nEvery non-2xx response body is `{ \"error\": { \"code\", \"message\", \"details\"? } }`. `code` is stable and group-prefixed, `ERR_<GROUP>_<NAME>`: branch on it. `message` is for people and may change. `details` is present only where the code documents its shape. By group: `REQUEST` and `DIAGRAM` are the caller's to fix, never retry unchanged; `KEY` needs a different key; `LIMIT` as 429 means wait for `retry-after`, as 402 means the balance is spent: the allowance and purchased credits are both spent (`details.cause` `balance`), with `retry-after` only when no purchased credits are left and the month's reset will refill it, or the owner's spend limit is reached (`spend_limit`), with `retry-after` until next month; `SERVICE` and `RENDER` may pass on a retry. The same table is served as JSON at [/v1/errors.json](https://api.mermaid.ai/v1/errors.json).\n\n| Code | Status | Meaning |\n| --- | --- | --- |\n| `ERR_REQUEST_NOT_FOUND` | 404 | No endpoint at that path. Check the path against the OpenAPI document. |\n| `ERR_REQUEST_METHOD_NOT_ALLOWED` | 405 | The path exists but not for that method; the message names the methods it allows. |\n| `ERR_REQUEST_MALFORMED` | 422 | The request body is empty or not JSON. Send a JSON object. |\n| `ERR_REQUEST_INVALID` | 422 | The request body does not match the schema of the endpoint. Fix the fields the details name. Details: An array of schema issues, each with a `path` (the field) and a `message`. |\n| `ERR_REQUEST_TOO_LARGE` | 413 | The request body exceeds the size limit. Send less diagram code or config. |\n| `ERR_REQUEST_FORBIDDEN_CONFIG` | 422 | The Mermaid config sets keys the service forbids. Remove every key the details name. Details: `{ keys: string[] }`: the forbidden keys the config set. |\n| `ERR_KEY_MISSING` | 401 | No API key was presented. Send `Authorization: Bearer <key>`. |\n| `ERR_KEY_UNKNOWN` | 401 | No key with that prefix exists, or the secret is wrong. Check the key was copied whole. |\n| `ERR_KEY_REVOKED` | 401 | The key was revoked by its owner or a super admin, or because the Mermaid Chart account or organisation owning it was deleted. Create a new key in the console. |\n| `ERR_KEY_EXPIRED` | 401 | The key is past its expiry. Create a new key in the console. |\n| `ERR_IDENTITY_MISSING` | 401 | Console endpoints only: no Mermaid Chart token was forwarded. Not returned under `/v1`. |\n| `ERR_IDENTITY_INVALID` | 401 | Console endpoints only: Mermaid Chart rejected the forwarded token. Not returned under `/v1`. |\n| `ERR_IDENTITY_UNAVAILABLE` | 503 | Console endpoints only: Mermaid Chart could not be asked about the token; retry later. |\n| `ERR_OWNER_UNKNOWN` | 404 | Console endpoints only: the signed-in user has not registered as a key owner yet, is not a member of the organisation whose context was asked for, or a super admin named an owner that does not exist. |\n| `ERR_OWNER_KEY_UNKNOWN` | 404 | Console endpoints only: no key of the signed-in owner, or for a super admin no key at all, has that id. |\n| `ERR_OWNER_FORBIDDEN` | 403 | Console endpoints only: in an organisation's context, the signed-in user's organisation role does not allow the action: a viewer or a pending member changes nothing, a member changes only the organisation keys they created. |\n| `ERR_CALL_CLASS_UNKNOWN` | 404 | Console endpoints only: a super admin named a call class that does not exist. |\n| `ERR_CALL_CLASS_EXISTS` | 409 | Console endpoints only: a super admin created a call class under a name already taken. |\n| `ERR_CALL_CLASS_IN_USE` | 409 | Console endpoints only: a super admin deleted a call class an endpoint belongs to, or a route declares; it would leave that endpoint unpriced. |\n| `ERR_CALL_CLASS_ENDPOINT_UNKNOWN` | 404 | Console endpoints only: a super admin moved or reset an endpoint that is not a keyed endpoint. |\n| `ERR_LIMIT_BURST` | 429 | The key made more calls this minute than its burst limit. Wait `retry-after` seconds, then retry. |\n| `ERR_LIMIT_BALANCE` | 402 | The call costs more API credits than the key owner's balance holds across all their keys, the user's own on a personal key, the organisation's on an organisation key: what remains of the monthly allowance and of their purchased credits together, or of those purchased credits the owner's monthly spend limit still lets their keys spend. `retry-after`, when present, is the seconds until the allowance and the spend limit reset at the start of next month, UTC: always at the spend limit, and at the balance only when no purchased credits are left and the refilled allowance covers the call. Details: `{ cause: \"balance\" | \"spend_limit\", ownerType: \"user\" | \"organisation\", remaining: number, purchasedRemaining: number, resetAt: string }`: `balance` when the balance cannot pay, `spend_limit` when purchased credits could but the spend limit forbids it; whose balance, the API credits left of this month's allowance, those left of unexpired purchases, and when the allowance resets. |\n| `ERR_PAYMENT_SIGNATURE` | 400 | Stripe's webhook only: the event's Stripe signature does not verify, so nothing was credited. |\n| `ERR_PAYMENT_UNAVAILABLE` | 503 | Payments are not configured on this service, or Stripe or Mermaid Chart could not be asked for a purchase; nothing was done. Try again later. |\n| `ERR_PAYMENT_NO_PAYMENT_METHOD` | 409 | Console only: auto top-up cannot be turned on because the owner's Stripe customer has no saved card to charge; auto top-up stays off. Save a card first. |\n| `ERR_SERVICE_INTERNAL` | 500 | The service failed. Retry; if it keeps happening, report the `x-request-id`. |\n| `ERR_DIAGRAM_INVALID` | 400 | Mermaid's parser rejected the diagram code; `message` is the parser's text. On render this is the status; on validate the same object is `error` inside a 200 with `valid: false`. Fix the code. Details: `{ name: string, line?: number, column?: number }`: the error name and the 1-based position, when known. |\n| `ERR_RENDER_TIMEOUT` | 504 | The render exceeded the deadline. A retry may succeed; a simpler diagram will. |\n| `ERR_RENDER_FAILED` | 500 | The renderer failed on code the parser accepted, or could not be reached. Retry; if it keeps happening, report the `x-request-id`. |\n\n## Changelog\n\nBreaking changes to the beta contract, newest first. An entry is the date the change took effect, what changed, and what a caller must do about it; error codes are never changed or reused, only added.\n\n- **2026-09-25**: A key owner may set a spend limit, the most purchased API credits their keys may spend in a month. The 402 `ERR_LIMIT_BALANCE` details gain `details.cause`: `balance` when the balance cannot pay, `spend_limit` when purchased credits are left but the spend limit forbids spending them, with `retry-after` until the first of next month. `GET /v1/balance` gains `spendLimit` and `purchasedSpent`. What to do: Read `details.cause` on a 402: on `spend_limit`, wait for `retry-after` or ask the key owner to raise the limit; buying credits will not help.\n- **2026-09-25**: Purchased API credits are spent once the month's allowance is spent, and a 402 `ERR_LIMIT_BALANCE` comes only when both are; its `details.purchasedRemaining` says what purchases have left, and `retry-after` is sent only when none are left. In `GET /v1/balance`, `spent` now counts every API credit charged this month, purchased ones included, and `remaining` is what is left of the allowance alone, so `allowance - spent` no longer equals `remaining` once purchases have paid. What to do: Read `details.purchasedRemaining`: above zero, the call cost more than the whole balance holds. Read `remaining` and `purchased.remaining` for what is left; do not derive it from `spent`.\n- **2026-09-25**: Organisation keys: a key may belong to a Mermaid Chart organisation and spend its balance. `GET /v1/balance` and the 402 `ERR_LIMIT_BALANCE` details carry `ownerType`, `user` or `organisation`. What to do: Nothing for a personal key; on an organisation key, read `ownerType` to know whose balance a 402 names.\n- **2026-09-25**: Any Mermaid Chart user can create keys in the console; the beta access gate is gone and `ERR_OWNER_NO_BETA_ACCESS`, a console-only code, is no longer raised. What to do: Nothing for API callers; stop handling `ERR_OWNER_NO_BETA_ACCESS` if a console client did.\n- **2026-09-25**: The allowance and the default burst limit follow the key owner's Mermaid Chart plan instead of one service-wide default; Basic applies while Mermaid Chart cannot be asked. What to do: Read the allowance from `GET /v1/balance` and the burst limit from `ratelimit-policy`; do not hard-code either.\n- **2026-09-25**: The monthly quota in calls is replaced by an allowance in API credits. A call whose cost exceeds the key owner's balance is 402 `ERR_LIMIT_BALANCE`, not 429 `ERR_LIMIT_QUOTA`, which is retired. What to do: Treat 402 as the balance spent: do not retry before `details.resetAt`. A 429 still means wait.\n- **2026-09-25**: The `quota` policy left the `ratelimit` and `ratelimit-policy` headers; they carry `burst` only. What to do: Stop reading a `quota` item from the headers.\n- **2026-09-24**: Keys no longer expire by default; keys created in the beta carry into general availability unchanged. What to do: Nothing; keep the key you have.\n- **2026-09-18**: The render cache reports under `x-render-cache`, not `x-cache`, which CloudFront overwrites on the public host. What to do: Read `x-render-cache`. The JSON envelope's `cacheStatus` is unchanged.\n- **2026-09-14**: The beta contract is published: validate, render in bytes and JSON modes, the error reference. What to do: Nothing; this entry marks where the log starts.\n"},"servers":[{"url":"https://api.mermaid.ai"}],"security":[{"apiKey":[]}],"paths":{"/health":{"get":{"operationId":"getHealth","summary":"Liveness and deployed build","description":"Returns 200 while the task serves, with the git SHA and build time of the running image.","tags":["operations"],"security":[],"responses":{"200":{"description":"The service is up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}},"default":{"description":"Failure; the body is the standard error structure with a stable code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/validate":{"post":{"operationId":"postV1Validate","summary":"Validate diagram code","description":"Runs Mermaid's parser over the diagram code; nothing is rendered, so it is cheap enough for every iteration of a generation loop. The response is 200 whether the code is valid or not: `valid`, the detected diagram type, and on failure the standard error structure carrying the parser message with line and column where the parser provides them. An invalid diagram is the answer asked for, not a failure of the call, so a caller treating 4xx as failure never mistakes an answer for one. Parsing always runs at security level parseOnly. Costs 1 API credit (call class `basic`).","x-cost":1,"tags":["diagrams"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateRequest"}}}},"responses":{"200":{"description":"The validation result, valid or not","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateResult"}}}},"401":{"description":"API key missing (ERR_KEY_MISSING), unknown (ERR_KEY_UNKNOWN), revoked (ERR_KEY_REVOKED) or expired (ERR_KEY_EXPIRED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body over the size limit (ERR_REQUEST_TOO_LARGE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Request body not JSON (ERR_REQUEST_MALFORMED), not matching the schema (ERR_REQUEST_INVALID), or a Mermaid config naming a forbidden key (ERR_REQUEST_FORBIDDEN_CONFIG, `details.keys` lists them).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"default":{"description":"Failure; the body is the standard error structure with a stable code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/render":{"post":{"operationId":"postV1Render","summary":"Render diagram code to svg, png or pdf","description":"Renders the diagram code with Mermaid. By default the response body is the rendered bytes with the format's content type, for writing straight to disk; when the Accept header names `application/json` the body is an envelope with the same bytes as base64 and the metadata the headers carry, for an LLM tool call. Every answer that reached the Mermaid config, rendered or failed, carries `x-mermaid-version` and `x-render-cache` (`hit` when the render cache served it, `miss` when it was consulted, `bypass` when `cache` is false or the cache is disabled for the key); a rendered one `x-diagram-type` too. A request refused before that, for its key, a limit, or a body too large, not JSON or not the schema, carries neither. Invalid diagram code is 400 with the error object validate returns, position included, so one handler covers both endpoints; the effective config is not echoed. Costs 1 API credit (call class `basic`).","x-cost":1,"tags":["diagrams"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderRequest"}}}},"responses":{"200":{"description":"The rendered diagram: the bytes with the content type of the format, or the JSON envelope when the request accepts `application/json`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderEnvelope"}},"image/svg+xml":{"schema":{"type":"string","contentMediaType":"image/svg+xml"}},"image/png":{"schema":{"type":"string","contentMediaType":"image/png"}},"application/pdf":{"schema":{"type":"string","contentMediaType":"application/pdf"}}}},"400":{"description":"The diagram code is invalid (ERR_DIAGRAM_INVALID): `message` is the parser text, `details.name` the error name, `details.line` and `details.column` 1-based when the parser says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key missing (ERR_KEY_MISSING), unknown (ERR_KEY_UNKNOWN), revoked (ERR_KEY_REVOKED) or expired (ERR_KEY_EXPIRED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body over the size limit (ERR_REQUEST_TOO_LARGE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Request body not JSON (ERR_REQUEST_MALFORMED), not matching the schema (ERR_REQUEST_INVALID), or a Mermaid config naming a forbidden key (ERR_REQUEST_FORBIDDEN_CONFIG, `details.keys` lists them).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"The renderer failed on code it did not reject (ERR_RENDER_FAILED); retry may help.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"The render exceeded its deadline (ERR_RENDER_TIMEOUT); retry may help.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"default":{"description":"Failure; the body is the standard error structure with a stable code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/balance":{"get":{"operationId":"getV1Balance","summary":"The key owner's balance and every endpoint's cost","description":"The allowance of the key's owner for the current month, what their keys spent and what remains, when it resets, their purchased credits left, and what every keyed endpoint costs in API credits. `ownerType` says whose balance it is: the user's own on a personal key, the organisation's on an organisation key. The allowance pays first, then purchased credits, no more of them in a month than `spendLimit` less `purchasedSpent`; a call is refused with 402 when its cost exceeds `remaining` and what purchased credits may still pay together. This call costs nothing and is served whatever the balance. Costs 0 API credits (call class `free`).","x-cost":0,"tags":["usage"],"responses":{"200":{"description":"The owner's month and the endpoint costs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Balance"}}}},"401":{"description":"API key missing (ERR_KEY_MISSING), unknown (ERR_KEY_UNKNOWN), revoked (ERR_KEY_REVOKED) or expired (ERR_KEY_EXPIRED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Over the key's burst limit (ERR_LIMIT_BURST).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"default":{"description":"Failure; the body is the standard error structure with a stable code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/openapi.json":{"get":{"operationId":"getV1OpenapiJson","summary":"OpenAPI 3.1 document","description":"The machine-readable contract of this API, generated from the request schemas; its description is the guide the reference page shows.","tags":["reference"],"security":[],"responses":{"200":{"description":"The OpenAPI document"},"default":{"description":"Failure; the body is the standard error structure with a stable code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/docs":{"get":{"operationId":"getV1Docs","summary":"API reference page","description":"The OpenAPI document rendered for people: the guide, then every operation.","tags":["reference"],"security":[],"responses":{"200":{"description":"The reference page"},"default":{"description":"Failure; the body is the standard error structure with a stable code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/errors.json":{"get":{"operationId":"getV1ErrorsJson","summary":"Error reference","description":"Every stable error code with the HTTP status it comes with and what to do about it.","tags":["reference"],"security":[],"responses":{"200":{"description":"The error reference","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorReference"}}}},"default":{"description":"Failure; the body is the standard error structure with a stable code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/llms.txt":{"get":{"operationId":"getV1LlmsTxt","summary":"llms.txt","description":"Where an agent finds the OpenAPI document, the reference page and the error reference.","tags":["reference"],"security":[],"responses":{"200":{"description":"The llms.txt"},"default":{"description":"Failure; the body is the standard error structure with a stable code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","pattern":"^ERR_[A-Z]+_[A-Z_]+$","description":"Stable machine code, group-prefixed"},"message":{"type":"string","description":"Human-readable explanation; not stable, do not branch on it"},"details":{"description":"Code-specific structure, documented per code"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"Health":{"type":"object","properties":{"status":{"type":"string","const":"ok"},"version":{"type":"string","description":"Image version tag"},"sha":{"type":"string","description":"Git commit the image was built from"},"buildTime":{"type":"string","description":"When the image was built, ISO-8601 UTC"},"since":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$","description":"When this task started serving"},"now":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["status","version","sha","buildTime","since","now"],"additionalProperties":false},"ValidateResult":{"type":"object","properties":{"valid":{"type":"boolean"},"diagramType":{"description":"The detected diagram type, when detectable","type":"string"},"error":{"description":"Present when valid is false","$ref":"#/components/schemas/DiagramError"}},"required":["valid"],"additionalProperties":false},"DiagramError":{"type":"object","properties":{"code":{"type":"string","const":"ERR_DIAGRAM_INVALID"},"message":{"type":"string","description":"Mermaid's parser message; free text, not stable"},"details":{"type":"object","properties":{"name":{"type":"string","description":"The parser error's name, e.g. UnknownDiagramError"},"line":{"description":"Line the parser stopped at, 1-based, when it says","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"column":{"description":"Column the parser stopped at, 1-based, when it says","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["name"],"additionalProperties":false}},"required":["code","message","details"],"additionalProperties":false},"ValidateRequest":{"type":"object","properties":{"code":{"type":"string","minLength":1,"description":"Diagram code"},"config":{"description":"The standard Mermaid config object, any subset; omitted keys take Mermaid defaults","$ref":"#/components/schemas/MermaidConfig"}},"required":["code"]},"MermaidConfig":{"type":"object","properties":{"maxTextSize":{"description":"Clamped to the service ceiling","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"maxEdges":{"description":"Clamped to the service ceiling","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"additionalProperties":{}},"RenderEnvelope":{"type":"object","properties":{"format":{"type":"string","enum":["svg","png","pdf"]},"contentType":{"type":"string","description":"Content type of the decoded content"},"content":{"type":"string","format":"base64","contentEncoding":"base64","pattern":"^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$","description":"The rendered bytes, base64"},"diagramType":{"type":"string","description":"The detected diagram type"},"mermaidVersion":{"type":"string","description":"The Mermaid version that rendered it"},"requestId":{"type":"string","description":"The request id, as in the x-request-id header"},"cacheStatus":{"type":"string","enum":["hit","miss","bypass"],"description":"Whether the render cache served it, as in x-render-cache"}},"required":["format","contentType","content","diagramType","mermaidVersion","requestId","cacheStatus"],"additionalProperties":false},"RenderRequest":{"type":"object","properties":{"code":{"type":"string","minLength":1,"description":"Diagram code"},"format":{"type":"string","enum":["svg","png","pdf"],"description":"Output format"},"config":{"description":"The standard Mermaid config object, any subset; omitted keys take Mermaid defaults","$ref":"#/components/schemas/MermaidConfig"},"png":{"description":"Format options for png; ignored for other formats","$ref":"#/components/schemas/PngOptions"},"pdf":{"description":"Format options for pdf; ignored for other formats","$ref":"#/components/schemas/PdfOptions"},"cache":{"default":true,"description":"false: this render is neither served from nor stored in the render cache; the cache is also off for a key when a super admin disabled it, whatever this says","type":"boolean"}},"required":["code","format"]},"PngOptions":{"type":"object","properties":{"scale":{"default":2,"description":"Device pixels per CSS pixel; lowered when the image would exceed the service ceiling","type":"number","minimum":0.5,"maximum":4},"background":{"default":"white","description":"CSS colour behind the diagram, or transparent","type":"string","pattern":"^(transparent|[a-z]{3,20}|#[0-9a-f]{3,8}|(rgb|hsl)a?\\([0-9.,\\s%]+\\))$"}}},"PdfOptions":{"type":"object","properties":{"fit":{"default":true,"description":"true: the page is the size of the diagram; false: one A4 page, the diagram scaled down to fit","type":"boolean"}}},"Balance":{"type":"object","properties":{"ownerType":{"type":"string","enum":["user","organisation"],"description":"Whose balance: the key owner's own on a personal key, the organisation's on an organisation key"},"month":{"type":"string","description":"The current calendar month, YYYY-MM, UTC"},"allowance":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The owner's API credits per month across all their keys"},"spent":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The API credits charged to all the owner's keys this month, purchased ones included"},"remaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"What is left of the allowance, never below zero; purchased credits are apart"},"resetAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$","description":"When the allowance resets: the first instant of next month, UTC"},"purchasedSpent":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The purchased API credits charged to the owner's keys this month"},"spendLimit":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}],"description":"The most purchased API credits the keys may spend in a calendar month, UTC; null, no limit"},"autoTopUp":{"oneOf":[{"type":"object","properties":{"enabled":{"type":"boolean","const":true},"pack":{"type":"integer","minimum":1000,"maximum":1000000,"multipleOf":1000,"description":"The credit pack bought, in API credits"},"threshold":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"The balance in API credits under which the pack is bought"}},"required":["enabled","pack","threshold"],"additionalProperties":false},{"type":"object","properties":{"enabled":{"type":"boolean","const":false}},"required":["enabled"],"additionalProperties":false}],"description":"The owner's auto top-up: on, with its pack and threshold, or off"},"purchased":{"description":"The owner's purchased API credits, each purchase valid twelve months","$ref":"#/components/schemas/PurchasedCredits"},"costs":{"type":"array","items":{"$ref":"#/components/schemas/EndpointCost"},"description":"Every keyed endpoint, this one included"}},"required":["ownerType","month","allowance","spent","remaining","resetAt","purchasedSpent","spendLimit","autoTopUp","purchased","costs"],"additionalProperties":false},"PurchasedCredits":{"type":"object","properties":{"remaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"API credits left from purchases that have not expired"},"soonestExpiry":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},{"type":"null"}],"description":"When the first of those credits expire; null when there are none"}},"required":["remaining","soonestExpiry"],"additionalProperties":false},"EndpointCost":{"type":"object","properties":{"method":{"type":"string"},"path":{"type":"string"},"callClass":{"type":"string","description":"The call class the endpoint is metered as"},"cost":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"API credits a call is charged when the service does the work; 0 is free"}},"required":["method","path","callClass","cost"],"additionalProperties":false},"ErrorReference":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","description":"The stable code, as in the error body"},"status":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The HTTP status the code comes with"},"meaning":{"type":"string","description":"What went wrong and what to do about it"},"details":{"description":"The shape of `details`, when the code carries one","type":"string"}},"required":["code","status","meaning"],"additionalProperties":false}}},"required":["errors"],"additionalProperties":false}},"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"An API key, as issued: shown once at creation."}}}}