Models
The Models page is the deployment catalogue: one row per provider serving a
model. The same claude-sonnet-4 reached through Anthropic and through Bedrock
is two rows, and the difference between their prices is the entire input to
least-cost routing.
Two things follow from that, and they govern the rest of this page:
- The catalogue is maintained at deployment level. Every mutation —
create, update, delete, bulk update — requires deployment scope. An
organization administrator holding
models:updatestill cannot rewrite what every other organization sees. - A scope chooses from the catalogue; it never edits it. Whether one organization or department may use a given model is a separate record, set through scope overrides.
The list
| Column | What it shows |
|---|---|
| Model | The model ID sent to the provider verbatim, with the display name beneath it |
| Provider | Which provider serves this copy |
| Can do | Declared capabilities, first three then a count |
| Context | Context window, with the output ceiling beneath it |
| Rate, per 1M tokens | Input plus output added together, with each half beneath |
| State | Routable or Off, plus a Free tier tag where set |
Filter by provider, by capability (Can do), and by state. The search box matches model ID and display name.
Only Model and State are sortable. The server sorts on modelId and
enabled and silently falls back to modelId for anything else, so context
window and price are deliberately not offered — clicking them would reorder the
twenty-five rows on screen and imply the several hundred behind them had moved
too.
The four figures above the list
Counted across the whole catalogue rather than the page on screen, so they do not move when a filter changes:
- In the catalogue — total rows, and how many providers they span.
- Routable — rows with
enabled: true. - No price set — routable rows with neither token rate recorded. This one is worth watching; see Pricing below.
- Served by more than one — models available from two or more providers, which is where a routing decision is worth money.
Same model, different price
Above the table, a comparison of every model the catalogue holds more than once, widest price gap first. Nowhere else in the console shows this, because a provider’s own Models tab only ever shows one side of it. Rows with no rate on either side are left out: a spread against zero is not a saving, it is a model nobody has priced.
The scan reads up to ten pages of 100. If the catalogue is larger it says how much it compared rather than paging on in the background.
Adding a model
Add a model opens a drawer.
| Field | Required | Notes |
|---|---|---|
| Provider | Yes | Cannot be changed afterwards. The same model under two providers is two rows, and comparing them is the point. |
| Model ID | Yes | Exactly what the provider’s API expects. Sent verbatim; routing rules match on this string. |
| Display name | No | Shown beside the ID. Changes nothing about routing. |
| Capabilities | Yes | At least one. See below. |
| Context window | Yes | Total tokens accepted, prompt and reply together. |
| Maximum output tokens | Yes | The server refuses a text-generating model saved without it. |
| Input, per 1M tokens | — | USD per million input tokens. |
| Output, per 1M tokens | — | USD per million output tokens. |
| Per image | — | Shown only when the model declares image-generation. |
| Per minute of audio | — | Shown only when the model declares an audio capability. |
| Counts towards the provider’s free tier | — | Feeds free-tier-first routing. Optional per-day request and token limits appear when it is on. |
| Routable | — | On by default. |
Context window and Maximum output tokens are enforced as positive numbers
only for models that generate text — those declaring chat or
completions. An embedding, rerank, image or speech model may legitimately
record zero for both, because neither describes anything it does.
The per-image and per-minute fields
They appear conditionally, on the capabilities you have ticked. That is not
cosmetic: an image model registered with no perImage rate, or a transcription
model with no perMinuteAudio rate, is unpriced in the only unit it is billed
in. Least-cost then ranks it as free — see below.
Capabilities
Twenty-six values, and the picker offers exactly the set the server accepts.
Anything outside it is rejected by validation on write and matches nothing when
sent as ?capability=.
| Wire value | Label |
|---|---|
chat | Chat |
completions | Text completion |
embeddings | Embeddings |
audio-transcription | Speech to text |
audio-translation | Speech translation |
audio-tts | Text to speech |
text-to-speech | Text to speech (older spelling) |
image-generation | Image generation |
image-analysis | Image analysis |
video-generation | Video generation |
rerank | Rerank |
function-calling | Tool calling |
streaming | Streaming |
json-mode | JSON mode |
vision | Vision |
batch | Batch |
prompt-caching | Prompt caching |
realtime | Realtime |
reasoning | Reasoning |
ocr | OCR |
fine-tuning | Fine-tuning |
speech-to-speech | Speech to speech |
music-generation | Music generation |
computer-use | Computer use |
code-execution | Code execution |
search-grounding | Search grounding |
Capabilities describe the model and drive the filter on this page. Routing does not read them. A rule sends its capability to whatever provider and model the route names, whether or not the model claims to support it — so a wrong tag misfiles a row rather than misrouting a request.
Pricing
Every rate is USD per million tokens. That is the storage unit, the unit the shipped catalogue uses, and the unit least-cost adds up.
Least-cost ranks on inputPerMillionTokens + outputPerMillionTokens. Both are
always written, including an explicit 0 — a zero is a statement (“this model
is free”), and omitting the key on an update would leave the previous rate in
place while the form showed a cleared field. The three optional rates
(perRequest, perImage, perMinuteAudio) are only sent when set, so a chat
model does not acquire a perImage: 0 for least-cost to reason about.
An unpriced model is not neutral
Least-cost reads (input ?? 0) + (output ?? 0). A catalogue row that exists with
no pricing therefore scores zero and is preferred over every priced
alternative. A model with no catalogue row at all scores infinity and is tried
last.
The two look identical in a list and behave as opposites, which is why the No price set figure is called out above the table and why unpriced rows are flagged in the price column.
Editing a model
Click a row to open it. Everything except the provider can be changed.
PUT /api/admin/models/:id picks its fields explicitly to block mass
assignment, and does not read providerConfigId — a model cannot be moved
between providers. Delete it here and add it under the other provider instead.
An update is a sparse patch: keys you do not send are left alone. The text-budget rule is re-checked against the result of the patch rather than the patch alone, so a context window cannot be zeroed after the fact, and a row stored before the rule existed stays editable for anything unrelated to it.
Switching models on and off
enabled is a boolean, shown as Routable or Off. There is no
deprecated state and no lifecycle beyond those two values.
- Routable — rules naming this model can send traffic to it.
- Off — every rule naming this model skips this provider. Requests fall through to the next entry in the chain; where it was the only route, they fall to the fallback chain or fail.
The Switch on / Switch off buttons above the table run
POST /api/admin/models/bulk-update, which issues a single updateMany against
the current filter with no paging. The count on the button and in the
confirmation is every matching row, not the page on screen.
Deleting a model
Delete removes the catalogue row permanently.
A request naming that model stops reaching that provider and falls through to the next in the chain, and least-cost drops the provider to last place. A routing rule addressed by its slug still sends the model ID to the provider verbatim, so that path keeps working — but with no price behind it, which means least-cost now scores it as free.
What a scope can change
Nothing on this page is per-organization. An organization or department decides
which catalogue models it may use through model overrides, a separate record
holding a scope, a model and a boolean — absent means inherit, false withdraws
a model the deployment offers, true takes one the deployment left off.
There is no per-scope pricing. A rate is a property of the model at the provider, so it belongs on the catalogue entry once.
See Scope Overrides for the endpoints and the cascade.
Endpoints
| Method | Path | Scope |
|---|---|---|
GET | /api/admin/models | models:read |
POST | /api/admin/models | models:create + deployment scope |
PUT | /api/admin/models/:id | models:update + deployment scope |
DELETE | /api/admin/models/:id | models:delete + deployment scope |
POST | /api/admin/models/bulk-update | models:update + deployment scope |
GET accepts page, limit (capped at 100), sort, order,
providerConfigId, capability, enabled and search.
bulk-update accepts either an explicit ids array or a filter
(providerConfigId, capability, enabled, search), and an update object
limited to enabled and isFreeTier. It returns matched and modified.