Skip to main content
Version: 1.9.0

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. Create the API key from API Keys in DVARA Flightdeck. Flightdeck applies the signed-in user's role and active workspace. The key starts with gw_, and the full secret is shown exactly once; only a SHA-256 hash is persisted. See Data plane authentication for rotation and revoke flows.

Every /v1 request must carry a valid key. A missing header returns 401 api_key_required; a key absent from the store returns 401 invalid_api_key. Revoked and expired keys return their corresponding 401 codes. The former require-api-key switch was removed in 1.8.0.

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.

A supplied trace ID must contain at most 128 letters, digits, or ._:-. DVARA replaces an invalid value with a new trace ID rather than reflecting it into logs.

# 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_RESPONSE audit event (one per request through the data plane), and any other event types fired downstream by policy, PII, guardrail, MCP, or admin paths — trace_id lives on the access log line surrounding the event, so a single grep on the trace ID reconnects every layer
  • The X-Trace-ID response 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.

A supplied session ID uses the same 128-character and [A-Za-z0-9._:-] contract. DVARA ignores an invalid session ID, so the request is not joined to that session.

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.

X-Dvara-End-User and X-Dvara-Tags (MCP and A2A)​

Name the customer a tool call or an agent call is for, and tag it, so its activity adds up with that customer's model calls. This is the MCP and A2A version of the chat request's user field and metadata.tags.

X-Dvara-End-User: cust-42
X-Dvara-Tags: customer=acme,booking=B-1042

You can send the same values inside the protocol message instead. In MCP, put them in params._meta. In A2A, put them in params.metadata or the message's metadata. The keys are dvarahq.com/end_user (a string) and dvarahq.com/tags (an object). A header wins when both name the same tag.

  • At most 16 tags. A key is up to 64 letters, digits or _ . : -. An end user or a tag value is up to 128 letters, digits or _ . : @ + / = -.
  • DVARA refuses a value it cannot accept: MCP answers -32602 (MCP_ATTRIBUTION_INVALID), and A2A answers invalid params. It never drops a value without telling you.
  • DVARA records the values as tags: your tags, the end user as user, and the session as session. These are the same tags a model call gets, so one tag value reads the same across model calls, tool calls and agent calls.
  • These values are what your application says. They do not prove who the caller is. Send an opaque customer id, not a name or an email address.

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.

HeaderDistributionWhen emittedWhat it means
X-Trace-IDBothAlwaysThe 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 / MISSBoth for exact cache; Enterprise for semantic matchingCache configuredWhether the response came from a cache rather than the provider. A HIT avoids the upstream call. Semantic similarity matching is Enterprise-only.
X-Gateway-Strict-Downgraded: trueBothresponse_format: json_schema with strict: true against Anthropic or AWS BedrockThe provider cannot enforce strict JSON Schema; validate on the client if strictness is load-bearing.
X-Gateway-Failover-Blocked: capability_mismatchBoth503 failover_capability_mismatchThe primary failed and no fallback supports the requested capability.
X-Budget-Remaining-Pct, X-Budget-Remaining-TokensEnterpriseA workspace has a budget capRemaining percentage and estimated token buying power.
X-Budget-Warning: trueBothA policy returned WARN_AGENTA policy warning, despite the historical header name; it is not a budget signal.
X-Context-Window-Warning, X-Context-Window-UtilizationBothApproaching the context windowEstimated input tokens crossed the configured warning threshold.
X-Gateway-Pii-UnresolvedEnterpriseResponse detokenization left placeholdersCount of unresolved request placeholders in the reply.
Retry-After, X-RateLimit-Retry-After-SecondsBothA rate limiter returns 429Backoff time in the standard and seconds-only forms.
X-RateLimit-Tokens-Limit, X-RateLimit-Tokens-Remaining, X-RateLimit-ResetBothToken-budget branch returns 429Active token limit, remainder, and reset time.

From 1.8.2 DVARA no longer sends X-License-Warning. Licence expiry never changes a response, so it is reported in DVARA Flightdeck, in LICENSE_* audit events, and on GET /actuator/license instead. See Get and apply a license.

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:

  1. Your application's structured logs
  2. Your tracing backend (Jaeger, Tempo, Honeycomb)
  3. DVARA's tamper-evident audit trail
  4. 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​