Request Headers
The X-Dz-* request headers that drive attribution, session identity and per-request routing, and the two headers the gateway returns.
Request Headers
Gateway controls ride X-Dz-* request headers rather than the request body, so
every official vendor SDK can drive them through a first-class, typed parameter
(default_headers and its equivalents).
Every X-Dz-* header listed here is stripped before the request is
forwarded upstream. The provider never sees them.
Attribution headers
These label a request so its cost can be attributed. All are optional.
| Header | Value |
|---|---|
X-Dz-User | Cost-attribution user. |
X-Dz-Team | Cost-attribution team. |
X-Dz-Project | Cost-attribution project. |
X-Dz-Env | Cost-attribution environment. |
X-Dz-Labels | Free-form labels, key1=val1,key2=val2. Malformed pairs are skipped rather than failing the request. |
Source headers
These record where a request came from, for correlating gateway traffic with the workload that produced it.
| Header | Value |
|---|---|
X-Dz-Namespace | Kubernetes source namespace. |
X-Dz-Workload | Kubernetes source workload. |
X-Dz-Pod | Kubernetes source pod. |
Behavioural headers
| Header | Value |
|---|---|
X-Dz-Session-Id | Your own conversation id. The router pins its first routing decision to it, so a mid-conversation profile edit cannot swap the model and reset the provider's prompt cache. |
X-Dz-Workload-Type | The workload type you are declaring. Used for per-workload cache scoping, and it is the axis evidence is grouped by. |
X-Dz-Router | The canonical carrier for the per-request routing override: the dz_router object as raw compact JSON, maximum 8192 bytes. |
Why the session id is worth sending
The session is the unit of this domain. It is resolved in precedence order:
- The
X-Dz-Session-Idheader you supplied. - A session id extracted from a recognised client surface.
- Auto-inference from the source pod, the system-prompt hash and a credential salt, within a sliding window.
Only the first is a stable session key -- one that came from you and is therefore comparable across turns. An inferred identity is recorded separately and never substituted for a client-supplied one, because it fragments a conversation: a reconnecting client presents the same conversation under a new identity, so an absent prior turn says nothing about whether a warm prefix existed.
Anything that reasons about a previous turn -- cache-miss classification,
cross-turn cache-bust pricing, holdout arm stickiness -- requires a stable
session key and falls back to "unknown" rather than guessing. Sending
X-Dz-Session-Id is the single cheapest thing you can do to improve the
quality of your own measurements.
X-Dz-Router rules
| Situation | Result |
|---|---|
| Sent once, valid JSON, known fields | Applied as the most specific rung of the routing ladder. |
Sent on the header and as the dz_router body field | 400 dz_router_conflict, even if the two are byte-identical. There is no precedence rule. |
| Sent twice as a repeated header | 400 invalid_dz_router. |
| Over 8192 bytes | 400 dz_router_too_large, with a message pointing at routing profiles -- the server-side mechanism for large steering configurations. |
| Carrying an unknown field | Refused, not ignored (invalid_dz_router). A typo must never silently do nothing. |
Response headers
Keyed inference responses carry two headers:
| Header | Value |
|---|---|
X-Dz-Request-Id | The id the trace and telemetry rows for this request are stored under. |
X-Cache | MISS, HIT or SEMANTIC-HIT. Stamped MISS before the cache is consulted and overwritten by whichever hit path serves, so the value is exhaustive. |
Both are emitted on keyed inference only. Passthrough traffic is forwarded byte-identically in both directions, so nothing is added there.