Skip to content

The API

An OpenAI-compatible HTTP server. The /v1 routes sit behind the API key when one is set; the Playground’s static pages and the API reference at /v1 do not.

Endpoint Method Notes
/v1/models GET The servable models: data[0] the loaded one (active: true; the speech model, when it can serve, comes right after it as kind: "speech", and the top-level speech object says whether it can and why not, and in its diarizer member the same of the diarizer — Speech to text) — for a text model with the context it runs (max_model_len), the requests it decodes at once (decode_lanes) and the steps its load took to fit the card’s VRAM (adapted, "" when none; when a profile does not fit) — then every model a request naming it would switch to and be served by now — each catalog entry on disk, each known model whose artifact is a file; the loaded one alone with --switch-allow-implicit false. A catalog entry on disk above the card’s class is listed available: false, with the reason (the catalog). And status, about data[0]: serving, switching, failed (Switching models), unloaded or loading (idle unload).
/v1/models/switch POST Replace the loaded model on the running process (Switching models).
/v1/models/catalog GET Every model the server can switch to or fetch, with its state on disk (Switching models).
/v1/models/download POST Download a catalog entry in the background while the server serves; the catalog’s rows follow it (Downloading from the Server view).
/v1/models/download/cancel POST Stop the running download, keeping its partial files for the entry’s next download to resume (Cancelling and resuming).
/v1/models/remove POST Delete a catalog entry’s files, finished or partial, from the models folder; never the model loaded, loading or being downloaded (Removing a model).
/v1/images/generations POST Generate images with the image model (Image generation).
/v1/images/edits POST Edit images from 1 to 10 condition images, multipart (Image generation).
/v1/audio/transcriptions POST Transcribe audio with the speech model, multipart (Speech to text). Served on the CPU through a model switch.
/v1/realtime?intent=transcription GET A live transcription session over a WebSocket, OpenAI’s Realtime transcription subset (Live transcription). Served on the CPU through a model switch.
/v1/config GET, PATCH The running configuration, and a change to it (configuration).
/v1/config/fields GET What each visible configuration field is: kind, default, rule, families, whether a change reloads.
/v1/config/origins GET Where each visible value in force comes from, shared and per model family: default, profile, file, env, flag or live.
/v1/chat/completions POST Chat completions — streaming (stream: true, SSE) and non-streaming.
/v1/responses POST The OpenAI Responses API, streaming (stream: true, SSE) and non-streaming (The Responses API).
/v1/responses GET Its WebSocket mode: the upgrade, then response.create events (The Responses API).
/v1/tokenize POST A body’s prompt-token count without serving it (Counting a prompt).
/v1/detokenize POST Token ids back to text, through the same tokenizer.
/v1/decide POST The decision endpoint (Decisions).
/v1/systemone POST The same handler on the System One API’s own route (Decisions).
/v1 GET The API reference — a 307 to /v1/docs/ (ADR 0036).
/v1/docs/ GET Swagger UI over the document, from assets compiled into the binary: no CDN, nothing fetched. Open even with an API key set — it publishes the API’s shape, not its load — and Authorize is how you drive the keyed routes from the page.
/v1/openapi.json GET The OpenAPI 3.1 document, generated from the handlers themselves. Monitoring is not in it.
/ui/ GET The Playground — unless --server-ui false.
/ui/metrics GET Prometheus text format 0.0.4 for the Playground — with the Playground, unless --server-metrics false. Behind the API key, like /v1.

Every /v1 route answers a CORS preflight. Prometheus itself scrapes GET /metrics on the metrics listener (--server-metrics-bind), not on the API’s address: no key, and never reachable through --server-expose.

Request body limits, enforced before JSON parsing: 16 MiB on a text-only load, 384 MiB with --vision-enabled, which takes images inline as base64 data URIs. Both are past what their own load can use, so an oversized prompt meets the refusal that names the real limit — the context — rather than a byte count.

Errors use OpenAI’s {"error": {message, type, code}} body with the matching status: 400 bad request, 404 unknown model, 413 oversized request, 503 engine full, 504 a request past its deadline that is answered an error (deadlines).

A full engine (every lane in use) answers 503 with type and code engine_full and a Retry-After, on /v1/chat/completions and on HTTP /v1/responses alike. Over HTTP nothing waits: the client’s retry is the admission. The header is an estimate of when a lane frees: the oldest request in flight plus how long requests have been holding a lane (a running average of the ones that finished, were cancelled or stopped, each moving it 1/8 of the way). It is whole seconds rounded up, clamped to 1..59, plus a one-second margin, so 2 to 60 (60 being the most the OpenAI SDK honours). Once that time has passed the oldest request is overdue, and a lane is expected one average hold after the refusal instead, at most 15 s (so 2 to 16): the average has already proved wrong for that request, and a client that polls sooner leaves a freed lane idle for less. It is 1 before any request has finished. Only the Responses API’s WebSocket mode queues a request instead. A request that stops being waited for gives its lane back at once, whether it hit its deadline or its client went away.