List models
The model catalog.
/v1/modelsGET /v1/models lists every model id RouterPlus can serve on your key, one row per id. GET /v1/models/<id> returns one row of that list. SDK models.list() and models.retrieve() calls resolve to these endpoints, so both answer in two shapes:
| Request | Response shape |
|---|---|
No anthropic-version header | OpenAI |
anthropic-version header present (any value) | Anthropic |
The Anthropic SDK sends anthropic-version on every request, so each SDK gets its own shape with no configuration.
Send your key as Authorization: Bearer $TM_API_KEY or as x-api-key: $TM_API_KEY. A missing or invalid key is a 401 with error_type: "auth" (see Errors).
List models: OpenAI shape (default)
curl -s https://dev2-api.routerplus.com/v1/models \
-H "Authorization: Bearer $TM_API_KEY"{
"object": "list",
"data": [
{ "id": "claude-haiku-4-5", "object": "model", "created": 1756900000, "owned_by": "anthropic",
"context_length": 200000,
"architecture": { "input_modalities": ["text", "image", "file"], "output_modalities": ["text"] } },
{ "id": "gpt-image-1", "object": "model", "created": 1756900000, "owned_by": "openai",
"architecture": { "input_modalities": ["text"], "output_modalities": ["image"] } },
{ "id": "typesafe/jev-1.13", "object": "model", "created": 1756900000, "owned_by": "typesafe",
"architecture": { "input_modalities": ["text"], "output_modalities": ["decisions"] } }
]
}| Field | Type | Meaning |
|---|---|---|
id | string | The exact string for the model field of your request. |
object | "model" | Constant. |
created | integer | Unix seconds. See the note under Anthropic shape. |
owned_by | string | The provider id of the first deployment routing would try for this model. routerplus for a dedicated endpoint. |
context_length | integer | Chat models only. The largest context window, in tokens, among the routes of your key for this model. Absent when no route declares a window. |
architecture.input_modalities | array | What a message to the model may carry: "text", plus each of "image", "file", "audio" and "video" that a route of this key takes. A chat request with a part that no route takes is a 400 (see Wire compatibility). Image and decision models take ["text"]. A route on your own provider key declares no inputs, so it adds none here. RouterPlus sends it every part as you sent it. |
architecture.output_modalities | array | ["text"], ["image"], ["video"], ["decisions"], ["embeddings"], ["transcription"] or ["audio"]. A transcription model takes ["audio"] and a speech model takes ["text"]. |
OpenAI SDKs ignore context_length and architecture. Clients that size their context window or pick a route by modality read them.
What the list contains
- A key bound to your own provider connection lists the models of that connection.
- A key under a routing policy lists the models of the policy.
- Your organization's active dedicated endpoints (
<your-namespace>/<name>) are listed withowned_byrouterplus, on the base URL they are served from. - Deployed endpoints from Optimize (
tm/<name>-v<n>) are not listed. - The OpenAI shape lists the
rp-name of each Claude model (rp-sonnet-5-5forclaude-sonnet-5-5) right after its model. That row has the sameowned_by,context_lengthandarchitecture, and acanonical_slugthat names the model. Model pickers that read this list, such as Cursor's, show these names. See Claude names for Cursor. The Anthropic shape does not list them.
Filtering
curl -s "https://demo-api.routerplus.com/v1/models?output_modalities=image" \
-H "Authorization: Bearer $TM_API_KEY"output_modalities takes a comma-separated list of these values:
| Value | Models for |
|---|---|
text | Chat |
image | Image generation |
video | Video generation |
decisions | POST /v1/decisions |
embeddings | POST /v1/embeddings |
transcription | POST /v1/audio/transcriptions |
audio | POST /v1/audio/speech |
- The list is a filter.
?output_modalities=text,image,video,decisions,embeddings,transcription,audiois the same as no filter. - A kind with no model in the catalog gives an empty list.
- Any other value is a 400
invalid_request("invalid output_modalities filter"). - The Anthropic shape lists chat models only. The Anthropic Messages API has no route for image or decision models.
A provider query parameter takes the same JSON object as the request-level provider routing controls, for example {"only":["openai"]}. The response lists the models those controls let through. See Routing policies.
Anthropic shape
curl -s https://dev2-api.routerplus.com/v1/models \
-H "x-api-key: $TM_API_KEY" \
-H "anthropic-version: 2023-06-01"{
"data": [
{ "type": "model", "id": "claude-haiku-4-5", "display_name": "claude-haiku-4-5", "created_at": "2026-09-03T12:00:00.000Z" }
],
"has_more": false,
"first_id": "claude-haiku-4-5",
"last_id": "gpt-4o-mini"
}has_more is always false. The full list arrives in one response, with no pagination.
created and created_at are the time the gateway process loaded its catalog. They are not the release date of the model, so do not build logic on them. For prices and retention policy, use the public /api/models.json, documented in Models & catalog.
Retrieve one model
GET /v1/models/<id> returns the row that GET /v1/models gives your key for that id, in the same shape rules. An id with a slash, such as typesafe/jev-1.13, works as it is or URL-encoded.
curl -s https://dev2-api.routerplus.com/v1/models/claude-haiku-4-5 \
-H "Authorization: Bearer $TM_API_KEY"{ "id": "claude-haiku-4-5", "object": "model", "created": 1756900000, "owned_by": "anthropic",
"context_length": 200000,
"architecture": { "input_modalities": ["text", "image", "file"], "output_modalities": ["text"] } }With anthropic-version, the answer is one Anthropic row, for example {"type": "model", "id": "claude-haiku-4-5", "display_name": "claude-haiku-4-5", "created_at": "2026-09-03T12:00:00.000Z"}.
An id that the list does not give your key is a 404 model_unavailable, with the same body as in Unknown models. In the Anthropic shape, this includes every model that is not a chat model.
GET /v1/models/<id>/endpoints is a separate route. It lists each provider of one model with its price, data policy, status and measurements. See Provider routing.
SDK usage
import os
from openai import OpenAI
client = OpenAI(base_url="https://demo-api.routerplus.com/v1", api_key=os.environ["TM_API_KEY"])
for m in client.models.list():
print(m.id, m.owned_by)import os
import anthropic
# The SDK sends anthropic-version itself, so this gets the Anthropic shape.
client = anthropic.Anthropic(base_url="https://demo-api.routerplus.com", api_key=os.environ["TM_API_KEY"])
for m in client.models.list():
print(m.id)import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://demo-api.routerplus.com/v1", apiKey: process.env.TM_API_KEY });
for await (const m of client.models.list()) {
console.log(m.id, m.owned_by);
}Unknown models on completion calls
A completion request (/v1/chat/completions or /v1/messages) for an id that is not in this list fails with a 404. The error echoes the string you sent. RouterPlus contacts no provider and bills nothing. One exception: a dated pin of a listed model (claude-haiku-4-5-20251001, gpt-4o-2024-08-06, -latest) routes as its family. See Models & catalog.
OpenAI surface:
{
"error": {
"code": "model_unavailable",
"message": "model \"gpt-5o\" is not in the catalog; GET /v1/models lists what this key can serve",
"type": "invalid_request_error",
"metadata": { "error_type": "model_unavailable" }
},
"request_id": "6f3c…"
}Anthropic surface:
{
"type": "error",
"error": {
"type": "not_found_error",
"message": "model \"gpt-5o\" is not in the catalog; GET /v1/models lists what this key can serve",
"error_type": "model_unavailable"
},
"request_id": "6f3c…"
}Both carry the x-tm-error-code: model_unavailable header and x-request-id.
RouterPlus does no fuzzy matching and never falls back to a similar model. A typo in the model id is a 404. Every unknown id gets the same 404, so the error does not reveal which ids exist.
Errors
| Status | error_type | Meaning |
|---|---|---|
| 404 | model_unavailable | The id is not in the catalog. Fix the id. |
| 503 | gateway_error | The id is in the catalog, but every deployment serving it is cooling down after failures. Comes with retry-after: 5 and x-tm-limit-kind: health. Retry the request. |
| 400 | model_not_priced | Billed key, and the ledger has no price row for this model. RouterPlus does not serve a model it cannot meter. |
| 400 | invalid_request | A listed image model sent to a chat route. The message names POST /v1/images/generations. A chat model sent to the images route gets the same 400, pointing at the chat routes. See POST /v1/images/generations. |
Errors has the full list.
For agents: /docs/api-models.md and /llms.txt