Routing
Every request goes through the router. For an explicit model the router’s job is small — resolve it to a healthy upstream that serves it. For an auto-routed model it also chooses which provider and region serve it. This page describes both.
Three modes
- Explicit model. You send a full model ID (see available models); the router resolves it to the provider and region encoded in that ID and sends it upstream.
- Auto-routed model (
auto/<creator>/<model>). You name the model; the router picks which provider serves it and from where. See auto-routing a model below. - Alias (
alias/<name>). You send the name of one of your account’s model aliases; the router resolves it to the stored route and continues exactly like an explicit model. Thealias/prefix (likeauto/) is a reserved namespace — no provider can ever be named that.
The model field is required. There is no per-request route object
and no separate routing parameters — everything the router needs comes
from the model ID you send and the model catalogue. To constrain
provider or region, encode it in the model ID (below).
lowrouter/auto has been removed. It used to let the router pick
the model as well as the route, ranked on carbon per token — which
meant the greenest answer was always the smallest model in the
catalogue, a capability downgrade you had not asked for and could not
see. Choosing the model is your decision; choosing the route is ours.
Requests naming it now return 400 and point here.
Auto-routing a model
The same model is often served by several providers, in several
regions, at different prices and on very different electricity grids.
auto/<creator>/<model> lets you name the model and leave that choice
to the router:
auto/mistralai/mistral-large-2512You get the same canonical model — same weights, same output. Only the
route is decided for you. Auto-routed IDs appear in GET /v1/models alongside the explicit ones
(see available models) for every model served by more
than one route, so they are selectable in any OpenAI-compatible
client. They are omitted when you filter that listing with
?jurisdiction= — auto ranking is global and cannot promise to stay
inside a facet, so a filtered catalogue lists only explicit IDs, which
name their provider and region outright.
The priority order
The order is fixed and identical for every account — there is no policy to select. Each step only breaks ties left by the previous one:
- EU-sovereign routes first. A route counts as sovereign only when both halves hold: the provider is an EU-sovereign company and the serving region is in the EU/EEA. An EU-sovereign company serving from a US datacenter does not qualify, and neither does a US-controlled provider serving from Frankfurt.
- Lowest grid carbon intensity. A region whose grid intensity we have no data for ranks below every region we do — an unknown is treated as unknown, never as the greenest.
- Lowest price. Because carbon is decided first, two identically-priced routes can never resolve to the dirtier grid. A route with no published price ranks below every priced one.
- Round-robin across whatever is still tied.
Routes a provider has taken out of service are excluded outright, at every step.
Sovereignty here is a preference, not a guarantee
If a model has no sovereign route at all, an auto request does not
fail — it falls through to the greenest, then cheapest route
available anywhere. auto/anthropic/claude-sonnet-5 routes, to a
non-EU provider.
The response is what keeps this honest.
lowrouter_metadata.eu_sovereign tells you whether the route you got
was sovereign, alongside provider and region, and the model
field carries the fully resolved four-segment ID. If you need
sovereignty as a hard constraint rather than a preference, use an
explicit ID — it fails loudly instead of falling back outside your
constraint.
lowrouter_metadata.routing_reason names the step that decided:
eu_sovereign_preferred, lowest_carbon_intensity, lowest_cost,
round_robin, or only_route when the model has just one route.
What auto-routing does not do
- It never changes which model you get — that is your choice, and the whole point of naming it.
- It does not score latency or answer quality.
- It does not consult your aliases:
auto/is its own namespace and always applies the order above. - A version shorthand still works —
auto/mistralai/mistral-largeresolves to the latest version — but a region does not: there is no 4th segment to write, because choosing the region is the point.
Pinning a provider or region
Region and provider are part of the model ID, not a separate
field. The public ID has the form
{provider}/{creator}/{model}[/{locode}]:
| Goal | How |
|---|---|
| Pin the provider | Use an explicit model ID — the first segment is the provider, e.g. vertex/anthropic/claude-opus-4.6. |
| Pin the region | Append a UN/LOCODE as the 4th segment, e.g. vertex/anthropic/claude-opus-4.6/sg-sin. |
| Default region | Omit the 4th segment; see how IDs resolve below. |
If you request a region a model isn’t served in, the request is rejected rather than silently served elsewhere — the region you pin is the region you get.
How IDs resolve
You do not have to write the full four-segment ID. What you leave out is filled in from the catalogue, most-specific first, and the response always tells you what you actually got.
| You send | What happens |
|---|---|
mistral/mistral/mistral-large-2512/eu | Used exactly as written. |
mistral/mistral/mistral-large-2512 | Region defaulted — resolves to /eu. |
mistral/mistral/mistral-large | Version and region defaulted — resolves to mistral-large-2512/eu. |
anthropic/anthropic/claude-sonnet | Resolves to the latest sonnet at /global. |
Missing version resolves to the most recent version of that same
model. The version is the only thing that moves: claude-sonnet
resolves to the newest sonnet, never to an opus, and
mistral-large never to a mistral-small. A shorthand that would be
ambiguous between genuinely different models — openai/openai/gpt-oss,
where gpt-oss-20b and gpt-oss-120b are separate models rather than
two versions of one — is rejected, not guessed.
Missing region resolves to global when the model has a global
endpoint. When it doesn’t, it resolves to the model’s only region, or,
where several exist, to the lowest-carbon one. A region whose grid
intensity we don’t have data for is never chosen over one we do — an
unknown is treated as unknown, not as zero.
The response’s model field always carries the fully resolved
four-segment ID, so a request is reproducible from its own response —
copy it back and you pin exactly what ran. lowrouter_metadata.region
reports the region independently.
Pinning still fails loudly
Resolution only ever fills in what you left out. It never overrides what you wrote:
- A version that doesn’t exist is an error, not a nudge to the nearest
one.
mistral/mistral/mistral-large-9999→404. - A region the model isn’t served in is an error, not a reroute.
mistral/mistral/mistral-large-2512/us-iad→503. - An explicit
/globalon a model with no global endpoint is an error, not a silent switch to a regional row.
That asymmetry is deliberate. Defaults exist so the IDs in our own
docs and model list are callable as printed; pins exist so that when
you name a version or a jurisdiction, the thing you named is the thing
that ran. Aliases are stricter still: an alias target must
be a full, concrete {provider}/{creator}/{model}/{locode} triple, so
a stored route can never drift under you.
Worked scenario: EU-only first, lowest carbon second
Say a data-residency commitment requires EU inference, and within that constraint you want the lowest carbon available. The order matters: sovereignty is a constraint, carbon is an optimisation, and the two are handled by different mechanisms.
- Encode the constraint. Filter the providers page to EU providers, then compare per-token carbon across the models that remain in the catalogue.
- Pin the winner with an explicit ID, e.g.
mistral/mistral/mistral-large-2512/eu— or better, point an alias at it, so you can re-run the comparison next quarter and repoint without touching client code. - Verify, don’t trust. Check
lowrouter_metadata.regionon the responses; the pin is proven on every call.
Note what you did not do: ask the router for “EU only”.
Auto-routing does not treat a jurisdiction as a hard constraint.
auto/<creator>/<model> does prefer EU-sovereign routes above
everything else, and reports whether it got one — but when a model has
no sovereign route it falls back rather than failing, so it is an
optimisation, not a commitment. Per-key jurisdiction restrictions are
coming; until then the honest tool for a hard constraint is the
explicit ID, which fails loudly rather than falling back outside it.
What happens on failure
LowRouter does not silently move your request to a different provider:
an explicit ID is a pin, and an auto-routed request commits to the
winner of the ranking. If that route fails, the request returns 503
naming the provider that failed rather than reporting a different one
you never asked for. Substituting a provider would bill against
another pricing row and serve from another jurisdiction than the ID
promised.
Which providers were attempted is reported on the response in
lowrouter_metadata.providers_attempted, alongside
lowrouter_metadata.fallback_occurred.
What the router does not do
- It does not choose the model — that is what naming it is for.
- It does not benchmark output quality — it optimises for sovereignty, then carbon, then cost, not “is the answer good”.
- It does not accept a per-request
routeobject or aprefer_low_carbonflag. Low carbon is already ranked ahead of price, so there is nothing to opt into.
