skip to content
Routing

Gateway

Routing

One endpoint in front of every model and every provider. The gateway picks the route, fails over when it has to, and tells you what served.

Conifer is one key and one base URL in front of every model in the catalog. Your request arrives on the OpenAI chat wire, the OpenAI Responses wire or the Anthropic Messages wire. The gateway checks the key, works out which provider should serve the model, sends the request there, retries elsewhere if that provider fails, and answers with a receipt that says which model served and what it cost. This page covers each of those in turn.

Named vs routed

A named request carries a catalog id, such as claude-haiku-4-5. That exact model answers, or the request is refused. Nothing cheaper is swapped in behind a 200. An id the catalog does not carry is a 404 model_not_found. A namespaced spelling such as anthropic/claude-opus-5 is accepted and served as claude-opus-5.

A routed request leaves the choice to Conifer. From any client, send beta-auto as the model and Conifer chooses the model for that turn from your routing pool, or send default for its default pin. beta-router explains the id and the receipt it produces.

Either way the receipt tells you what happened. x-conifer-requested-model is the id you sent and x-conifer-effective-model is the model that answered. Pinning a model in a tool, for example claude --model claude-haiku-4-5, is a named request and turns routing off for that tool.

Fig. 01named and routed

Two ways a request travels

A named id fails over between providers, and to another model only one you listed in x-conifer-fallback-models. A routed id lets Conifer choose the model.

named

  1. you sendclaude-haiku-4-5A catalog id. An id the catalog does not carry is a 404.
  2. the gatewayChecks the key and the balanceOver a ceiling you sent, a 402 before any provider is called.
  3. a providerThe best available hostOn a rate limit, error or timeout: the same model, another host. Then the ids in x-conifer-fallback-models, if you sent any, in order.
  4. the receiptas_requestedor provider_failover. x-conifer-effective-model names the model that answered.

routed

  1. you sendbeta-autoThe choice is left to Conifer.
  2. beta-routerPicks the model for this turnFrom your routing pool, or the catalog your key can call.
  3. a providerThe best available hostFailover works the same as for a named id.
  4. the receiptroutedx-conifer-effective-model names the model that answered.

The wire

Use whichever wire your client already speaks. Claude Code speaks Anthropic Messages, Codex speaks Responses, and almost everything else speaks OpenAI chat. All three are on the same host with the same key, so the only decision is the base URL. The OpenAI wires end in /v1 and the Anthropic wire has no suffix. See Replace your provider key for the two-line change.

One rule to know: /v1/messages serves Anthropic models only. Send a non-Anthropic id there and you get a 400 wire_upstream_mismatch. Every model in the catalog is available on the chat wire.

Providers and failover

Many models are served by more than one provider. You do not pick one. The gateway sends each request to the best available provider for that model, and if a provider rate-limits, errors or times out, it retries the same model with another. The price is the catalog price for the model whichever provider served it, and when a retry happened the receipt reason reads provider_failover. If no provider can serve the request, it fails and nothing is charged.

Failover never changes the model unless you ask for that. To name a chain of your own, send x-conifer-fallback-models with up to three catalog ids. They are tried in order after the model you named cannot be served, and whichever one answers is disclosed in x-conifer-effective-model.

terminal
curl https://api.conifer.build/v1/chat/completions \
  -H "Authorization: Bearer $CONIFER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "x-conifer-max-cost-nanousd: 50000000" \
  -H "x-conifer-fallback-models: claude-sonnet-5,gpt-5.4" \
  -d '{
    "model": "claude-haiku-4-5",
    "max_tokens": 512,
    "messages": [{"role": "user", "content": "three names for a build cache"}]
  }' -D -

Headers you can send

Request headerWhat it does
x-conifer-max-cost-nanousdA hard ceiling on what this request may cost, in integer nanodollars ($1 = 1e9). Over the ceiling the request is refused with 402 cost_ceiling_exceeded before any provider is called, and nothing is spent.
x-conifer-fallback-modelsUp to three comma-separated catalog ids to try, in order, if the model you named cannot be served. Chat and Responses wires only.
x-conifer-cacheoff skips the gateway's prompt caching for this one request.
x-conifer-deferallow runs a non-streaming request as a deferred job with a completion window of at least 24 hours. The gateway answers 202 and you fetch the result from /v1/jobs.

The cache

The gateway manages the provider’s prompt cache for you. On Anthropic models it marks the stable part of a conversation for caching once it can see that more turns are coming, so a long system prompt or a tool list is paid for once and read cheaply after that. If your request already carries cache_control markers, they are used as sent. Send x-conifer-cache: off to skip caching on one request.

Cache reads are billed well below the input rate and cache writes a little above it. The exact rates are in the pricing fields of each catalog entry. Cached tokens come back in the body as usage.prompt_tokens_details.cached_tokens on the chat wire and cache_read_input_tokens on the Messages wire, and in the receipt as the cache_read and cache_write parts of the cost.

The receipt

response headers
x-conifer-requested-model: claude-haiku-4-5
x-conifer-effective-model: claude-haiku-4-5
x-conifer-receipt-reason: as_requested
x-conifer-cost-nanousd: 1340000
x-conifer-cost-components-nanousd: fresh=920000,cache_write=0,cache_read=0,output=420000
x-conifer-request-id: req_…
HeaderValue
x-conifer-requested-modelThe id you sent, in your spelling.
x-conifer-effective-modelThe model that answered and was billed. The same as the requested id unless you sent beta-auto or default, or a fallback you named served.
x-conifer-receipt-reasonas_requested, provider_failover when a retry happened, or routed when a Conifer route chose the model.
x-conifer-endpointcredits, or byok:<provider> when your own provider key served the request.
x-conifer-cost-nanousdThe settled cost in nanodollars. Absent on a streamed response, where the cost arrives in a final conifer_receipt event instead: always on /v1/messages, and on chat and Responses when you send x-conifer-stream-receipt: true. Absent means not yet known, never zero.
x-conifer-cost-components-nanousdfresh, cache_write, cache_read and output in nanodollars. The four sum to the cost. Not sent on a beta-auto turn.
x-conifer-list-cost-nanousdOn a byok:<provider> request only: the usage at the provider's list rates, in nanodollars. A list-rate estimate of what the provider bills your own key; a discounted provider contract bills less. Conifer charges none of it. Absent on credits and on an Azure deployment the catalog does not price. On a stream it arrives as list_cost_nanousd on the final conifer_receipt event when you send x-conifer-stream-receipt: true.
x-conifer-pricing-identitysha256:<hex> naming the rate card the itemisation was computed under, the numbers that set the charge for the model that served. Sent only with the itemisation. It changes whenever a rate changes, so you can tell a receipt from an estimate made against an old price table.
x-conifer-receipt-pin-fallbackPresent only when the default pin served in place of a router's pick: timeout, unavailable, breaker_open or saturated. The reason stays as_requested. More values may be added. beta-auto never sends it: when it cannot pick, the request fails with a 503.
x-conifer-request-idThe request id to quote in a support message. Also sent as x-request-id and request-id.