Speko Docs
RouterRouting

Headers

Per-request headers, how they beat the key policy, and what the response tells you.

Routing controls ride in headers, never in the body, so an OpenAI client stays untouched. Put them on the key instead and you send none of these — see keys and policy.

Request headers

HeaderValueEffect
X-Speko-Objectivelatency, cost, quality, balancedWhich axis the ranking optimizes.
X-Speko-LanguageBCP 47 tag, e.g. es-COWhich board ranks candidates, and whether TTS accent narrowing applies.
X-Speko-AllowComma-separatedRestrict candidates to these.
X-Speko-DenyComma-separatedRemove these from consideration.
X-Speko-Max-PriceNumberDrop candidates above this price.

Allow and deny entries take a provider (every model from that vendor) or a provider:model:

X-Speko-Allow: cartesia,elevenlabs:eleven_v3
X-Speko-Deny: openai
X-Speko-Objective: latency

What beats what

  1. A request header beats the key policy for objective, language and max price.
  2. X-Speko-Allow disables the key's chain entirely — the allowlist becomes the candidate set. This is how you override a pinned key for one call.
  3. Deny and max-price beat even a pin. A pinned model that is denied, or too expensive, is not a candidate.
  4. A model with no provider credential is never a candidate — filtered before ranking, even if you allowlisted it. Allowing only unavailable models gives 503 no_candidate.

For TTS the accent also participates; full ordering is in languages and accents.

Response headers

HeaderValue
x-routeProvider/model that actually served the request.
x-route-reasonWhy this candidate, including the ranking evidence class.
x-speko-failover-countHow many candidates failed first. 0 means the first choice worked.
x-speko-first-byte-msTime to first byte from the winning upstream, router-side.

x-speko-first-byte-ms appears on success only — the requests you most want to trace are the ones without it. Read x-speko-failover-count and the error's details.attempts instead.

It measures the router's wait on the upstream, not your first sample. On a streaming route the two differ by the network leg to you, so time the first chunk client-side as well.

x-route names the provider and the model on every HTTP route. The realtime sockets send a ready frame carrying provider only, so a model-level pin cannot be confirmed there.

Pin ids come from the API

GET /v1/models is public. The id values it returns are exactly what you write into a key chain, an X-Speko-Allow entry, or a body model. Copying an id from a vendor's own docs instead is how you get 400 unsupported_model.

GET /v1/routing/preview returns the candidate the router would pick without calling a provider or costing anything. Parameters for both are in the API reference.

On this page