Per-Request Override

The dz_router override -- steering one request inside the routing modes your team already enabled.

Per-Request Override

dz_router is a caller's steer for one request. It is the fourth and most specific rung of the routing profile ladder, and it merges by the same field-by-field rule: a field you omit is inherited from your team's configuration, never cleared.

Carriers

The override rides exactly one of two carriers per request:

CarrierStatus
The X-Dz-Router request header, raw compact JSON, maximum 8192 bytesCanonical. Send it through your SDK's default-headers mechanism.
The dz_router body fieldCompatibility alias.

Presenting the override on both carriers is 400 dz_router_conflict -- even if the two are byte-identical. There is deliberately no precedence rule: two answers to one question is a bug in the caller, not an ambiguity to resolve.

Both carriers share one strict decoder. An unknown field is refused with invalid_dz_router rather than ignored, because a typo must never silently do nothing. The header is stripped with the other X-Dz-* headers before forwarding, and the body field is stripped before the body is forwarded.

Fields

FieldTypeMeaning
fallback_modelsarray of author/slug idsReplaces the configured fallback chain whole when non-empty; it is never appended to. Requires the profile to configure a chain or to enable auto.
provider_sortcost, latency or throughputProvider ranking for the decided model.
provider_orderarray of provider namesExplicit provider preference order.
provider_allowarray of provider namesProviders that may serve this request.
provider_denyarray of provider namesProviders that may not serve this request.
autoobjectPer-request auto-mode dials, forwarded to the auto resolver. Requires the profile to enable auto.
upstreamstringWhich registered upstream connector serves this request. An id the installation has not enabled is refused with 502 unknown_upstream.

There is deliberately no model field. The primary model stays the surface's own model field -- the override steers around it rather than replacing it.

The rule is that a caller may steer inside a substitution mode the team enabled, but may not enable one:

Override carriesProfile stateResult
auto dialsAuto enabledApplied.
auto dialsAuto not enabled400 routing_override_not_permitted.
fallback_modelsA chain or auto is configuredApplied, replacing the chain for this request.
fallback_modelsNeither is configured400 routing_override_not_permitted.
Provider preferencesAnyApplied. Preferences are steering rather than substitution, so they are not gated.

Provider enforcement is not the override's job either way: the boundary for which providers may serve remains the allowed_providers rule on your guardrail.

Raw upstream routing fields are refused

Do not send the upstream marketplace's own routing shapes. provider, models, route, transforms, preset and plugins are refused at the top level of every keyed inference body with 400 unsupported_routing_field. They never enter the API contract; dz_router is the only routing vocabulary the gateway accepts.

Examples

curl https://<your-gateway-host>/v1/chat/completions \
  -H "Authorization: Bearer sk-dz-..." \
  -H "Content-Type: application/json" \
  -H 'X-Dz-Router: {"provider_sort":"latency","provider_deny":["some-provider"]}' \
  -d '{
    "model": "anthropic/claude-sonnet-4-5",
    "messages": [{"role": "user", "content": "Hello"}]
  }'

In an SDK, send it through default_headers so it applies to every call from that client, or per call where your SDK supports per-request headers.

When to use a profile instead

An override is the right tool for a decision that genuinely belongs to one request. It is the wrong tool for standing configuration:

  • It is capped at 8192 bytes on the header, and an oversize value is refused with a message pointing at routing profiles.
  • It cannot enable a mode, so a large override is usually an attempt to configure something that should be configured once, server-side.
  • Which fields an override applied is recorded per request, so a fleet steering itself by header makes "why did this route here" a per-request question instead of a per-team answer.

See Routing profiles.

On this page