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:

FieldMeaning
requested_modelWhat the caller asked for. Empty when the caller named no model.
decided_modelWhat the gateway resolved and gated on.
served_modelWhat actually answered, parsed from the upstream's response. Empty on a denial or a cache hit.
decided_upstreamWhich registered upstream connector served.
served_providerWhich provider behind that upstream actually answered.
routing_switch_reasonWhy the served model differs from the decided one.
routing_overrideWhich override fields the caller applied.
routing_degradedWhat 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

MechanismScopePage
Routing profileA named bundle scoped to a team, attached down a binding ladderRouting profiles
Fallback chains and provider preferencesFields on a profileFallbacks and providers
Auto modeA profile flag plus a reserved model nameAuto mode
dz_router overrideOne requestPer-request override
Model catalogGlobal, read-onlyModel 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:

KindExampleBehaviour
PreferenceA fallback chain, a provider rankingDegrades. The request proceeds and the loss is recorded in routing_degraded.
RestrictionA provider allow or deny listRefused. Serving anyway would route to a provider somebody forbade.
Content guardrails the upstream cannot applyA delegated content filterRefused, 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.
AutoDelegated model selection an upstream cannot expressRefused, 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_undetermined rather 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.

On this page