# Models & catalog

The catalog is one flat namespace of model ids. Every **chat** model in it is
callable through both wire surfaces — OpenAI-compatible `/v1/chat/completions`
and Anthropic-compatible `/v1/messages` — with one key; the gateway translates.
Image models answer on `POST /v1/images/generations` only, and decision models on
`POST /v1/decisions` only.
Pricing is pass-through: the per-token rates in the catalog are what you pay,
and every billed response carries `usage.cost` so you can recompute the bill
from the wire.

There are four ways to read the catalog:

| Surface | URL | Auth | For |
|---|---|---|---|
| Model directory | `https://dev.routerplus.com/` | none | Browsing, filters, featured model order |
| Per-model pages | `https://dev.routerplus.com/models/<id>` | none | Providers with prices, latency, uptime and data policy; copy-paste snippets |
| Machine-readable JSON | `https://dev.routerplus.com/api/models.json` | none | Scripts, dashboards, price checks |
| SDK-shaped list | `https://dev-api.routerplus.com/v1/models` | API key | `client.models.list()` — see [GET /v1/models](/docs/api-models) |

## Model ids

Ids are exact strings. There is no fuzzy matching and no silent substitution: a
request for an id that is not in the catalog is a 404 that echoes the id you
sent (see [GET /v1/models](/docs/api-models)). The catalog as of this writing —
the live list is always [`/api/models.json`](https://dev.routerplus.com/api/models.json):

| Model id | Providers | Context | Input /1M | Cached /1M | Cache write /1M | Output /1M |
|---|---|---|---|---|---|---|
| `claude-opus-5-5` | anthropic, deepinfra-labs, inference-net-chat | 1M | $4 | $0.2 | $5 | $20 |
| `claude-fable-5-1` | anthropic | 1M | $10 | $0.25 | $12.5 | $50 |
| `claude-sonnet-5-5` | anthropic, deepinfra-labs | 1M | $2 | $0.1 | $2.5 | $10 |
| `claude-haiku-5-5` | anthropic | 1M | $0.1 | $0.01 | $0.125 | $0.5 |
| `gpt-6-astra` | openai, inference-net-chat | 1.05M | $10 | $1 | $12.5 | $50 |
| `gpt-6.1-sol` | openai | 1.05M | $2 | $0.1 | $2.5 | $10 |
| `gpt-6-luna` | openai, inference-net-chat | 1.05M | $0.1 | $0.01 | $0.125 | $0.5 |
| `gpt-5.6-terra` | openai, inference-net-chat | 1.05M | $2 | $0.2 | $2.5 | $12 |
| `gpt-6-sol` | openai | 1.05M | $2 | $0.2 | $2.5 | $10 |
| `gpt-5.6-sol` | openai, inference-net-chat | 1.05M | $4 | $0.4 | $5 | $20 |
| `gpt-5.6-luna` | openai, inference-net-chat | 1.05M | $0.2 | $0.02 | $0.25 | $1.2 |
| `claude-sonnet-5` | anthropic | 1M | $2 | $0.2 | $2.5 | $10 |
| `claude-opus-5` | anthropic, deepinfra-labs, inference-net-chat | 1M | $5 | $0.5 | $6.25 | $25 |
| `claude-fable-5` | anthropic, deepinfra-labs, inference-net-chat | 1M | $10 | $1 | $12.5 | $50 |
| `claude-sonnet-4-5` | anthropic | 200K | $3 | $0.3 | $3.75 | $15 |
| `claude-haiku-4-5` | anthropic, deepinfra-labs, inference-net-chat | 200K | $1 | $0.1 | $1.25 | $5 |
| `gpt-4o-mini` | openai, inference-net-chat | 128K | $0.15 | $0.075 | – | $0.6 |
| `gpt-4.1-mini` | openai, inference-net-chat | 1.05M | $0.4 | $0.1 | – | $1.6 |
| `gpt-4o` | openai, inference-net-chat | 128K | $2.5 | $1.25 | – | $10 |
| `deepseek/deepseek-v4.1-flash` | morphllm, deepinfra-chat, nebius-chat, novita-chat, inference-net-chat, runinfra-chat, sail-research-chat, doubleword-chat | 1.05M | $0.3 | $0.006 | – | $1.2 |
| `tencent/hy4-preview` | deepinfra-chat, novita-chat | 1.05M | $0.834 | $0.042 | – | $2.501 |
| `z-ai/glm-5.3-flash` | morphllm, deepinfra-chat, nebius-chat, novita-chat, inference-net-chat, runinfra-chat, sail-research-chat, doubleword-chat | 1.05M | $0.15 | $0.015 | – | $0.5 |
| `z-ai/glm-5.3` | morphllm, deepinfra-chat, mistral-ai, nebius-chat, novita-chat, inference-net-chat, runinfra-chat, sail-research-chat, doubleword-chat | 1.05M | $1.4 | $0.06 | – | $4.4 |
| `deepseek/deepseek-v4-flash-0731` | sail-research-chat, deepinfra-chat, nebius-chat, streamlake, chutes-chat, inference-net-chat, doubleword-chat | 1.05M | $0.14 | $0.015 | – | $0.28 |
| `moonshotai/kimi-k3` | chutes-chat, sail-research-chat, morphllm, deepinfra-chat, nebius-chat, novita-chat, inference-net-chat, doubleword-chat | 1.05M | $3 | $0.285 | – | $15 |
| `z-ai/glm-5.2` | chutes-chat, inference-net-chat, morphllm, deepinfra-chat, novita-chat, streamlake, doubleword-chat | 1.05M | $1.4 | $0.26 | – | $4.4 |
| `minimax/minimax-m3` | deepinfra-chat, nebius-chat | 524K | $0.3 | $0.056 | – | $1.2 |
| `deepseek/deepseek-v4-pro` | deepinfra-chat, novita-chat, inference-net-chat | 1.05M | $1.6 | $0.135 | – | $3.2 |
| `deepseek/deepseek-v4-pro-0813` | deepinfra-chat, nebius-chat, novita-chat, sail-research-chat, doubleword-chat | 1.05M | $1.32 | $0.1 | – | $3.96 |
| `google/gemma-4-31b-it` | deepinfra-chat, novita-chat, sail-research-chat, doubleword-chat | 262K | $0.2 | – | – | $0.4 |
| `qwen/qwen3.6-27b` | chutes-chat, deepinfra-chat, streamlake | 262K | $0.32 | – | – | $3.2 |
| `xiaomi/mimo-v2.6-pro` | deepinfra-chat, novita-chat | 1.05M | $0.435 | $0.0036 | – | $0.87 |
| `xiaomi/mimo-v2.6-flash` | deepinfra-chat, novita-chat | 1.05M | $0.14 | $0.0028 | – | $0.28 |
| `tencent/hy3` | novita-chat | 262K | $0.14 | $0.035 | – | $0.58 |
| `claude-opus-4-8` | deepinfra-labs, inference-net-chat | 1M | $5 | – | – | $25 |
| `claude-opus-4-7` | deepinfra-labs, inference-net-chat | 1M | $5 | – | – | $25 |
| `claude-sonnet-4-6` | deepinfra-labs, inference-net-chat | 1M | $3 | – | – | $15 |
| `google/gemini-3.7-flash` | deepinfra-labs, inference-net-chat | 1M | $0.75 | – | – | $3.75 |
| `google/gemini-3.5-flash` | deepinfra-labs, inference-net-chat | 1M | $1.5 | – | – | $9 |
| `google/gemini-3.1-pro` | deepinfra-labs | 1M | $2 | – | – | $12 |
| `google/gemini-3.1-flash-lite` | deepinfra-labs, inference-net-chat | 1M | $0.25 | – | – | $1.5 |
| `google/gemini-2.5-pro` | deepinfra-labs, inference-net-chat | 1M | $1.25 | – | – | $10 |
| `google/gemini-2.5-flash` | deepinfra-labs, inference-net-chat | 1M | $0.3 | – | – | $2.5 |
| `openai/gpt-oss-120b` | deepinfra-chat, sail-research-chat | 131K | $0.037 | – | – | $0.17 |
| `openai/gpt-oss-20b` | deepinfra-chat | 131K | $0.03 | – | – | $0.14 |
| `morph/morph-v3-fast` | morphllm | 262K | $0.8 | – | – | $1.2 |
| `morph/morph-v3-large` | morphllm | 262K | $0.9 | – | – | $1.9 |
| `morph/kimi-k3-fast` | morphllm | 1.05M | $6 | $0.6 | – | $22.5 |
| `mistral-large-4` | mistral-ai | 1.05M | $1.36 | $0.14 | – | $4.18 |
| `mistral-medium-2604` | mistral-ai | 262K | $1.5 | $1.5 | – | $7.5 |
| `mistral-small-2603` | mistral-ai | 262K | $0.15 | $0.15 | – | $0.6 |
| `mistral-large-2512` | mistral-ai | 262K | $0.5 | $0.5 | – | $1.5 |
| `ministral-14b-2512` | mistral-ai | 262K | $0.2 | $0.2 | – | $0.2 |
| `ministral-8b-2512` | mistral-ai | 262K | $0.15 | $0.15 | – | $0.15 |
| `ministral-3b-2512` | mistral-ai | 131K | $0.1 | $0.1 | – | $0.1 |
| `codestral-2508` | mistral-ai | 256K | $0.3 | $0.3 | – | $0.9 |
| `qwen/qwen3.5-397b-a17b` | chutes-chat, nebius-chat, streamlake | 262K | $0.6 | $0.6 | – | $3.6 |
| `qwen/qwen3-235b-a22b-2507` | nebius-chat | 262K | $0.2 | $0.2 | – | $0.6 |
| `qwen/qwen3.8-27b` | runinfra-chat, chutes-chat, nebius-chat, streamlake, doubleword-chat | 262K | $0.45 | $0.45 | – | $3 |
| `nvidia/nemotron-3-ultra-550b-a55b` | nebius-chat, doubleword-chat | 1.05M | $1 | $1 | – | $3 |
| `nvidia/nemotron-3.5-lightning` | nebius-chat, runinfra-chat | 1.05M | $0.06 | $0.06 | – | $0.24 |
| `moonshotai/kimi-k2.6` | chutes-chat, nebius-chat, streamlake, sail-research-chat, inference-net-chat | 262K | $0.95 | $0.95 | – | $4 |
| `claude-opus-4-6` | inference-net-chat | 1M | $5 | $0.5 | – | $25 |
| `deepseek/deepseek-v4-flash` | inference-net-chat | 1M | $0.23 | $0.0028 | – | $0.62 |
| `google/gemini-2.5-flash-lite` | inference-net-chat | 1.05M | $0.1 | $0.01 | – | $0.4 |
| `google/gemini-3-flash-preview` | inference-net-chat | 1.05M | $0.5 | $0.05 | – | $3 |
| `google/gemini-3.1-pro-preview` | inference-net-chat | 1.05M | $2 | $0.2 | – | $12 |
| `google/gemini-3.5-flash-lite` | inference-net-chat | 1.05M | $0.3 | $0.03 | – | $2.5 |
| `google/gemini-3.6-flash` | inference-net-chat | 1.05M | $1.5 | $0.15 | – | $7.5 |
| `google/gemma-3-4b-it` | inference-net-chat | 131K | $0.05 | – | – | $0.1 |
| `z-ai/glm-5` | inference-net-chat | 205K | $0.95 | $0.2 | – | $2.55 |
| `z-ai/glm-5.2-fast` | inference-net-chat | 1M | $2.6 | $0.4 | – | $8.8 |
| `gpt-4.1` | inference-net-chat | 1.05M | $2 | $0.5 | – | $8 |
| `gpt-4.1-nano` | inference-net-chat | 1.05M | $0.1 | $0.025 | – | $0.4 |
| `gpt-5-mini` | inference-net-chat | 400K | $0.25 | $0.025 | – | $2 |
| `gpt-5-nano` | inference-net-chat | 400K | $0.05 | $0.005 | – | $0.4 |
| `gpt-5.4` | inference-net-chat | 1.05M | $2.5 | $0.25 | – | $15 |
| `gpt-5.5` | inference-net-chat | 1.05M | $5 | $0.5 | – | $30 |
| `x-ai/grok-4.5` | inference-net-chat | 500K | $2 | $0.3 | – | $6 |
| `x-ai/grok-4.6` | inference-net-chat | 500K | $2 | $0.5 | – | $6 |
| `moonshotai/kimi-k2.5` | inference-net-chat | 262K | $0.8 | $0.13 | – | $3.95 |
| `moonshotai/kimi-k3-fast` | inference-net-chat | 1.05M | $4.5 | $0.45 | – | $22.5 |
| `meta-llama/llama-3.2-1b-instruct` | inference-net-chat | 60K | $0.027 | – | – | $0.201 |
| `meta-llama/llama-3.2-3b-instruct` | inference-net-chat | 131K | $0.05 | – | – | $0.33 |
| `meta-llama/llama-3.3-70b-instruct` | inference-net-chat | 131K | $0.13 | – | – | $0.4 |
| `nvidia/nemotron-3-super-120b-a12b` | inference-net-chat | 262K | $0.102 | – | – | $0.48 |
| `qwen/qwen3-14b` | inference-net-chat | 131K | $0.2275 | – | – | $0.91 |
| `qwen/qwen3-30b-a3b` | inference-net-chat | 41K | $0.12 | – | – | $0.5 |
| `qwen/qwen3.7-plus` | inference-net-chat | 1M | $0.4 | $0.08 | – | $1.6 |
| `inference-net/schematron-v2-small` | inference-net-chat | 128K | $0.05 | $0.05 | – | $0.23 |
| `inference-net/schematron-v2-turbo` | inference-net-chat | 128K | $0.03 | $0.03 | – | $0.15 |
| `stepfun/step-5-preview` | inference-net-chat | 1.05M | $1 | $0.05 | – | $2.7 |
| `deepseek/deepseek-v4.1-flash-1017` | runinfra-chat, sail-research-chat, doubleword-chat | 1.05M | $0.15 | $0.01 | – | $0.6 |
| `ornith-ai/ornith-1.5-122b` | runinfra-chat | 262K | $0.26 | $0.07 | – | $2.08 |
| `ornith-ai/ornith-1.5-35b-a3b` | runinfra-chat | 262K | $0.1 | $0.01 | – | $0.4 |
| `google/gemma-4-31b-it-nvfp4` | chutes-chat, sail-research-chat | 262K | $0.14 | $0.07 | – | $0.4 |
| `google/gemma-4-12b-it` | sail-research-chat | 16K | $0.3 | $0.15 | – | $2 |
| `deepseek/deepseek-v3.2` | chutes-chat | 131K | $1 | $0.1 | – | $1 |
| `z-ai/glm-5.1` | chutes-chat | 203K | $0.9 | $0.09 | – | $2.9 |
| `qwen/qwen3-vl-235b-a22b-instruct` | doubleword-chat | 262K | $0.21 | $0.1155 | $0.2625 | $1.9 |
| `qwen/qwen3.5-35b-a3b-dottxt` | doubleword-chat | 262K | $0.35 | $0.19999 | $0.4375 | $1.2 |

Where a model lists two providers, the first is tried first: the Claude models are served by
Anthropic directly, and DeepInfra (`deepinfra-labs`) serves them only when Anthropic fails before
the first byte, at the same price.
The five open models Morph and DeepInfra both serve go to Morph first and to DeepInfra only
when Morph fails before the first byte. Both bill the same price: per token type, the lower of
the two providers' list prices. GLM 5.3 has a third route, Mistral, after both, at that same
price.
On the models Chutes (`chutes-chat`) serves, the providers are listed in their default order,
cheapest first: Chutes is tried first on Gemma 4 31B NVFP4, Kimi K2.6, Kimi K3, Qwen3.5 397B
A17B, Qwen3.6 27B and GLM 5.2. A request routed there is billed Chutes's own price, which on those
six is below the row's list price. On DeepSeek V4 Flash 0731 Chutes is dearer than the row and
fifth, after `streamlake` at the same price. [`/api/models.json`](https://dev.routerplus.com/api/models.json) shows each provider's price.

`google/gemma-4-31b-it-nvfp4` is Gemma 4 31B in NVFP4, NVIDIA's 4-bit floating-point format: the
same weights as `google/gemma-4-31b-it`, quantized to fp4, so it is listed apart from them. Its
262K context is the largest of its routes. Chutes, tried first, holds 131,072 tokens; a longer
prompt goes to `sail-research-chat`, which holds 262,144.

The first eleven lead the Models page and the playground in this order. OpenAI's seven
GPT-6 and GPT-5.6 models are called on OpenAI's Responses API, where they take function
tools and custom (free-form) tools; you still call them on either chat surface, or on
[POST /v1/responses](/docs/api-responses). On these seven, `stop`, `n`, `seed`, `logprobs`,
`logit_bias` and the penalties are dropped on the chat surfaces, and an output limit under
16 tokens is sent as 16.

The Claude 5 models (Opus, Fable, Sonnet and Haiku) and OpenAI's GPT-6 and GPT-5.6 models
take only their default sampling: their providers refuse `temperature` other than 1, and
any `top_p` or `top_k`, with a 400. The gateway leaves these out for those models on every
route. Each drop is named in `x-tm-dropped-params`, except `temperature: 1` and `top_p: 1`,
which change nothing. Under `require_parameters` a drop is a 400 instead.

OpenAI bills a prompt over 272K input tokens at twice the input and 1.5 times the output
rate, and Anthropic bills a Claude Haiku 5.5 prompt over 100K tokens at five times its rate;
the catalog lists the base rate.

A model or mix you deploy from [Optimize](/docs/model-search) gets an id of its
own, `tm/<name>-v<n>`. It is callable on `POST /v1/chat/completions` with a key of
the organization that owns it, and it is not listed in the catalog.

### Fast Apply (code merge)

`morph/morph-v3-fast` and `morph/morph-v3-large` merge an edit into a file. They are chat
models on `POST /v1/chat/completions`, but they answer one kind of message: a single user
message holding the instruction, the original file and the edit, each in its own tag. The
edit may skip unchanged lines with `// ... existing code ...` (or `# ...` in Python). The
reply's `content` is the whole merged file.

```bash
curl https://dev-api.routerplus.com/v1/chat/completions \
  -H "Authorization: Bearer $TM_API_KEY" -H "content-type: application/json" \
  -d '{"model":"morph/morph-v3-fast",
       "messages":[{"role":"user","content":"<instruction>Add an optional third number</instruction>\n<code>def total(a, b):\n    return a + b</code>\n<update>def total(a, b, c=0):\n    # ... existing code ...\n    return a + b + c</update>"}]}'
```

### Image models

Image models bill in tokens like everything else, but they answer on
[POST /v1/images/generations](/docs/api-images) and nowhere else. The per-image
ceiling is the most output tokens one image can bill; the reservation holds `n`
times it.

| Model id | Sizes | Qualities | Per-image ceiling | Text in /1M | Image out /1M |
|---|---|---|---|---|---|
| `gpt-image-1` | `1024x1024 · 1536x1024 · 1024x1536` | `low · medium · high` | 6,240 | $5 | $40 |
| `gpt-image-1-mini` | `1024x1024 · 1536x1024 · 1024x1536` | `low · medium · high` | 6,500 | $2 | $8 |
| `gpt-image-1.5` | `1024x1024 · 1536x1024 · 1024x1536` | `low · medium · high` | 6,500 | $5 | $32 |
| `gpt-image-2` | `1024x1024 · 1536x1024 · 1024x1536` | `low · medium · high` | 8,232 | $5 | $30 |
| `gpt-image-2.5-flare` | `1024x1024 · 1536x1024 · 1024x1536` | `low · medium · high · xhigh · max` | 8,232 | $5 | $30 |
| `gpt-image-2.5-sunburst` | `1024x1024 · 1536x1024 · 1024x1536` | `low · medium · high · xhigh · max` | 8,232 | $5 | $30 |

`size` and `quality` also accept `auto`, which lets the provider choose. Every
model's full descriptor map is in `/api/models.json` under
`supported_parameters`.

### Decision models

Decision models answer on [POST /v1/decisions](/docs/api-decisions) and nowhere else. They
write no text: they return one typed answer per question about a state. Each model takes its
own question format.

| Model id | Made by | Providers | Question kinds | Input /1M | Cached /1M |
|---|---|---|---|---|---|
| `typesafe/jev-1.13` | TypeSafe | `typesafe` | choice, score, yes/no (System One) | $0.042 | – |
| `bespokelabs/nimble-v4` | Bespoke Labs | `bespokelabs` | choice, score, yes/no (System One, the same as Jev) | $0.04 | – |
| `bespokelabs/nimble-v4-max` | Bespoke Labs | `bespokelabs` | choice, score, yes/no (System One, the same as Jev) | $0.09 | – |
| `cloudflare/clef` | Cloudflare | `workers-ai` | choice, score, yes/no (System One, the same as Jev) | $0.24 | – |
| `cloudflare/clef-flash` | Cloudflare | `workers-ai` | choice, score, yes/no (System One, the same as Jev) | $0.09 | – |
| `routerplus/decider-2b` | RouterPlus | `routerplus` | choice, score, yes/no (System One, the same as Jev) | $0 | $0 |
| `routerplus/kev-4b` | RouterPlus | `routerplus` | choice, score, yes/no (System One, the same as Jev) | $0 | $0 |
| `perplexity/pplx-decider-v1-27b` | Perplexity | `perplexity-decisions` | choice, score, yes/no (System One, the same as Jev) | $0.04 | – |
| `openai/gpt-6-luna-decisions` | OpenAI | `openai-decisions` | choice, score, yes/no (System One, the same as Jev) | $0.10 | – |
| `levanto/sage-1.2` | Levanto | `levanto` | choice, score, yes/no (System One, the same as Jev) | $0.05 | – |
| `scaledown/classify-1` | ScaleDown | `scaledown` | choice, score, yes/no (System One, the same as Jev) | $0.05 | – |
| `fastino/gliner-2.5-decide` | Fastino | `fastino` | classifications (single- and multi-label), entities, structures, relations | $0.03 | – |

Output is free on every decision model. Sage, like Perplexity Decider, bills the state once
per question. Bespoke Nimble v4 is $0.04 per million input tokens, and Nimble v4 Max
is $0.09: Bespoke's own prices with no markup. Nimble v4 is fast and low cost, v4 Max is
Bespoke's most accurate model. Both have a 262,144-token context for each question's prompt,
including the state, and take 1 to 64 questions per call. They share one pool, which takes 7 requests at once (5 per organization): Bespoke
allows our account 8, and one is kept for our test environment. The gateway also accepts
`bespokelabs/nimble-latest`, which this table does not list: Bespoke picks the model that
answers it (Nimble v4 today), at $0.04 per million input tokens. Clef and Clef-flash are Cloudflare's own decision models, served by Cloudflare
Workers AI at Cloudflare's own price with no markup: $0.24 and $0.09 per million input
tokens. They take 1 to 64 questions per call, each question id 1 to 100 letters, digits,
`_`, `.` or `-`, and a context of 65,536 tokens. They share one pool: 200 requests a minute
(150 per organization) and at most 8 at a time (6 per organization). Decider 2B and Kev 4B
are RouterPlus's own models, on our own GPUs in the United States, and free: $0 in and out.
They share one pool. Their contexts are 25,600 and 8,192 tokens.
RouterPlus answers an identical request from its cache for 600 s. Perplexity Decider v1 27B is Perplexity's own decision model, served by Perplexity's API
at Perplexity's own price with no markup: $0.04 per million input tokens. Perplexity bills
the state once per question, so a call costs about one state for each question it asks. It
takes 1 to 128 questions per call, and 262,144 tokens for each question's prompt. Its pool
takes 540 requests a minute (405 per organization) and 8 at once (6 per organization).
GPT-6 Luna Decisions is OpenAI's own decision model, served by OpenAI's API at OpenAI's own
price with no markup: $0.10 per million input tokens. OpenAI's API speaks its own format,
not System One, so the gateway translates your System One body to it and the answers back.
OpenAI bills the state once per call, and each question adds about 150 input tokens. It
takes 1 to 200 questions per call, 2 to 255 options in a choice, and a context of 272,000
tokens. OpenAI can decline one question and answer the rest: that answer's `type` is
`refusal`. Its pool takes 24,000 requests a minute (18,000 per organization) and 64 in flight
at once (48 per organization), so your organization's own limits bind first. OpenAI's own
name for it, `gpt-6-luna`, is the id of OpenAI's chat model GPT-6 Luna here, not of the
decision model.
ScaleDown Classify-1 is ScaleDown's Jev-compatible decision model on its `/v1/scaledown`
endpoint, at ScaleDown's own price with no markup: $0.05 per million input tokens, output
free, the price of every ScaleDown model. It runs each question as its own call, so input grows with the number of
questions. Its `state` may also carry `document` (a base64 image or PDF) with
`document_mime_type`, which ScaleDown reads by OCR. Its context is 1,000,000 tokens.
A discount may apply to decision models; see [Pricing](/docs/pricing).

Most models also carry cache pricing (`cached_prompt`, the Cached column above,
and `cache_write` where the provider bills it, the Cache write column) — the full
per-SKU table is on each model's page and in `/api/models.json`. A model with no
separate cache or reasoning price bills those tokens **at the base rate** — a
missing SKU never means free.

### Task models (ScaleDown)

ScaleDown's two chat models are tasks, not assistants. You call them on
`POST /v1/chat/completions` (or `POST /v1/messages`), and the answer's content is a JSON
string with the task's result, which you parse:

| Model id | Task | Input /1M | Cached /1M | Output /1M | Context |
|---|---|---|---|---|---|
| `scaledown/extract-1` | Fields and entities from the last user message, defined by a `response_format` of type `json_schema` (each property is a field; its `description` is the hint) | $0.05 | – | $0 | 1M |
| `scaledown/summarize-1` | An abstractive summary of the last user message; the system message holds instructions, and `max_tokens` is honored | $0.05 | – | $0 | 1M |

Output is free: these models bill input tokens only, and report 0 output tokens.
ScaleDown answers in one piece. With `stream: true` you still get a stream (role and
content, the finish, usage with its cost, `[DONE]`), but it starts when the whole answer
is ready. To classify with ScaleDown, use `scaledown/classify-1` on
[POST /v1/decisions](/docs/api-decisions).

Both read an image or a PDF too. On `/v1/chat/completions`, put one `image_url` part (a base64
`data:` URL) or one `file` part (base64 `file_data`) in the last user message, with a text part
beside it. ScaleDown reads the attachment by OCR. A web URL, more than one attachment, or an
attachment with no text is a 400 that says which.

### One model, several providers

A model id can be served by more than one provider. The catalog shows one
card; the model page lists every
provider with its own uptime and TTFB. Routing tries providers cheapest
first: the lowest input price plus output price per million, at each provider's
live price (providers at the same price keep the routing order). It fails over
**before the first byte** only — never mid-answer. A provider that fails twice
in a row, or leaves two requests in a row without an answer, rests for 30
seconds (see [Routing](/docs/routing#health-circuits-and-cooldowns)).
Each provider charges its own price, and you pay the price of the provider that
serves your request. Name a provider with `provider.only` and you pay its price.
Otherwise you pay the price of the provider that routing picks (the cheapest
first, failover included). Providers that do not set their own price share the
model's list price (the catalog build enforces it). A provider that we reach through an aggregator
is charged at the aggregator's listing price, which is the model's list price.
Its row on the model page shows that price. The row can also show the host's own
published price, labelled "Host's list price"; you do not pay that price. The
bold cells and the Cheapest sort use only the prices that you pay. The Cheapest
sort ranks providers by the input price plus the output price, the same rule as
`provider.sort: "price"`. The bold
cells mark the lowest input price, the lowest cached input price and the lowest
output price, each in its own column. A self-serve provider sets its own price, and
can change it without a release: a decrease starts at the next 5-minute mark,
an increase only after notice. Every price change starts at a 5-minute mark
(10:00, 10:05, 10:10 UTC), the first one at least 2 minutes after the change is
written: written at 10:02:30, it starts at 10:05. So every gateway knows a
change before it starts, and all of them switch at the same time. A self-serve
provider can also turn a model off or lower its limits (these stops apply at
once); the pages then hide the model at that provider and show the lower
limits. Only a limit that the listing declares, on a chat model, can be lower;
the pages show no other pushed limit, because the gateway applies no other.
A model that no provider serves now but one turns back on later has a page that
says it is not served now, and is not in the directory until it is back. A
turn-off has no price: nobody pays a price while the model is off, so a turn-off
is never an increase and needs no notice. A turn-on is compared with the last
price that you could pay while the model was on, never with a price set while it
was off. When it is higher, it is an increase, and the provider must schedule
the turn-on at least the notice period ahead.
The model page shows each provider's live price, the price in force now. It does
not show scheduled changes. `/api/models.json` shows each provider's live price
and lists every scheduled change of each provider (`scheduled_pricing`; a
provider can have at most 20). A change at the same price is not a change. In the directory, a decision model's price
is the cheapest price that you can get by naming a provider, which is the price
that the directory sorts and filters by. It is labelled "from" when it is below
the price of the provider that the page lists first. The model page's "from" price
names the same provider. The directory's price sort, its price filter and the
"from" price rank providers by the input price; when two have the same input
price, the one with the lower output price comes first. This is not the rule of
the Cheapest sort (the input price plus the output price), so on one model page
the "from" price can name a provider that the Cheapest sort does not put first. An operator can freeze a self-serve
provider. While it is frozen, you pay its listing's own price from the manifest
files, and the pages show that price. `/api/models.json` does not list its
scheduled price changes, because they do not apply while it is frozen. A model
that it turned off stays hidden, lower limits stay in force, and
`/api/models.json` still lists a scheduled turn-off or turn-on, because these
still apply. How fresh they are: the site reads the
pushed prices every 30 s, and the edge keeps a page that shows a self-serve
provider for up to 60 s (`s-maxage=60`) and can serve that copy up to 60 s more
while it fetches a new one (`stale-while-revalidate=60`), but never past the
next 5-minute mark. So `/api/models.json` lists a change as scheduled within
about 2.5 minutes, and the pages switch to the new price at its mark. A change to the manifest files (a release) can take up
to 60 s more, because the site rereads them once a minute. `/api/models.json`
lists an increase that a provider pushes for its whole notice period before it
starts, also when it comes with a turn-on. There are these exceptions:

- While a provider is frozen, its scheduled price changes are not listed. When
  an operator unfreezes it and accepts its increases, they can apply at once.
- A provider with a price feed does not choose when an increase starts: the
  site schedules a fed increase at the earliest for the notice period plus 5
  minutes after it reads the feed, which can be later than the time the
  provider publishes.
- An operator can apply an increase without notice. Each such change is
  audited.

Just
after the site starts, and until its first read, no page is cached at all. A
list price that a release changes starts at the next 5-minute mark: until then
the pages show the price you pay now (and `/api/models.json` lists the change as
scheduled), and they switch at the mark. Any other page with no self-serve provider changes only with
a release, and the edge can serve a copy up to about 11 minutes old. The gateway charges the price
in force when your request arrives at the gateway, whatever a cached page says: a
price change applies at its 5-minute mark exactly, and a stop that applies at
once (a model turned off, a lower limit) applies within about 30 s, when the
gateway next reads the prices.
That cheapest-first order (the rule of the Cheapest sort) is the default.
`provider.order` comes before it, `provider.sort: "price"` asks for it by name
(it also overrides a routing policy's saved order), and `provider.max_price`
leaves out a provider above your limit.
The `x-tm-provider` header says who served you; when that provider knows the model under
its own id, `x-tm-upstream-model` carries the id that was sent, and
the response's `model` field still names the model you asked for.
`x-tm-served-by` names the provider that ran the request, when a route reports one.

**Inference.net.** `inference-net-chat` (Inference.net) is an ordinary provider at its own
price, also on the models other providers serve. Routing tries it by its price like any
other provider: first where it is the cheapest (GLM 5.3 Flash, for example), else as a
fallback. Name it in `provider.only` or `provider.order` (`"inference-net"` works too) to
send a request there first. You pay Inference.net's own price for the model, which can be
higher or lower than another provider's; the model page shows it on Inference.net's row, and
`usage.cost` is computed from it.

```json
{ "model": "moonshotai/kimi-k2.6", "messages": [...], "provider": { "only": ["inference-net-chat"] } }
```

### Date-pinned ids

The catalog lists **one clean id per model** (`claude-haiku-4-5`), but vendors
also ship dated snapshots (`claude-haiku-4-5-20251001`, `gpt-4o-2024-08-06`)
and `-latest` spellings, and tools like Claude Code send them. Any such pin of a
catalog model works without being listed: the gateway resolves it to its family
**for routing and pricing only**, and forwards your original id to the provider
verbatim — a snapshot pin is never silently retargeted to a newer version. The
response's `model` field shows the exact snapshot that served you. If a vendor
retires a pinned snapshot, you get the vendor's own error, not a quiet upgrade.
Unknown ids still 404 naming themselves, dated or not. A key bound to your own
provider connection matches ids literally, so list the exact ids you send there.

### Claude names for Cursor

Cursor sends a model name that starts with `claude-` to Anthropic, never to a custom
base URL. So each Claude model also answers to one second name, `rp-` and its id without
`claude-`:

| Name | Model |
|---|---|
| `rp-opus-5-5` | `claude-opus-5-5` |
| `rp-sonnet-5-5` | `claude-sonnet-5-5` |
| `rp-haiku-5-5` | `claude-haiku-5-5` |
| `rp-fable-5-1` | `claude-fable-5-1` |
| `rp-opus-5` | `claude-opus-5` |
| `rp-sonnet-5` | `claude-sonnet-5` |
| `rp-fable-5` | `claude-fable-5` |
| `rp-sonnet-4-5` | `claude-sonnet-4-5` |
| `rp-haiku-4-5` | `claude-haiku-4-5` |

Each name is exactly one model, at that model's price (the price of the provider that
serves it, as for the model's own id): it is not a substitution, and
it takes no date pin (`rp-sonnet-4-5-20250929` is a 404). The provider is sent the
model's own id. The answer's `model` field echoes the name you sent (a Claude stream on
`/v1/messages` is relayed as Anthropic sent it, so its first event names the model's own
id). Billing, `/v1/usage` and `/v1/generation` record the model's own id. `GET /v1/models`
lists each name right after its model, with `canonical_slug` set to the model's id, so
model pickers that read it show them. A key bound to your own provider connection or to
a routing policy takes ids literally, so these names are not available on it. In your own
code, use the catalog ids.

### Id grammar

Ids match `[a-zA-Z0-9][a-zA-Z0-9._/-]{0,127}` — letters, digits, `.` `_` `/`
`-`, max 128 chars. `:` is deliberately excluded: the suffix namespace
(`:something`) is reserved for future marketplace variants, so a provider can
never squat a routing suffix.

## Providers are manifests

A provider is a JSON manifest in the repo — endpoint, wire dialect, settlement
terms, data policy, and a model list with exact prices:

```json
{
  "provider": { "id": "anthropic", "name": "Anthropic (direct API)", "prompt_logging": "retained" },
  "endpoint": { "base_url": "https://api.anthropic.com/v1", "dialect": "anthropic" },
  "models": [{
    "id": "claude-haiku-4-5",
    "context_length": 200000,
    "max_output_tokens": 64000,
    "pricing": [
      { "type": "prompt", "unit": "token", "cost_usd_per_million": "1" },
      { "type": "completion", "unit": "token", "cost_usd_per_million": "5" }
    ]
  }]
}
```

Manifests compile into the routing catalog through a gated pipeline —
validate, emit a staging catalog, run the live conformance suite, then promote.
Adding or repricing a model is a **data change with a gate**, never a gateway
code deploy. A self-serve provider changes its own prices without a release,
through the provider API: see [List your models](/docs/for-providers). Three
lifecycle rules do real work:

- **`is_ready: false`** stages a model: validated and testable, but never
  routed and never listed.
- **`deprecation_date`** delists automatically: past that date the model drops
  out of the compiled catalog and the public pages.
- **Shared ids must agree.** If two providers that are neither self-serve nor
  opt-in declare the same model id with different prices, or one as a chat model
  and the other as an image model, the catalog build fails. So those providers
  share the model's list price. A self-serve provider and an opt-in provider
  (`"routing": "opt_in"`) are left out of the price check: each charges its own
  price, and you pay the price of the provider that serves your request. An
  opt-in provider serves a model that other providers also serve only to a
  request that names it.

> [!NOTE]
> Prices sync as effective-dated append-only rows. A price change never
> rewrites history — old requests stay priced as dispatched. A changed list
> price starts at the first 5-minute mark (UTC) at least 2 minutes after the
> release writes it; a new model's first price applies at once.

## Conformance before listing

No model is listed on a provider's say-so. The conformance suite runs live
requests against the provider's endpoint, and passing it is the gate between
staging and live. It is deliberately implemented independently of the gateway's
own wire parsers, so a shared bug can't hide real breakage.

| Check | Proves |
|---|---|
| C1 | A non-stream completion returns real usage tokens (usage is the billable record; a listing whose output is free may report 0 output) |
| C2 | Stream frames are parseable SSE |
| C3 | Streams terminate properly (`[DONE]` / `message_stop`) |
| C4 | Usage tokens are reported in-stream |
| C5 | An unknown model yields a parseable 4xx — not a silent fallback |
| C6 | Responses carry actual assistant content, not just billable counters |
| C7 | The response echoes the requested model id — no silent substitution |
| I1 | An image generation at the top declared quality returns base64 data and usage |
| I2 | The declared per-image ceiling covers the billed output |
| I3 | An undeclared size is refused |
| I4 | The ceiling holds at every declared size (release-day probe, opt-in: it buys a real render per size) |

A text listing that answers in one piece (`streaming: false`, such as ScaleDown's) runs
C1, C5, C6 and C7: C2–C4 test the provider's stream, and the gateway makes that stream
itself.

Image listings run I1–I3 and C5. C2–C4, C6 and
C7 do not apply to them — the image route does not stream, carries no assistant
text, and an images response has no `model` field to echo.

C6 and C7 exist because the failure modes that matter are billing for an empty
answer and quietly serving a cheaper model. C7 accepts exactly one alias form:
a dated snapshot of the *same* id (`gpt-4o` → `gpt-4o-2024-08-06`), or an alias
target the manifest declares up front in `resolves_to`. `gpt-4o` answered by
`gpt-4o-mini` fails.

## The directory

[`https://dev.routerplus.com/`](https://dev.routerplus.com/) lists every live model in three sections —
chat, image and decision — because they are called on different routes. A row shows
the model's context length and max output (for a chat model), or its sizes and
qualities (for an image model). Request counts are not shown on directory rows or model
pages for any model, including newly added models. The default decision order starts with
Jev 1.13, GPT-6 Luna Decisions, Nimble v4 Max, ScaleDown Classify-1 and Nimble v4. The list can be searched
(`/?q=haiku` matches model,
lab and provider names), filtered by kind, context length, supported parameters,
zero data retention, input price, lab and provider, and sorted by use, name,
price or context. Prices, latency and uptime depend on the provider, so they
live on each model's page at `/models/<id>`: one row per provider that runs the
model, per-SKU pricing, the provider's prompt-retention policy, and ready-to-paste
snippets. The marketplace's handling of request data is described in the
[Data policy](/docs/data-policy).

### The uptime figure is allowed to say nothing

Uptime and latency come from the trailing 24 hours of real routed traffic.
When a provider has fewer than 100 counted attempts in that
window, the model page shows a dash (**–**) instead of a percentage.

> [!NOTE]
> A model with 3 requests is not "100% up", and we won't render it that way.
> No number until the sample is real — that rule is load-bearing, not a
> placeholder.

## Machine-readable: /api/models.json

Everything above, as JSON, no auth:

```bash
curl -s https://dev.routerplus.com/api/models.json
```

```json
{
  "models": [
    {
      "id": "claude-haiku-4-5",
      "display_name": "Claude Haiku 4.5",
      "output_modalities": ["text"],
      "providers": [
        { "id": "anthropic", "name": "Anthropic (direct API)", "dialect": "anthropic", "prompt_logging": "retained",
          "pricing_usd_per_million": { "prompt": "1", "cached_prompt": "0.10", "cache_write": "1.25", "completion": "5" } }
      ],
      "served_by": [
        { "id": "anthropic", "name": "Anthropic", "zdr": false,
          "routes": [ { "via": "anthropic", "direct": true } ] }
      ],
      "context_length": 200000,
      "max_output_tokens": 64000,
      "pricing_usd_per_million": {
        "prompt": "1", "cached_prompt": "0.10",
        "cache_write": "1.25", "completion": "5"
      },
      "lab": { "id": "anthropic", "name": "Anthropic" },
      "weights": "proprietary"
    }
  ],
  "gateway": "https://dev-api.routerplus.com/v1",
  "docs": "https://dev.routerplus.com/docs"
}
```

| Field | Meaning |
|---|---|
| `id` | The exact string to put in your request's `model` field |
| `output_modalities` | `["text"]`, `["image"]` or `["decisions"]` — which route serves this model. Filter on it; never guess from the id |
| `providers` | Every deployment serving this id, primary first, each with `id`, `name`, `dialect`, `prompt_logging`, its price, and `upstream_id` when the provider knows the model under its own name |
| `pricing_usd_per_million` (per provider) | What you pay when this provider serves the request, live: decimal-string USD per 1M tokens, keyed by SKU type. Absent for a `reported_cost` listing (see `price_card`) |
| `price_revision` / `price_effective_from` (per provider) | Only for a self-serve provider with a pushed price in force for this model: the revision number and when it took effect (ISO 8601, UTC). Absent when the revision in force does not have this model, and while the provider is frozen: the listing's own price from the manifest files applies then |
| `scheduled_pricing` (per provider) | Only when a change is scheduled: `[{effective_from, rises, pricing_usd_per_million}]` in time order. `rises` is `true` when any SKU goes up against the last price you could pay before it. `enabled: false` means the provider turns the model off then; such an entry has no `pricing_usd_per_million` and its `rises` is always `false`, because nobody pays a price while the model is off. A later entry without it turns the model on again, at its price; its `rises` compares that price with the last one you could pay while the model was on, never with a price set while it was off, and the notice period applies to a turn-on that rises. While the provider is frozen, only turn-offs and turn-ons are listed, at the price you pay then |
| `enabled` (per provider) | Only `false`: the provider has the model off now, and a turn-on is in its `scheduled_pricing`. Such an entry comes after the providers that serve the model, has no price, `price_revision` or `opt_in`, and is not in `served_by`. A provider that has the model off with no turn-on scheduled is not listed |
| `enabled` | Only `false`: no provider serves the model now, but one turns it back on later (see its `providers` entries). A request for it now that no BYOK route serves is answered as for an unknown model. Such an entry has no top-level `pricing_usd_per_million`, and `served_by` is empty |
| `dialect` (per provider) | The provider's **native** wire format — informational; every chat model answers on both surfaces |
| `prompt_logging` (per provider) | Provider's prompt retention: `none` or `retained` |
| `served_by` | The providers that run the model, one entry per provider. `routes[].via` is the `providers` entry the request goes to; `direct: true` means the request goes to the provider's own API. `zdr` is `true` when the provider offers Zero Data Retention for this model |
| `context_length` / `max_output_tokens` | Token limits; `max_output_tokens` may be `null`, and `context_length` is `null` for image models |
| `supported_parameters` | Image models only: the descriptor map the route enforces (`size`, `quality`, `n`, and the rest) |
| `pricing_usd_per_million` | The primary provider's live price (what a request that names no provider pays first): decimal-string USD per 1M tokens, keyed by SKU type. Other providers can charge another price: see each `providers[]` entry |
| `lab` | Who made the model, as distinct from who serves it — `null` when unknown |
| `weights` | `"open"` when the lab publishes the model's weights, `"proprietary"` when it never has, `null` when we are not certain |

For an image model `max_output_tokens` is the **per-image ceiling**, not a cap
on a completion.

Prices are decimal **strings** so nothing is lost to float rounding — parse
them with a decimal type if you're doing money math. For the authenticated,
SDK-shaped list (what `client.models.list()` calls), see
[GET /v1/models](/docs/api-models).
