Models & catalog
The catalog, model ids, uptime honesty, machine-readable feeds.
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://app.routerplus.com/ | none | Browsing, filters, featured model order |
| Per-model pages | https://app.routerplus.com/models/<id> | none | Providers with prices, latency, uptime and data policy; copy-paste snippets |
| Machine-readable JSON | https://app.routerplus.com/api/models.json | none | Scripts, dashboards, price checks |
| SDK-shaped list | https://api.routerplus.com/v1/models | API key | client.models.list() — see GET /v1/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). The catalog as of this writing — the live list is always /api/models.json:
| Model id | Providers | Context | Input /1M | Output /1M |
|---|---|---|---|---|
claude-opus-5-5 | anthropic, deepinfra-labs | 1M | $4 | $20 |
claude-fable-5-1 | anthropic | 1M | $10 | $50 |
claude-sonnet-5-5 | anthropic, deepinfra-labs | 1M | $2 | $10 |
claude-haiku-5-5 | anthropic | 1M | $0.1 | $0.5 |
gpt-6-astra | openai | 1.05M | $10 | $50 |
gpt-6.1-sol | openai | 1.05M | $2 | $10 |
gpt-6-luna | openai | 1.05M | $0.1 | $0.5 |
gpt-5.6-terra | openai | 1.05M | $2 | $12 |
gpt-6-sol | openai | 1.05M | $2 | $10 |
gpt-5.6-sol | openai | 1.05M | $4 | $20 |
gpt-5.6-luna | openai | 1.05M | $0.2 | $1.2 |
claude-sonnet-5 | anthropic | 1M | $2 | $10 |
claude-opus-5 | anthropic, deepinfra-labs | 1M | $5 | $25 |
claude-fable-5 | anthropic, deepinfra-labs | 1M | $10 | $50 |
claude-sonnet-4-5 | anthropic | 200K | $3 | $15 |
claude-haiku-4-5 | anthropic, deepinfra-labs | 200K | $1 | $5 |
gpt-4o-mini | openai | 128K | $0.15 | $0.6 |
gpt-4.1-mini | openai | 1.05M | $0.4 | $1.6 |
gpt-4o | openai | 128K | $2.5 | $10 |
deepseek/deepseek-v4.1-flash | morphllm, deepinfra-chat | 1.05M | $0.049 | $0.6 |
tencent/hy4-preview | deepinfra-chat | 1.05M | $0.834 | $2.501 |
z-ai/glm-5.3-flash | morphllm, deepinfra-chat | 1.05M | $0.029 | $0.5 |
z-ai/glm-5.3 | morphllm, deepinfra-chat, mistral-ai | 1.05M | $0.055 | $4 |
deepseek/deepseek-v4-flash-0731 | deepinfra-chat | 1.05M | $0.06 | $0.18 |
moonshotai/kimi-k3 | morphllm, deepinfra-chat | 1.05M | $0.75 | $14.25 |
z-ai/glm-5.2 | morphllm, deepinfra-chat | 1.05M | $0.4 | $2.4 |
minimax/minimax-m3 | deepinfra-chat | 524K | $0.28 | $1.1 |
deepseek/deepseek-v4-pro | deepinfra-chat | 1.05M | $1.3 | $2.6 |
deepseek/deepseek-v4-pro-0813 | deepinfra-chat | 1.05M | $1.3 | $2.6 |
google/gemma-4-31b-it | deepinfra-chat | 262K | $0.2 | $0.4 |
xiaomi/mimo-v2.6-pro | deepinfra-chat | 1.05M | $0.43 | $0.87 |
xiaomi/mimo-v2.6-flash | deepinfra-chat | 1.05M | $0.14 | $0.28 |
claude-opus-4-8 | deepinfra-labs | 1M | $5 | $25 |
claude-opus-4-7 | deepinfra-labs | 1M | $5 | $25 |
claude-sonnet-4-6 | deepinfra-labs | 1M | $3 | $15 |
google/gemini-3.7-flash | deepinfra-labs | 1M | $0.75 | $3.75 |
google/gemini-3.5-flash | deepinfra-labs | 1M | $1.5 | $9 |
google/gemini-3.1-pro | deepinfra-labs | 1M | $2 | $12 |
google/gemini-3.1-flash-lite | deepinfra-labs | 1M | $0.25 | $1.5 |
google/gemini-2.5-pro | deepinfra-labs | 1M | $1.25 | $10 |
google/gemini-2.5-flash | deepinfra-labs | 1M | $0.3 | $2.5 |
openai/gpt-oss-120b | deepinfra-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 | $22.5 |
mistral-large-4 | mistral-ai | 1.05M | $1.36 | $4.18 |
mistral-medium-2604 | mistral-ai | 262K | $1.5 | $7.5 |
mistral-small-2603 | mistral-ai | 262K | $0.15 | $0.6 |
mistral-large-2512 | mistral-ai | 262K | $0.5 | $1.5 |
ministral-14b-2512 | mistral-ai | 262K | $0.2 | $0.2 |
ministral-8b-2512 | mistral-ai | 262K | $0.15 | $0.15 |
ministral-3b-2512 | mistral-ai | 131K | $0.1 | $0.1 |
codestral-2508 | mistral-ai | 256K | $0.3 | $0.9 |
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.
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. 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 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.
curl https://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 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 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 |
|---|---|---|---|---|
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 |
routerplus/kev-4b | RouterPlus | routerplus | choice, score, yes/no (System One, the same as Jev) | $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.
Most models also carry cache pricing (cached_prompt, and cache_write where the provider bills it) — 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 | 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.
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 in priority order and fails over before the first byte only — never mid-answer. Prices are identical across providers of one model (enforced when the catalog is built), so which provider served you never changes your bill. The x-tm-provider header says who did; 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 echoes the provider's id truthfully. x-tm-served-by names the provider that ran the request, when a route reports one.
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: 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:
{
"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. Three lifecycle rules do real work:
is_ready: falsestages a model: validated and testable, but never routed and never listed.deprecation_datedelists automatically: past that date the model drops out of the compiled catalog and the public pages.- Shared ids must agree. If two providers 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. Pass-through pricing stays coherent per id.
Prices sync as effective-dated append-only rows. A price change never rewrites history — old requests stay priced as dispatched.
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://app.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.
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 n<100 instead of a percentage.
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.
The hourly bars on a model page are green at ≥ 99%, amber at ≥ 95%, and red below that; an hour with no sample stays grey.
Machine-readable: /api/models.json
Everything above, as JSON, no auth:
curl -s https://app.routerplus.com/api/models.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" }
],
"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://api.routerplus.com/v1",
"docs": "https://app.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, and upstream_id when the provider knows the model under its own name |
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 | Decimal-string USD per 1M tokens, keyed by SKU type |
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.
Markdown source for agents: /docs/models.md · index at /llms.txt