openrouter_metadata field to successful responses, capturing exactly what the router did. It’s intended for debugging routing decisions, attributing latency or cost, and auditing pipeline behavior.
Enabling Router Metadata
Opt in by sending theX-OpenRouter-Metadata request header with the value enabled:
Accepted Values
The header accepts the following values, matched case-insensitively:| Value | Behavior |
|---|---|
enabled | Surface openrouter_metadata on the response. |
disabled | Do not surface metadata. Equivalent to omitting the header. |
disabled. The default behavior — when the header is absent — is disabled.
Supported Endpoints
Router metadata is wired into every public completion route:/api/v1/chat/completions(OpenAI Chat Completions)/api/v1/messages(Anthropic Messages)/api/v1/responses(OpenAI Responses)/api/v1/completions(legacy text completions)
openrouter_metadata is delivered on the final chunk before data: [DONE] (Chat Completions / Responses) or as part of the terminal message_stop event (Anthropic Messages).
Response Shape
When opted in, successful responses include anopenrouter_metadata object alongside the rest of the response payload:
Field Reference
| Field | Type | Description |
|---|---|---|
requested | string | The model slug (or alias) the client sent. May differ from the provider/model that actually served the request. |
strategy | string | Routing strategy used: direct, auto, free, latest, alias, fallback, pareto, bodybuilder, fusion. |
region | string | null | Edge region that handled the request, when available. |
summary | string | Human-readable one-liner describing the routing decision (e.g. candidate count, selected provider). |
attempt | integer | 1-indexed attempt number that succeeded. Greater than 1 means earlier attempts failed and fell back. |
is_byok | boolean | Whether the request used a Bring-Your-Own-Key provider key. |
endpoints | EndpointsMetadata | Snapshot of endpoint candidates considered, and which one was selected. |
params | RouterParams | Optional. Router-level parameters that influenced selection (e.g. quality_floor, throughput_floor). |
attempts | Attempt[] | Optional. Per-attempt provider/model/status when the router retried against fallbacks. |
pipeline | PipelineStage[] | Optional. Plugins that materially altered the request or response (compression, guardrails, healing, server tools, etc.). |
OpenRouterMetadata in the OpenAPI spec, including SDK type definitions for TypeScript and other generated clients.
Pipeline Stages
Thepipeline array records every plugin that materially affected the request. A plugin only emits a stage when it actually ran; a no-op plugin (e.g. context compression that found the input already fit the budget) is omitted. Today’s stage types include:
type | name values | What it tells you |
|---|---|---|
guardrail | content-filter, moderation | flagged: bool, plus engine-specific verdict (decision, confidence_level, matched_entity_types, etc.). |
plugin | web-search, file-parser | Plugin-specific telemetry (e.g. result counts for web search, page count for file parsing). |
server_tools | server-tools | Mode (native / sdk) and the list of tools invoked. |
response_healing | response-healing | Mode (json_schema / json_object), whether healing improved the response, lengths. |
context_compression | context-compression | Engine used, input type (messages / prompt), original vs. compressed counts. |
type. To find a specific guardrail (say, the content filter), iterate the array and match on both type === 'guardrail' and name === 'content-filter'. The full set of guardrail-level plugins emits type: 'guardrail' so you can filter all of them together (pipeline.filter(s => s.type === 'guardrail')) without enumerating individual plugins.
The list grows over time. Treat unknown stage types as opaque — data is a free-form record by design so plugins can attach plugin-specific telemetry without a schema bump.
Cache Hits
Cache hits never includeopenrouter_metadata. Both streaming and non-streaming cache replays strip the field so clients cannot pin behavior on stale routing data. This is intentional: the metadata you see on a cache miss may not reflect the routing that produced the cached payload.
Error Responses
Opt-in error responses surfaceopenrouter_metadata at the top level of the error envelope, mirroring the success-path placement (sibling of error rather than nested inside it). This applies to all four routes — Chat Completions, Messages, Responses, and legacy Completions — and to both streaming and non-streaming requests. The same opt-in rules apply: send X-OpenRouter-Metadata: enabled and the snapshot is included on failure; omit it and it isn’t.
No Providers Available (404)
Guardrail Blocked (403)
When a request is blocked before reaching a provider — for example by a content filter or prompt-injection detector configured via guardrails — the response includes the fullopenrouter_metadata object with routing context and a pipeline array showing every guardrail stage that ran, including the one that blocked:
selected and the optional attempts array is absent.
A few things to know:
attemptreflects how far the router got. A value of0means the request never reached a provider — typically because every candidate was filtered out before submission (e.g.provider.onlyexcluded the last endpoint, or an allowed-providers / max-price filter rejected everything). Values≥ 1mean every attempted provider failed and fallbacks were exhausted.- No endpoint is marked
selectedon failure. None of theendpoints.available[].selectedflags aretruebecause no endpoint actually served a 200. - Internal-error masking still applies. Responses with a
500status are scrubbed to a generic message, andopenrouter_metadatais omitted from those envelopes by design — we don’t surface internal routing details on errors whose cause is already hidden. Other 5xx classes (502,503,504,529) still include the metadata when the client opted in. - Some failure modes won’t carry it. Authentication / rate-limit failures and other errors that fire before the router has usable routing state (for example, validation rejections at the API edge) will not include the field. If you need post-mortem routing context for a request that completed past the API edge but before the router materialised state, fetch the generation record via
GET /api/v1/generationusing theX-Generation-Idresponse header.
Stability
Theopenrouter_metadata response shape is additive — new optional fields and pipeline stage types may appear without a deprecation cycle, but existing fields are stable. Decode permissively (ignore unknown fields and stage types) and your integration will be forward-compatible.
Legacy Header
The previous header nameX-OpenRouter-Experimental-Metadata is still accepted for backward compatibility. We recommend migrating to X-OpenRouter-Metadata at your convenience.