Skip to main content

Provider Routing

By default, the Router distributes requests across healthy providers using round-robin with automatic failover. X-0G-Provider-* request headers let you override this when you need specific behavior.

Default Behavior

If you send no routing headers, the Router:

  1. Picks a healthy provider for the requested model
  2. Retries on the next healthy provider if the first returns an error
  3. Returns the response — or a 503 if every provider failed

This is the recommended path for most applications.

Routing surfaces

The Router accepts routing preferences from two surfaces. In priority order:

PrioritySurfaceEndpointsStatus
1X-0G-Provider-* request headersAll inference endpoints (JSON, multipart, async)Canonical
2JSON body provider: {…} objectJSON endpoints only (/v1/chat/completions, /v1/messages, /v1/images/generations, /v1/async/images/generations)Deprecated — kept for back-compat

Headers and body are merged field-by-field; when the same field is set on both, the header wins. Multipart endpoints (/v1/audio/transcriptions, /v1/images/edits, /v1/async/images/edits) have no body routing surface — headers are the only way to control routing there.

The JSON body provider object is deprecated

New code should use X-0G-Provider-* headers. The body surface still works today for back-compat but will be phased out in a future release. Headers are the only routing surface that works uniformly across JSON, multipart, and async endpoints.

Routing Strategies

curl https://router-api.0g.ai/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-YOUR_API_KEY" \
-H "X-0G-Provider-Sort: latency" \
-d '{
"model": "zai-org/GLM-5-FP8",
"messages": [{"role": "user", "content": "Hello"}]
}'

Routes to the provider with the lowest recently-observed latency for this model.

Header Reference

HTTP header names are case-insensitive per RFC 7230 — X-0G-Provider-Address and x-0g-provider-address are equivalent.

HeaderValuesDescription
X-0G-Provider-Addresson-chain address (0x…)Pin the request to a specific provider. Implies Allow-Fallbacks: false unless overridden.
X-0G-Provider-Sortlatency | priceSort strategy when no address is pinned. Ignored if X-0G-Provider-Address is set. Must be exactly latency or price — any other non-empty value is rejected with 400 invalid_provider_header.
X-0G-Provider-Trust-Modestandard | verified | privateRestrict provider selection to a trust tier — see Trust modes.
X-0G-Provider-Allow-Fallbackstrue | falseAllow cross-provider retry on failure. Must be exactly true or false (case-insensitive) — 1, 0, yes, and other non-empty values are rejected with 400 invalid_provider_header.
X-0G-Provider-Max-Price-Usd-Promptfinite, non-negative decimalPer-request ceiling on prompt token price, USD per 1M tokens. See Capping price per request.
X-0G-Provider-Max-Price-Usd-Completionfinite, non-negative decimalPer-request ceiling on completion token price, USD per 1M tokens. See Capping price per request.
X-0G-Provider-Max-Price-Usd-Imagefinite, non-negative decimalPer-request ceiling on image price, USD per generated image. See Capping price per request.

Defaults: Allow-Fallbacks is true normally, and false when X-0G-Provider-Address is set.

A header that is absent, or blank after trimming whitespace, is treated as unset and falls back to the default. Only a present-but-malformed value is rejected — a blank header meaning "I didn't set this" is never an error.

Trust modes

X-0G-Provider-Trust-Mode restricts selection by the provider's verification mode. The tiers are ordered standard < verified < private and act as a floor: asking for verified is also satisfied by the stronger private.

ValueRoutes toGuarantee
standardAny TEE-backed providerTEE-backed execution; the upstream discloses no independent verifiability method.
verifiedTeeML and TeeTLS providersVerifiable execution — the response provably came from the real model.
privateTeeML providers onlyVerifiability and privacy — the model itself runs inside the TEE, so prompts never leave the enclave.

Values other than standard/verified/private are rejected with 400 invalid_trust_mode. Omit the header for no trust-tier restriction (the default).

Capping price per request

The X-0G-Provider-Max-Price-Usd-* headers set a hard ceiling on what you're willing to pay. Any provider above the ceiling on a relevant dimension is dropped from the candidate pool entirely — this is a filter, not a preference, and it runs before sorting and failover. A fallback during an outage can never silently route you to a provider you've priced out.

curl https://router-api.0g.ai/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-YOUR_API_KEY" \
-H "X-0G-Provider-Max-Price-Usd-Prompt: 1.0" \
-H "X-0G-Provider-Max-Price-Usd-Completion: 5.0" \
-d '{
"model": "zai-org/GLM-5-FP8",
"messages": [{"role": "user", "content": "Hello"}]
}'

Send any subset — one header, two, or all three. Each value is a finite, non-negative decimal; NaN, Inf, negative, and non-numeric values are rejected with 400 invalid_max_price_usd.

Which dimension applies to which endpoint

The ceiling is service-type aware. Setting Image on a chat call (or Prompt / Completion on an image call) is silently inert, so a cross-endpoint SDK that always sends all three headers won't accidentally filter out every provider.

Service typeEndpointsDimensions enforcedUnit
Chat/v1/chat/completions, /v1/messagesPrompt, CompletionUSD per 1M tokens
Image/v1/images/generations, /v1/images/edits, /v1/async/images/*ImageUSD per generated image
Speech-to-text/v1/audio/transcriptionsnone yet — see below
Speech-to-text is not covered yet

STT models are billed per second of audio, which has no equivalent in the current USD pricing schema (prompt / completion / image only). Reusing the Prompt header for STT would be a footgun — the same 1.0 would mean "1per1Mtokens"onchatand"1 per 1M tokens" on chat and "1 per second" on audio — so /v1/audio/transcriptions enforces no ceiling for now.

Two failure modes are worth calling out:

  • No provider qualifies. If the ceiling filters out every candidate, the request fails with 400 no_provider_within_max_price, not 503 — the pool is empty structurally, not transiently, so retrying without raising the ceiling won't help.
  • Pinning + ceiling. If X-0G-Provider-Address pins a provider above the ceiling, the request fails with 400 pinned_provider_exceeds_max_price — the pin isn't silently overridden.

Discovering Provider Addresses

List the providers serving a model with GET /v1/providers?model_id=… — see Models.

  • Principles — why failover is the default
  • Errors — what 502 and 503 mean for routing