Stav's response headers are the per-request receipt. They are how you answer "which model served this", "under which jurisdiction", and "why did the router pick that" without opening a portal.
These are on every successful inference response. Error responses do not carry X-Stav-* headers.
Always present
| Header | Example | Meaning |
|---|---|---|
X-Stav-Request-Id | chatcmpl-8f3a1c… | The request identifier. Same value as the completion id. Quote it in support requests |
X-Stav-Model | claude-sonnet-4-5-20250929 | The model that actually served — not what you asked for |
X-Stav-Provider | anthropic | The provider that served |
X-Stav-Model-Type | routed_commercial | How the model that served is classified. Commercial models proxied through Stav report routed_commercial |
X-Stav-Sovereignty-Level | L3 | The effective ladder level of the serving endpoint: L0–L4 or UNCLASSIFIED |
X-Stav-Route-Time-Ms | 31 | Streaming: time from handler start to provider dispatch. Non-streaming: total handler latency including the provider round-trip. Do not compare the two |
X-Stav-Route-Reason | Explicit model selection: gpt-4o-mini | One-line rationale. Present on pinned requests too, where it simply restates the selection |
Conditional
| Header | Emitted when | Meaning |
|---|---|---|
X-Stav-Router | a named or default router handled the request | @team-slug/router-slug |
X-Stav-Inference-Tier | the serving endpoint has a tier | The tier of the endpoint that served — whether or not you asked for one. Compare it against the suffix you sent rather than treating it as confirmation |
X-Stav-Session-Id | a KV-cache session hash was computed | Prefix-cache affinity hash |
X-Session-Id |
Rate limiting
On a 429 from Stav's per-key limiter. The admission-queue 429 carries Retry-After only, and an upstream provider 429 passed through carries whatever the provider sent:
| Header | Meaning |
|---|---|
Retry-After | Seconds to wait |
X-RateLimit-Limit | Requests per minute for this key |
X-RateLimit-Remaining | 0 when limited |
X-RateLimit-Reset | Unix timestamp of the window reset |
Request headers Stav reads
| Header | Purpose |
|---|---|
Authorization: Bearer … | Your API key |
x-api-key | Alternative credential header (Anthropic SDK compatibility) |
X-Title | Application name for attribution. Matched against the app catalogue |
X-Stav-App-Id | Exact app UUID from Connect → Apps. An invalid value is rejected with 400 invalid_app_attribution rather than being ignored |
HTTP-Referer | Secondary attribution signal (OpenRouter convention) |
Reading them from SDKs
Python — OpenAI
raw = client.chat.completions.with_raw_response.create(
model="auto",
messages=[{"role": "user", "content": "hei"}],
)
print(raw.headers["X-Stav-Model"])
print(raw.headers["X-Stav-Sovereignty-Level"])
print(raw.headers.get("X-Stav-Route-Reason"))
resp = raw.parse()
TypeScript — OpenAI
const { data, response } = await client.chat.completions
.create({ model: "auto", messages })
.withResponse();
console.log(response.headers.get("x-stav-model"));
console.log(response.headers.get("x-stav-sovereignty-level"));
Python — Anthropic
raw = anthropic_client.messages.with_raw_response.create(
model="claude-sonnet-4-5-20250929",
max_tokens=256,
messages=[{"role": "user", "content": "hei"}],
)
print(raw.headers["X-Stav-Sovereignty-Level"])
Patterns worth adopting
Log the receipt, not the request. Store X-Stav-Request-Id, X-Stav-Model and X-Stav-Sovereignty-Level alongside your own trace id. When a question arrives six months later — about cost, about quality, about jurisdiction — you can answer it from your own logs and confirm against Stav's.
Alert on unexpected levels. If your team runs an L3 floor, X-Stav-Sovereignty-Level should never read L0 on a routed request. Treat UNCLASSIFIED as an alert too — it means an endpoint reached you that has not been assessed. A single occurrence means something drifted; catch it in your own telemetry rather than in an audit.
Watch lifecycle headers in CI. Endpoint deprecation headers are the earliest warning that a pinned model is going away. A test that fails when they appear turns a future outage into a ticket.
Do not parse X-Stav-Route-Reason. It is human-readable prose and will change. The structured decision lives in the routing log.
Streaming caveat
On a streaming response, headers are committed before the first chunk. If a first-chunk failover occurs, X-Stav-Model may name the model that was tried first while the chunk bodies name the one that served. When the two disagree on a streaming response, trust the chunk model field.