Console
API reference/GET /v1/models

GET /v1/models

The catalog, in whichever shape your SDK expects.

/llms.txt

Lists every model id this gateway can serve — one row per distinct id. This is the endpoint SDK models.list() calls resolve to, so it answers in two shapes:

RequestResponse shape
No anthropic-version headerOpenAI list object
anthropic-version header present (any value)Anthropic models list

The Anthropic SDK sends anthropic-version on every request, so each SDK gets its native shape with zero configuration.

Authentication is required, in either surface's convention — both work on every gateway route:

Authorization: Bearer $TM_API_KEY
# or
x-api-key: $TM_API_KEY

A missing or invalid key is a 401 with error_type: "auth" (see Errors).

A key bound to your own provider connection lists that connection's models; a key under a routing policy lists the policy's models. Deployed endpoints from Optimize (tm/<name>-v<n>) are not listed here. Your organization's active dedicated endpoints (<your-namespace>/<name>) are, with owned_by routerplus, on the base URL they are served from.

OpenAI shape (default)

bash
curl -s https://api.routerplus.com/v1/models \
  -H "Authorization: Bearer $TM_API_KEY"
json
{
  "object": "list",
  "data": [
    { "id": "claude-haiku-4-5", "object": "model", "created": 1756900000, "owned_by": "anthropic",
      "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": "wan-3.0", "object": "model", "created": 1756900000, "owned_by": "openrouter-media",
      "architecture": { "input_modalities": ["text"], "output_modalities": ["video"] } }
  ]
}
FieldTypeMeaning
idstringThe exact string for your request's model field
object"model"Constant
createdintegerUnix seconds — see the note below
owned_bystringProvider id of the first deployment routing would try for this model; routerplus for a dedicated endpoint
architecture.input_modalitiesarrayWhat 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, video and decision models take ["text"]. A route on your own provider key declares no inputs, so it adds none here; the gateway sends it every part as you sent it. A documented extension OpenAI SDKs ignore
architecture.output_modalitiesarray["text"], ["image"], ["video"] or ["decisions"] — a documented extension OpenAI SDKs ignore

Filtering by modality

bash
curl -s "https://api.routerplus.com/v1/models?output_modalities=image" \
  -H "Authorization: Bearer $TM_API_KEY"

output_modalities takes a comma-separated list of text, image, video and decisions; the list is a filter, so ?output_modalities=text,image,video,decisions is the same as sending nothing. Any other value is a 400 invalid_request ("invalid output_modalities filter"). The Anthropic shape never lists image, video or decision models — the Anthropic Messages API has no route to call them on.

A provider query parameter takes the same JSON object as the request-level provider routing controls ({"only":["openai"]}, for example) and lists what those controls would let through — see Routing policies.

Anthropic shape

bash
curl -s https://api.routerplus.com/v1/models \
  -H "x-api-key: $TM_API_KEY" \
  -H "anthropic-version: 2023-06-01"
json
{
  "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 catalog is small and the full list arrives in one response. There is no pagination to implement.

Note

created / created_at is the time the gateway process loaded its catalog, not the model's release date. Don't build logic on it. For real metadata — context length, prices, retention policy — use the public /api/models.json, documented in Models & catalog. This endpoint stays SDK-shaped plus one documented extension: architecture, which SDKs ignore and modality-aware clients read.

SDK usage

python
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.routerplus.com/v1", api_key=os.environ["TM_API_KEY"])
for m in client.models.list():
    print(m.id, m.owned_by)
python
import os
import anthropic

# The SDK sends anthropic-version itself, so this gets the Anthropic shape.
client = anthropic.Anthropic(base_url="https://api.routerplus.com", api_key=os.environ["TM_API_KEY"])
for m in client.models.list():
    print(m.id)
typescript
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://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

This list is the contract: a completion request (/v1/chat/completions or /v1/messages) for any id not in it fails immediately with a 404 that echoes exactly the string you sent — before any provider is contacted and before anything is billed. The one exception is a dated pin of a listed model (claude-haiku-4-5-20251001, gpt-4o-2024-08-06, -latest), which routes as its family — see Models & catalog.

OpenAI surface:

json
{
  "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:

json
{
  "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 alongside x-request-id.

Warning

There is no fuzzy matching and no silent fallback to a "close" model. A typo in the model id is a 404, not a quietly different bill. Echoing your own requested string back names the problem without turning the error into an existence oracle — unknown ids all 404 identically.

Three neighbors of this error are worth telling apart:

Statuserror_typeMeaning
404model_unavailableThe id is not in the catalog. Fix the id.
503gateway_errorThe 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, don't fix.
400model_not_pricedBilled key, and the ledger has no price row for this model — the gateway refuses to serve what it cannot meter.

The full taxonomy is in Errors.

One more neighbor: a listed image model sent to a chat route is a 400 invalid_request naming POST /v1/images/generations, not a 404 — the id exists, you called the wrong route. A video model on a chat route names POST /v1/videos the same way. The mirror case (a chat model on the images or videos route) is the same 400 pointing back at the chat routes. See POST /v1/images/generations and POST /v1/videos.

Markdown source for agents: /docs/api-models.md · index at /llms.txt