# HTTP headers

The complete wire-header contract for TokenTriage — every request header a client may send and every response header the proxy emits, with exact names, values, and meaning.

Source: https://tokentriage.com/docs/reference/headers

---
import Callout from '../../../components/Callout.astro';
import NextSteps from '../../../components/NextSteps.astro';

The consolidated reference for every TokenTriage wire header. All identity, dimension,
and cache-control headers use the `x-tt-*` namespace. Names, casing, and values below are
verified against the proxy source.

<Callout type="key">
Every `x-tt-*` header is **stripped before the request is forwarded upstream** — the
provider never sees them. Trace/dimension identity comes *exclusively* from explicit
request headers; `traceparent` is logged for correlation but is **never** used to infer
identity, and inbound `x-tt-request-id`, `x-tt-team`, and `x-tt-key` are never trusted
(the proxy mints / stamps its own).
</Callout>

## Request headers

What the client may send. Opaque identity values are capped at **128 bytes** (truncated at
the byte boundary); longer values are silently truncated, never rejected.

| Header | Values / example | Meaning |
|---|---|---|
| `x-tt-trace-id` | opaque, ≤128 B — e.g. `run-a1b2c3d4e5f6` | Groups requests into one agent trace. The one header that turns rows into a trace. |
| `x-tt-step-id` | opaque, ≤128 B — e.g. `step-9f8e7d6c` | Identifies the step within the trace; enables the per-step cost tree (`top --trace ID`). |
| `x-tt-parent-id` | opaque, ≤128 B | Parent step id — draws the sub-agent fan-out edges. Set to the spawning step's `x-tt-step-id`. |
| `x-tt-agent` | e.g. `planner`, `coder`, `Task:code-reviewer` | Logical agent / sub-agent name. Drives `top --by agent`. |
| `x-tt-step-class` | `user_turn` \| `tool_loop` \| `provider_state` | Explicit step class. When absent the proxy derives a guess from structure and records `step_class_source: derived`. Informs routing, never identity. |
| `x-tt-tier` | tier name — e.g. `cheap`, `frontier` | Explicit tier override. Honored in `route` mode; logged in all modes; overrides affinity pins. Header **name is configurable** (`routing.overrides.tier_header`); `x-tt-tier` is the default. |
| `x-tt-user` | opaque, ≤128 B | First-class **user** business dimension (`dims.user`). Requires `ledger.dimensions.enabled: true`. |
| `x-tt-tenant` | opaque, ≤128 B | First-class **tenant** dimension (`dims.tenant`) — the unit-economics / budget group-by. |
| `x-tt-feature` | opaque, ≤128 B — e.g. `chat`, `autocomplete` | First-class **feature** dimension (`dims.feature`). |
| `x-tt-tag-<k>` | key `<k>` ≤32 B, value ≤128 B | Free-form tag `k = value`. Bounded to `ledger.dimensions.max_tags` per request (default 8), admitted in sorted key order; excess dropped-and-counted. |
| `x-tt-cache` | `off` \| `refresh` \| `no-store` | Client cache control. `off` = bypass read + write; `refresh` = bypass read, allow write (force-refresh); `no-store` = serve hits, skip write. Absent / `none` = normal. |
| `traceparent` | W3C trace-context string | Logged as `trace.w3c` for correlation. **Never** used to stitch identity. |
| `x-llm-d-slo-ttft-ms` | integer ms (alias `x-slo-ttft-ms`) | Time-to-first-token SLO hint. Parsed and logged only; v1 never acts on it. Current name wins over the deprecated alias. |
| `x-llm-d-slo-tpot-ms` | integer ms (alias `x-slo-tpot-ms`) | Time-per-output-token SLO hint. Parsed and logged only. |
| `Authorization` | `Bearer <token>` | Inbound credential. The bearer token is resolved to a governance Principal (team / key dims, scopes, budgets). |
| `x-api-key` / `api-key` / `x-goog-api-key` | raw key value | Alternative credential carriers, checked in that order when `Authorization` is absent. |

<Callout type="warning">
`x-tt-team` and `x-tt-key` are **server-stamped only**. If a client sends them inbound they
are stripped and never read as an assertion — the proxy stamps the resolved key's team node
and key id itself (dims-authority: *stamped beats asserted*). `x-tt-request-id` is likewise
stripped inbound; TokenTriage always mints its own.
</Callout>

## Response headers

What the proxy emits. All are cheap to eyeball with `curl -i`.

```console
$ curl -i http://127.0.0.1:8787/v1/messages -H 'x-tt-trace-id: run-1' ...
```

| Header | Values / example | Meaning |
|---|---|---|
| `x-tt-request-id` | e.g. `tt_abc123` | Per-request id, always emitted (when non-empty). **The join key**: equals the decision-log row's `req_id` and the SDK receipt id. |
| `x-tt-mode` | `shadow` \| `route` | Effective engine mode. Emitted only in shadow/route modes; **absent** in ledger mode. |
| `x-tt-decision` | tier name — e.g. `frontier` | Chosen tier in shadow/route modes. Omitted when no tier was chosen (e.g. a passthrough). |
| `x-tt-model-rewrite` | `<from>-><to>` — e.g. `gpt-5->claude-haiku-4-5` | Emitted only when a model rewrite actually occurred (both ends non-empty). |
| `x-tt-cache` | `hit` \| `miss` \| `bypass` \| `error` | Cache **serving status** — what the client received. Set on every cache-eligible request (no off switch). A shadow `would_hit` pairs with `miss` (the response was a live passthrough). |
| `x-tt-cache-kind` | `exact` \| `normalized` \| `semantic` | Match kind (hit only). `semantic` is a probabilistic match, always disclosed with its score + threshold below. |
| `x-tt-cache-age` | integer seconds — e.g. `42` | Age of the served entry (hit only). |
| `x-tt-cache-source` | source `req_id` | The `x-tt-request-id` of the original row that populated this entry (hit only) — provenance join to the source row. |
| `x-tt-cache-entry` | entry id | The cache entry identifier (hit only). |
| `x-tt-cache-similarity` | float `0`–`1` | Similarity score. **Semantic hit only.** |
| `x-tt-cache-threshold` | float `0`–`1` | The threshold the score was tested against. **Semantic hit only.** |
| `x-tt-cache-verified` | `true` \| `false` \| `none` | Verifier verdict (`none` = no verifier ran). **Semantic hit only.** |
| `x-tt-coordination` | `suspended` | Presence flag: this request's admission carried a verdict-level suspension (a fail-open governance fallback). **Emitted only when degraded** — a healthy / single-node / air-gapped request omits it entirely (there is no `ok` value). |
| `x-tt-refused-by` | firing `limit_id` | On a governance refusal, names the limit that fired. Omitted on a 401 (no existence oracle). |
| `x-tt-refusal-type` | see values below | On a governance refusal, the closed refusal-type vocabulary — also `error.type` in the JSON body. Rides **every** refusal. |
| `Retry-After` | integer seconds | On a `429` / `503` refusal only, rounded **up** to whole seconds. |
| `RateLimit` | `"<limit_id>";r=0;t=<reset>` | IETF structured field on a `429` refusal (when a limit id is known). |
| `RateLimit-Policy` | `"<limit_id>";q=<limit>` | IETF policy field on a `429` whose firing limit reports a genuine integer cap — in practice `concurrency_exceeded`. **Suppressed** for budget/quota (`budget_usd` / `quota_*`) limits (a raw nanodollar/token `q` would misrepresent an IETF request-quota), and **not present** on an `rpm` `rate_limited` refusal (its store can't cheaply report countable numbers). |

### `x-tt-refusal-type` vocabulary

The closed set of refusal types and their HTTP status:

| `x-tt-refusal-type` | Status | Meaning |
|---|---|---|
| `invalid_key` | `401` | Unknown / revoked / expired key (uniform message; no `refused_by` on the wire). |
| `scope_violation` | `403` | Requested model / provider / endpoint is outside the key's scope. |
| `rate_limited` | `429` | An rpm rate-class limit fired. |
| `quota_exhausted` | `429` | A token / request quota is exhausted. |
| `budget_exceeded` | `429` | A USD budget is exhausted. |
| `concurrency_exceeded` | `429` | A concurrency (in-flight) cap is full. |
| `quota_cost_unfittable` | `429` | The request's cost can never fit under the limit (typed refusal, not an infinite retry loop). |
| `enforcement_unavailable` | `503` | A fail-closed limiter is down. |

<Callout type="note">
Every governance refusal writes headers, body, and the decision-log `refused_by_limit`
block from **one** value — so `x-tt-refused-by` / `x-tt-refusal-type` on the wire are
byte-consistent with the row (row == wire by construction). The full breach detail
(`observed`, `limit`, `node`, `resets_at`, enforcement `bound`) lives in the JSON body and
the ledger row.
</Callout>

<NextSteps items={[
  { title: "Observability", href: "/docs/build/observability", description: "Join the x-tt-request-id back to the decision-log row and receipts." },
  { title: "Response caching", href: "/docs/build/caching", description: "How the x-tt-cache control and the hit-disclosure headers behave." },
  { title: "Ledger fields", href: "/docs/reference/ledger-fields", description: "The decision-log row the response headers mirror, field by field." },
]} />
