Every Cova-* header you can send, and every one Cova sends back.
The CoreValue gateway uses Cova-* headers for request-side configuration and
returns Cova-* headers on every response. Header matching is case-insensitive
(the gateway lowercases header keys before comparison), but the canonical names
below are recommended.
All examples below use the placeholder key sk-cova-XXXXXXXXXXXXXXXX and the
gateway base URL https://gateway.corevalue.dev. Authentication is always
Authorization: Bearer <COVA_API_KEY> — see
Authentication.
Which of your customers a request was made on behalf of, for per-customer unit economics. Promoted to an indexed customer_id column, so cost can be grouped by customer without scanning the properties map.
Validation
Truncated at 256 characters. Whitespace-only values are ignored.
Which of your teams the spend belongs to. Cost attribution only — this header never affects what anyone can see. Access is decided from the credential, so tagging a request with another team's id changes the invoice split, not the audience.
Validation
Truncated at 256 characters. Whitespace-only values are ignored.
Example
Cova-Team-Id: platform
These three are self-reported: the gateway records what you send. A key
scoped to customers checks Cova-Customer-Id
against its list, and a key scoped to one customer fills it in. Team budgets
and chargeback use the key's team, never Cova-Team-Id.
They cannot be forged by a caller supplying a matching Cova-Property-*
header. Property names have their hyphens replaced with underscores, so
Cova-Property-Cova-Customer-Id is stored as cova_customer_id and can
never collide with the literal Cova-Customer-Id these are read from.
Whether a person or a program produced this turn. Cost per model is a commodity; cost per actor is what makes an agent fleet governable, and you cannot budget for something you cannot name.
Validation
One of human, agent, unknown. Sanitized as an identifier, then matched exactly. An unrecognised value is not coerced to unknown: the request falls through to the heuristic below, since a misspelled header is no reason to discard evidence the payload still carries.
Example
Cova-Actor: agent
When the header is absent, the gateway infers the answer from the payload. The
signal is not that tools exist — people chat with search and code interpreters
enabled all day, and a capability is not an actor. It is that the turn is a
continuation: the last thing in the conversation is a tool result being fed
back, which no person typed.
Dialect
Tail that reads as an agent continuation
OpenAI messages
last message role is tool or function
Anthropic / Bedrock messages
last message content contains type: "tool_result"
Google contents
last content parts contain functionResponse
Responses input
last item type is function_call_output
The heuristic under-counts agents, by roughly one turn per run. The first
turn of an agent run is identical to a person asking a question of a
tool-enabled assistant, because at that moment it is the same request. A
ten-turn loop is recorded as one unknown and nine agent; a one-shot agent
call is recorded as unknown outright.
This is the argument for sending the header. The heuristic gives coverage with
no integration work; the header gives correctness.
unknown is a real answer and never collapses into human. Treating "no
evidence of an agent" as "a person" is true for most workloads today and will
not stay true, and a default of human would silently reclassify the future as
the past.
Written by the gateway. Not read from your request.
Purpose
How the actor was determined: header if you declared it, inferred if the payload tail matched, none if there was no evidence. Recorded beside the value so the number is interpretable.
Validation
Sending this header has no effect. It is ignored rather than rejected.
Example
Appears in logs and filters as cova_actor_source, never as input
Accepting this inbound would let a caller assert its own provenance, declaring
header while sending none, which destroys the only thing the field is for.
"45% agent" means nothing if you cannot tell whether that is declared or
guessed, and the two carry very different error bars.
cova_actor and cova_actor_source are reserved property names. A
Cova-Property-cova_actor header, or Cova-Property-cova-actor which
sanitises to the same key, is dropped, so a caller cannot overwrite the
classification.
Both appear on the Requests page as the Actor column, and
as the Actor and Actor source filters.
Group related requests into one run, shown on the console's Runs page. Cova-Session-Id identifies the run, Cova-Session-Name labels it, and Cova-Session-Path places a request in the run's tree, for example /plan/search. See Runs.
Validation
Trimmed, then truncated at 256 characters. Blank values are ignored. A Cova-Property-* header cannot set or overwrite them.
Example
Cova-Session-Id: run_7f3a
A session cap limits what each
session on a key may spend. The id is whatever your application sends, so a
session cap bounds an honest or buggy agent only: a caller that sends a new id
gets a fresh cap.
Arbitrary key-value metadata attached to the request for filtering, segmentation, and analytics. Multiple Cova-Property-* headers are allowed per request.
Validation
Name: lowercased, hyphens converted to underscores, then [a-z0-9_], max 64 chars, so Cova-Property-Region is stored as region. Value: max 256 chars (truncated). Invalid names are silently dropped.
Header-based bucket rate-limit policy. Overrides the DB-configured policy when present. Parsed into capacity / window / unit / segment.
Validation
Must follow the format above. An invalid value is ignored, and the rate limits configured in the console apply.
Format
<quota>;w=<window seconds>;u=<request|cents>;s=<segment>. Only w=, u= and s= are read: a part spelled any other way, such as window=60, is ignored, and the window falls back to one hour.
JSON array of body keys to exclude from cache key computation (e.g. ignore user_id so different users share a cache entry).
Validation
Valid JSON string array. Invalid JSON is ignored (no keys stripped).
Example
Cova-Cache-Ignore-Keys: ["user_id","timestamp"]
Cache-Control (the standard HTTP header) also sets how long a cached
response is kept (s-maxage or max-age, max 365 days, default 7 days). It
is not a Cova-* header, but the cache reads it.
Gateway-generated request ID (UUID). Used for log correlation and /meta endpoint lookups.
When Set
On every response the gateway forwards from a provider (streaming and non-streaming). Also set on the forwarded upstream request. Not set on cache hits or on requests the gateway refuses.
Whether cross-provider translation was applied. "passthrough" (default) or "translated".
When Set
On every response the gateway forwards from a provider. "translated" when the request was converted to another provider's format: an anthropic/, google/ or bedrock/ model on /gateway/v1.
Number of retry attempts made before the request succeeded. Set by the retry executor for observability.
When Set
Set when gateway-configured retries are enabled (env-configured server-side) and at least one retry was attempted. Absent on first-try success or when retries are disabled.
When the gateway processes a streaming request, it appends one final SSE event
after the upstream stream closes (including after data: [DONE] for
OpenAI-format providers).
The frame is a single SSE data: line terminated by \n\n (two newlines).
The JSON payload is nested under a "cova" key so the SDK can detect it by
checking "cova" in lastChunk.
The fields the CoreValue TypeScript and Python SDKs return:
Field
Type
Source
requestId
string
Cova-Id header
provider
string
Cova-Provider header
model
string
Cova-Model header
status
"success" | "error"
Cova-Status header
requestCost
number?
Cova-Request-Cost (non-streaming) or final SSE event (streaming) or /meta endpoint
estimatedCost
number?
Cova-Request-Cost-Estimate (upfront, all responses)
creditsRemaining
number?
Cova-Credits-Remaining
gatewayMode
"passthrough" | "translated"?
Cova-Gateway-Mode
translationWarning
string?
Cova-Translation-Warning (comma-separated list of dropped fields, only when translated)
In the streaming final SSE frame, requestCost is set only when
usage.costUsd > 0. If no usage was extracted (e.g. upstream errored), the
field is absent and the SDK should fall back to the /meta endpoint.
For streaming requests, cost and credit fields are not available as response
headers. Use the /meta endpoint to retrieve the CovaGatewayMeta after the
stream completes: