Routing Overview
How the gateway decides which model and which provider serves a request, and what it records about that decision.
Routing Overview
Routing is the stage between resolving a request's model and applying the governance gate. It exists on keyed connector-routed traffic, and it answers three questions per request: which model, which upstream, and which provider behind that upstream.
Subscription and OAuth traffic never resolves a routing profile. The credential-shape split is permanent, so nothing on these pages changes how a coding-tool seat behaves.
The decision record
Every keyed request emits a routing decision record, and it exists for every outcome -- denials and cache hits included:
| Field | Meaning |
|---|---|
requested_model | What the caller asked for. Empty when the caller named no model. |
decided_model | What the gateway resolved and gated on. |
served_model | What actually answered, parsed from the upstream's response. Empty on a denial or a cache hit. |
decided_upstream | Which registered upstream connector served. |
served_provider | Which provider behind that upstream actually answered. |
routing_switch_reason | Why the served model differs from the decided one. |
routing_override | Which override fields the caller applied. |
routing_degraded | What the gateway could not express to the upstream and proceeded without. |
That record is what makes "requested versus decided versus served" answerable after the fact, which is the whole point: a model swap you did not intend should be visible in the data before it is visible in the invoice.
What routing does and does not do
Routing decides which model answers. It does not rewrite a request's content -- that is the optimization side, which is governed separately by the profile's own optimization setting. And it does not decide whether a request may spend: that is guardrails, applied after the routing decision and on the decided model.
Where routing behaviour comes from
| Mechanism | Scope | Page |
|---|---|---|
| Routing profile | A named bundle scoped to a team, attached down a binding ladder | Routing profiles |
| Fallback chains and provider preferences | Fields on a profile | Fallbacks and providers |
| Auto mode | A profile flag plus a reserved model name | Auto mode |
dz_router override | One request | Per-request override |
| Model catalog | Global, read-only | Model catalog |
Two defaults worth knowing
A request that names no model resolves the merged default from the profile
ladder. If no rung configures one, the request fails with no_default_model
rather than receiving a platform default. An explicitly named model is never
substituted.
An anthropic/* decision that no rung gave a provider order is sent asking
for the Anthropic first-party endpoint first. Claude's automatic prompt-cache
breakpoints are guaranteed only there, and a request served by a resale endpoint
loses them with no error and no visible difference in the reply -- only in the
bill. It is a default, so it stands down the moment you express a preference of
your own: an explicit order, a non-empty allow list, or a deny naming the same
provider.
Session pinning
For a request that names no model, the router pins its first decision per session and reuses it for later turns of the same client-supplied session. A model you name explicitly is never pinned, and never governs a later turn that names none. A profile edit landing mid-conversation therefore does not swap the model, because swapping it would reset the provider's prompt cache invisibly.
The pin moves only on failure or fallback. That turn is treated as a representation break: it is recorded with its own cache-bust attribution and denied the cross-turn discount, because the newly-serving model's prompt cache is cold however identical the bytes are.
Pinning depends on a client-supplied session id: the
X-Dz-Session-Id header, or -- on Anthropic Messages
-- the client's own conversation id, which Claude Code already sends. On the
OpenAI and Gemini surfaces the header is the only source.
When routing refuses rather than degrades
The gateway distinguishes a preference it could not express from a restriction it could not enforce, and treats them differently:
| Kind | Example | Behaviour |
|---|---|---|
| Preference | A fallback chain, a provider ranking | Degrades. The request proceeds and the loss is recorded in routing_degraded. |
| Restriction | A provider allow or deny list | Refused. Serving anyway would route to a provider somebody forbade. |
| Content guardrails the upstream cannot apply | A delegated content filter | Refused, on the same rule with an extra reason: a filter that does not run leaves no trace at all. The request would succeed with unfiltered content and an entirely ordinary-looking response. |
| Auto | Delegated model selection an upstream cannot express | Refused, for a structural reason: a delegated decision carries no model to fall back to. |
Two more refusals exist because guessing would be worse than failing:
- A profile naming an upstream the installation has not enabled is refused, with no fallback to a default. A team routed somewhere it did not choose, with traffic working, hides the misconfiguration until the invoice arrives.
- A profile that could not be read at all, on an installation with more than
one upstream registered, is refused with a retryable
503 upstream_undeterminedrather than defaulted to the primary. Two exceptions, both because nothing is being guessed: an installation with exactly one registered upstream is not choosing between anything, and a stale profile is your own last-known answer and still routes.
Attribution
How spend is attributed to people, teams, departments, services and seats -- and which of those are records you curate versus values observed in traffic.
Routing Profiles
The named bundle that decides which model a request gets when it names none -- its fields, its binding ladder, and how the rungs merge.