Auto router
Let RouterPlus pick the model for each request.
Send the model routerplus/auto, and RouterPlus selects a model for each request. The router reads what the request asks for and stays in the cost tier that you select. It keeps one conversation on one model.
Request
{
"model": "routerplus/auto",
"messages": [{ "role": "user", "content": "Why does this throw?\n```js\nnull.x\n```" }],
"auto": { "tier": "economy", "prefer": "cost", "models": ["deepseek/deepseek-v4.1-flash", "claude-haiku-5-5"] }
}The auto object and all of its fields are optional.
| Field | Rule |
|---|---|
auto.tier | economy, balanced (default) or premium. |
auto.prefer | quality (default) or cost. With cost, the router can also select models in cheaper tiers, and price counts for more. |
auto.models | The models that the router can select. Leave it out to use the full list below. |
Tiers
| Tier | Models |
|---|---|
premium | claude-opus-5-5, gpt-6-astra |
balanced | claude-sonnet-5-5, gpt-6-luna, moonshotai/kimi-k3, z-ai/glm-5.3 |
economy | claude-haiku-5-5, deepseek/deepseek-v4.1-flash, openai/gpt-oss-120b, z-ai/glm-5.3-flash |
The router selects from your tier. When no model in your tier can serve the request, it selects from the next tier up.
How it selects
- 01The router reads the conversation and names the task:
code: code fences, stack traces, file paths or SQL.reasoning: proofs, math or requests for step-by-step work.extraction:response_formatwith a JSON schema.vision: images in the latest message.long_context: 120,000 or more characters of input.chatorcreativeotherwise.
- 02It removes the models that cannot serve the request:
- models without image input, when you send images
- models without tools, when you send tools
- models with a context window too small for your input
- 03It removes the models that your key's guardrails or
auto.modelsdo not allow. - 04It ranks the remaining models by how well each one does the task, then by price.
A short follow-up such as "thanks, now make it faster" keeps the conversation's task.
One model per conversation
The router keeps a conversation on the model that it selected first. The router identifies a conversation by your system prompt plus your first user message. It selects again only in these cases:
- The latest message asks for a different task, for example a code conversation that now asks for a poem.
- The model can no longer serve the request.
Fallback
The router also ranks up to 4 more models. When the selected model fails before its answer starts, RouterPlus tries the next model, as in Model fallback.
Response
The response is the selected model's answer, and model names that model. Two headers tell what the router did:
| Header | Meaning |
|---|---|
x-tm-auto-model | The model that the router selected. |
x-tm-auto-reason | A short reason, for example task code; tier economy; strong at code. |
Billing
RouterPlus bills the request as a direct call to the model that answered. The router adds no charge.
Custom routers
Your organization can store its own router and call it as the model routerplus/auto@<slug>. A router has a list of models that it can select, rules that it tries in order, and a default model. In the console, open Build > Routers.
{
"model": "routerplus/auto@support",
"messages": [{ "role": "user", "content": "Where is my invoice for October?" }]
}The router selects a model in this order:
- 01The trained classifier, if the router has one and its prediction is above the threshold. See Training.
- 02The rules, in order. The first rule that matches selects its model.
- 03The built-in ranking above, over the router's candidates.
- 04The default model.
- The router never selects a model that your key's guardrails or
auto.modelsdo not allow. It goes to the next step instead. auto.tierandauto.preferin the request apply to step 3.- In step 3, one conversation keeps its model, as above. The classifier and the rules decide again on each request.
The response has the x-tm-auto-model and x-tm-auto-reason headers. It also has x-tm-router with the router's slug and version, for example support@3. The reason names the step: classifier: claude-haiku-5-5 at 94%, rule 2, a ranking reason, or default. An unknown slug returns 404 model_unavailable.
Spec
{
"candidates": [
{ "model": "claude-haiku-5-5", "tier": "economy" },
{ "model": "claude-sonnet-5-5", "strengths": ["code", "creative"] }
],
"rules": [
{ "when": { "contains": ["\\binvoice\\b", "\\brefund\\b"] }, "use": "claude-haiku-5-5" },
{ "when": { "task": ["code"], "min_input_chars": 20000 }, "use": "claude-sonnet-5-5" }
],
"default": "claude-haiku-5-5",
"prefer": "cost"
}| Field | Rule |
|---|---|
candidates | Up to 20 models for step 3. tier and strengths are optional. A model from the tiers table keeps its tier, strengths and context window. Any other model is balanced, and the router assumes that it takes images and tools. |
rules | Up to 50 rules. Each rule has when and use (a model id). |
default | The model for step 4. Required. |
prefer | cost or quality, for step 3. auto.prefer in the request wins. |
Every condition in when must be true. A rule with an empty when always matches.
| Condition | Matches when |
|---|---|
task | The task is one of these: code, reasoning, extraction, chat, creative, vision, long_context. |
contains | One of these regular expressions matches the first 20,000 characters of the latest user message. Case is ignored. 1 to 10 patterns of up to 512 characters. |
min_input_chars | The input, with the system prompt and the tool definitions, has at least this many characters. |
has_images | The conversation has an image (true), or has none (false). |
has_tools | The request sends tools (true), or sends none (false). |
contains patterns follow the same safety rules as guardrail regex rules. RouterPlus refuses these patterns with 400 invalid_router:
- a lookahead or a lookbehind
- a backreference
- a repeated group that holds a quantifier or an alternation, such as
(a+)+
Manage routers
Use a management key, under https://demo-api.routerplus.com/v1 or https://demo-api.routerplus.com/api/v1.
| Method and path | Body | Result |
|---|---|---|
GET /v1/routers | The latest version of each router. | |
POST /v1/routers | { "slug": "support", "spec": { ... } } | 201. A slug that exists returns 409. |
GET /v1/routers/:slug | The latest version. ?version=2 reads an older version. | |
PUT /v1/routers/:slug | { "spec": { ... }, "expected_version": 3 } | A new version. expected_version is optional. When it is not the latest version, the response is 409. |
DELETE /v1/routers/:slug | The router stops working. | |
POST /v1/routers/:slug/train | { "examples": [ ... ], "threshold": 0.7 } | A new version with a trained classifier. |
A slug is 1 to 80 characters from a-z, 0-9, _ and -, and starts with a letter or a digit. Each change writes a new version. Requests use the latest version within 5 seconds.
curl -s https://dev2-api.routerplus.com/v1/routers \
-H "Authorization: Bearer $TM_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{"slug":"support","spec":{"rules":[{"when":{"contains":["\\binvoice\\b"]},"use":"claude-haiku-5-5"}],"default":"claude-sonnet-5-5"}}'Training
A router can learn from your labeled requests. Send examples of text, each with the model that must answer it:
curl -s https://dev2-api.routerplus.com/v1/routers/support/train \
-H "Authorization: Bearer $TM_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{"threshold":0.8,"examples":[
{"text":"I was charged twice this month","model":"claude-haiku-5-5"},
{"text":"The export to CSV crashes with error 500","model":"claude-sonnet-5-5"}
]}'- Send 10 to 5,000 examples. Each
texthas up to 10,000 characters. - Label at least two models. Each label must be a candidate or the router's default.
- The gateway fits a naive Bayes text classifier on words and word pairs. It keeps the 20,000 most frequent features.
thresholdis optional, above 0 and below 1. Default 0.7.
At request time, the classifier reads the latest user message. When its top model has a probability above the threshold, that model answers, before the rules. Otherwise the rules decide.
The response has the new version and a training object with these fields: examples, labels, features, threshold and training_accuracy. training_accuracy is the share of your examples that the classifier labels correctly. Router objects show a summary of the classifier: its labels, feature count, example count, threshold and training time.
To replace the classifier, train again. A PUT without model_classifier keeps the current classifier. To remove it, send "model_classifier": null.
Errors
| Status | Cause |
|---|---|
400 invalid_request | The auto object is invalid. The message names the field. |
400 invalid_request | No allowed model can serve the request. The message names the need: image input, tools or context length. |
400 invalid_router | A custom router's spec or training request is invalid. The message names the field. |
400 invalid_request | No step of a custom router can select an allowed model. |
404 model_unavailable | The custom router slug is unknown. |
For agents: /docs/auto-router.md and /llms.txt