How auto routing works

Routing is two layers, and only runs at all when you pass model:"auto":

  1. Requirement profile. Your messages are classified into a model-agnostic profile — difficulty, task type, and whether the query needs reasoning, code, tools, vision, or a long context window. This never names a model, is regex/keyword-based (no network call, sub-millisecond), and reads real signals where they exist: requires_tools from whether you actually passed tools, requires_vision from whether a message actually contains an image.
  2. Model selection. The cheapest model in the catalog that satisfies the profile is chosen, under your key's routing mode. Adding a new model to the catalog never requires retraining anything — it's a registry row picked up on the next request.

Routing modes

mode only affects "auto" requests. Precedence: request body mode > x-llmrouter-mode header > your key's configured default > balanced.

costfavors the cheapest model that meets the minimum bar
balanceddefault — balances cost against the query's predicted difficulty
qualityfavors the highest capability grade clearing the bar, cost secondary

Pinning a model

Pass any slug from the catalog directly — e.g. anthropic/claude-opus-4.8, openai/gpt-5 — and no routing decision runs at all; it's served (with automatic provider failover, see Model fallbacks and Provider selection). If your key has a model_allowlist, both explicit pins and "auto" are restricted to it — an explicit id outside the allowlist gets a 403 model_not_allowed.

Listing models

GET /v1/models returns the OpenAI list shape — every catalog slug plus the auto pseudo-model — restricted to your key's allowlist if it has one. Browse the same catalog with price, context, and capability grades at /models, or compare models side by side at /compare.

curl https://api.llmrouter.sh/v1/models \
  -H "Authorization: Bearer llmr_sk_live_..."

Explain a decision

POST /v1/route takes the same body as /v1/chat/completions and returns the routing decision only — chosen model, ranked candidates, mode, reason, and predicted profile — with no upstream call and no charge. Use it to debug why a request would route somewhere before spending anything.

Response headers

Every /v1/chat/completions response carries the routing decision in headers, so you never have to guess what actually served the request:

x-llmrouter-modelthe model slug that actually served the request
x-llmrouter-modethe routing mode used for this request
x-llmrouter-difficulty / -reasonpresent on "auto" requests only — the predicted difficulty and why this model was chosen
x-llmrouter-fallbackscomma-separated ordered candidate list behind the primary pick
x-llmrouter-primary-modelpresent only when a fallback actually served — the model originally routed to
x-llmrouter-served-viawhich transport served it (direct, fallback, sandbox)
x-llmrouter-cost-usdtotal cost billed, provider price + the 1% fee
x-llmrouter-routing-mstime spent selecting a model, excluding the upstream call
x-llmrouter-trace-idlook this up under /logs for the full trace

Send x-llmrouter-explain: true to also get an llmrouter: {"{"}chosen, served, ranked, mode, reason, profile, fallback_used, trace_id{"}"} block inline in the JSON response body.