DVARA headers — request and response reference
DVARA is an AI governance platform, so every /v1/* request is already audited with a server-generated trace ID. The headers below let you authenticate, correlate the audit trail with your own request identifiers, and read the signals DVARA emits back on the response.
Request headers
Authorization: Bearer gw_…
Required on every data-plane request. The API key is minted in the DVARA Flightdeck (/portal/keys for workspaces, /workspaces/{id}/keys for operators) and starts with gw_. The full secret is shown exactly once at creation time — only a SHA-256 hash is persisted server-side. See Data plane authentication for rotation and revoke flows.
A key that is presented must be valid, whatever the posture. dvara.llm-gateway.data-plane.require-api-key governs one narrower question — whether a request may arrive with no key at all — and the two cases return different codes:
| request | require-api-key=false (default, development) | require-api-key=true |
|---|---|---|
no Authorization header | 200, served as anonymous | 401 api_key_required |
| a key absent from the store | 401 invalid_api_key | 401 invalid_api_key |
Measured on 1.7.0 in both postures. The second row is what changed in 1.7.0: a wrong key used to be served as anonymous under the permissive default, which was the one credential failure a caller could not detect — the response was a 200 while the request carried no workspace, so budgets, PII action, rate-limit overrides and strict-BYOK silently did not apply. Sending no key and sending a wrong key are different acts, and only the first is a development convenience.
X-Trace-ID
Pass X-Trace-ID for distributed tracing correlation. DVARA resolves the trace ID in this order: (1) client-supplied X-Trace-ID / X-Trace-Id header, (2) the OTel trace ID from the current span when OpenTelemetry tracing is active, (3) a random UUID. The chosen value lands on the audit event, the SLF4J MDC, and is echoed back as the X-Trace-ID response header.
# Python (OpenAI SDK)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
extra_headers={"X-Trace-ID": "my-trace-123"},
)
// TypeScript (OpenAI SDK)
const response = await client.chat.completions.create(
{
model: "gpt-4o",
messages: [{ role: "user", content: "Hello" }],
},
{ headers: { "X-Trace-ID": "my-trace-123" } },
);
// Java (LangChain4j)
OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("http://localhost:8080/v1")
.apiKey("your-dvara-api-key")
.modelName("gpt-4o")
.customHeaders(Map.of("X-Trace-ID", "my-trace-123"))
.build();
The same trace ID will appear on:
- The
GATEWAY_RESPONSEaudit event (one per request through the data plane), and any other event types fired downstream by policy, PII, guardrail, MCP, or admin paths —trace_idlives on the access log line surrounding the event, so a single grep on the trace ID reconnects every layer - The
X-Trace-IDresponse header DVARA sends back to you - The OTLP span emitted for the request (when tracing is enabled)
X-Session-Id
Pass X-Session-Id for agent session tracking. DVARA groups requests sharing a session ID into a single agentic session, which activates loop detection, approval gates, and session-level audit grouping.
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Continue our conversation"}],
extra_headers={"X-Session-Id": "agent-session-456"},
)
const response = await client.chat.completions.create(
{
model: "gpt-4o",
messages: [{ role: "user", content: "Continue" }],
},
{ headers: { "X-Session-Id": "agent-session-456" } },
);
OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("http://localhost:8080/v1")
.apiKey("your-dvara-api-key")
.modelName("gpt-4o")
.customHeaders(Map.of("X-Session-Id", "agent-session-456"))
.build();
Sessions appear in the DVARA Flightdeck under Agents → Sessions, where you can see loop-detection status, kill a runaway session, or drill into every request the session produced.
Response headers
DVARA stamps response headers to signal in-band conditions that don't justify a non-2xx but a well-behaved client should react to. None of these break the OpenAI wire format; they layer on top.
| Header | When emitted | What it means |
|---|---|---|
X-Trace-ID | Always | The trace ID DVARA resolved for the request — echo it in your application logs to grep across the audit, tracing, and provider-log layers. |
X-Cache: HIT / MISS | Always | Whether the response came from the semantic cache rather than the provider. A HIT books $0 — the served tokens are still recorded, but no upstream call happened so no cost record is written. Note the default matching: DVARA uses vectors as a prefilter but serves only on an exact cache-key match unless cache.semantic.similarity-serving is on, so a HIT means the same request, not a similar one. |
X-Gateway-Strict-Downgraded: true | response_format: json_schema with strict: true against Anthropic or AWS Bedrock | The underlying provider cannot enforce strict JSON Schema. DVARA still issues the tool-use rewrite, but a non-conforming response will not be rejected upstream — validate on the client if strictness is load-bearing. |
X-Gateway-Failover-Blocked: capability_mismatch | 503 failover_capability_mismatch | The primary provider failed and no fallback on the route supports the requested capability (e.g. all fallbacks are vision-blind for an image request). Add a capable fallback to the route or change the request. |
X-License-Warning | License is EXPIRING_SOON (≤30 days) or GRACE_PERIOD (expired, within 14-day grace) | The gateway is still serving traffic but the operator should renew. Surface this to SRE alerting so it doesn't fall to a degraded state. |
X-Budget-Remaining-Pct, X-Budget-Remaining-Tokens | Every request from a workspace that has a budget cap — not only once a threshold is crossed | Percentage of the cap still unspent, and roughly how many more tokens that buys at this model's price. Measured on 1.7.0: a workspace 0.4% into its cap gets X-Budget-Remaining-Pct: 100. Absent entirely when no cap governs the workspace, which is how you tell "no cap" from "cap with room left". |
X-Budget-Warning: true | A policy rule returned WARN_AGENT | Despite the name, this is not a budget signal. It is set when the policy engine warns rather than denies, and it fires with no budget cap configured at all. If you are alerting on budget pressure, read X-Budget-Remaining-Pct; if you are surfacing policy warnings to an agent, read this. |
X-Context-Window-Warning, X-Context-Window-Utilization | Approaching the model's context window | The estimated input tokens are over the per-workspace guardrail.context.warning-threshold-pct (default 70%). At the hard threshold a 400 context_window_exceeded is returned. |
X-Gateway-Pii-Unresolved | A response contained PII placeholders that could not be turned back into real values, and pii.auto-detokenize-response is on | The count of placeholders still in your reply. DVARA replaces personal data with a placeholder before sending your prompt to the provider, and swaps the real values back in on the way out. This header says how many it could not swap back — so the text you received still contains {{PII_TYPE_…}} markers rather than the original values. Only placeholders that were in your request are counted, so a marker the model invented does not inflate it. The header carries a count and nothing else: never the placeholder, never the value it stood for. Treat any non-zero value as a data-quality signal on that response — there is no human in this path to notice it for you. |
Retry-After, X-RateLimit-Retry-After-Seconds | 429 rate_limit_exceeded or 429 priority_throttled | Standard rate-limit backoff envelope on every 429 — Retry-After is the canonical HTTP header, X-RateLimit-Retry-After-Seconds is the same value in seconds-only for SDKs that don't parse Retry-After. Honor either to avoid hammering the window. |
X-RateLimit-Tokens-Limit, X-RateLimit-Tokens-Remaining, X-RateLimit-Reset | 429 rate_limit_exceeded when the token-budget branch tripped | Additional headers on the token-budget reject path (not the request-count reject path). The limit + remaining tell the client the per-key token budget and how close it was; X-RateLimit-Reset is the ISO-8601 instant the 60-second sliding window resets. Distinguish a token-budget 429 from a request-count 429 by checking these headers' presence, or by reading error.rate_limit.limited_resource in the body. |
The HTTP error envelope ({"error": {"type": "...", "code": "...", "message": "...", ...}}) is documented separately in Error handling.
Why this matters for governance
Trace IDs and session IDs are the join key between:
- Your application's structured logs
- Your tracing backend (Jaeger, Tempo, Honeycomb)
- DVARA's tamper-evident audit trail
- The upstream provider's request logs (via propagation)
Without them, when a policy fires a denial at 3 a.m. you know what was blocked but not which customer request triggered it. With them, one grep on the trace ID reconnects every layer of the stack.
Next steps
- Back to language-agnostic integration overview.
- Looking for examples by language? See Python, JavaScript / TypeScript, or Java.
- Debugging a specific response code? See Troubleshooting.