Skip to main content
In normal mode Relay picks a host key from a pool for each request. In proxy mode the caller sends its own upstream credential, and Relay forwards the request body unchanged to the host with that credential attached. Relay still authenticates the relay key, applies its policy’s rate limits, and records usage, cost and (if enabled) payloads. Use it when the credential belongs to the caller, for example a developer’s own provider subscription, but you still want one endpoint, rate limits and usage records in front of the traffic. Claude Code uses it this way.

Normal mode vs proxy mode

Enabling it

Proxy mode is off by default. Turn it on through the control API:
The change reaches every pod within about a second.

Allowing a relay key to proxy

An authenticated proxy request also needs a relay key with spec.passthroughAllowed: true; any other credential gets 403 passthrough_forbidden. Inference tokens never carry the flag, so they cannot be used for proxy mode. Set the flag when you create the key:
For an existing key, read it with GET /api/keys/{ref}, set spec.passthroughAllowed to true, and send the object back with PUT /api/keys/by-id/{id}. In a manifest the field is spec.passthroughAllowed on the Key document.

Making a proxy request

Send X-WR-Proxy-Mode: Proxy, put your relay key in X-WR-API-Key, put your upstream credential in Authorization, and name the host in X-WR-Upstream-Host:
Relay removes its own headers (X-WR-*) and hop-by-hop headers, sets Authorization to the value you sent, and posts the body to the host’s endpoint for that shape. In proxy mode the relay key is read only from X-WR-API-Key, because Authorization carries the upstream credential. Send the body in the shape the target host expects, since nothing is translated.

Authenticated requests

With a relay key:
  • Host. If X-WR-Upstream-Host is set, Relay forwards to that host. If it is absent, Relay reads model from the body and picks the host through the governing policy’s grants and the model’s bindings, as normal routing does, without requiring a host key.
  • Grants. A pinned request reaches only a model the governing policy grants on the pinned host, as normal routing does, and its usage is priced from that binding. The caller’s own credential does not widen the grant. A model that does not route there is refused with the same errors as normal mode (model_not_found, model_not_allowed), and an @host in the model that names a different host than X-WR-Upstream-Host gets 400 upstream_host_conflict. A keyless (noAuth) host such as a self-hosted Ollama additionally needs a policy that explicitly grants that host. A key with no governing policy has no grant to check: a model that does not route at the pin is forwarded unpriced.
  • Rate limits. The governing policy’s rate limit is reserved and committed as in normal mode. The inference-api-proxy rate limit is applied on top as a per-credential ceiling. It ships disabled with no rules; add rules and enable it to cap every relay key’s proxy traffic. A key with no governing policy gets only that ceiling.
  • Attribution. The request is recorded against the relay key, its principal, project and policy.

Anonymous requests

Without a relay key, a proxy request is allowed only when allowUnauthenticated is on. X-WR-Upstream-Host is then required, and the request is rate-limited per client IP by the inference-api-proxy-anonymous rate limit, which ships enabled at 60 requests and 5,000 tokens per minute and 10 concurrent requests per IP. Keyless hosts cannot be reached anonymously. See client IP for how Relay finds the caller’s address behind a load balancer. Both system rate limits are created on boot when missing and never overwritten once they exist. Change them with PUT /api/rate-limits/by-id/{id}; set enabled: false to remove a limit. A deleted one is recreated as shipped on the next boot. See Rate limits.

Discovering upstream hosts

List the host slugs you can pass in X-WR-Upstream-Host:
Keyless hosts appear only when the caller’s policy grants them.

Errors

An upstream error is returned as the upstream sent it.