Skip to content

Provider Routing Headers

The X-0G-Provider-* request headers control routing: which provider serves a request, what trust tier it must meet, and what you are willing to pay. This page gives the value domain, the default, and the exact error each malformed value produces.

Header names are case-insensitive per RFC 7230. X-0G-Provider-Sort and x-0g-provider-sort are the same header. Header values follow the per-header rules below.

Every authenticated endpoint uses the same header. The prefix decides what the credential can do.

Terminal window
Authorization: Bearer sk-<YOUR_API_KEY>
Terminal window
Authorization: Bearer mk-<YOUR_MANAGEMENT_KEY>
Prefix What it is for
sk- Inference endpoints. Billed against your deposit.
mk- Account administration: balance, usage, and sk- key management. Not billed.

There is no OAuth flow and no per-request wallet signature. Missing header gives 401 missing_authorization; an unknown or malformed key gives 401 invalid_api_key. See API & Authentication for the endpoint-by-credential matrix, and Error Codes for every code.

Routing preferences arrive from two surfaces:

Priority Surface Endpoints Status
1 X-0G-Provider-* request headers All inference endpoints, including JSON, multipart, and async Canonical
2 JSON body provider object JSON endpoints only Deprecated

The two are merged field by field. When both set the same field, the header wins; a field set only in the body still applies. Multipart endpoints have no body routing surface at all, so headers are the only way to route there.

The Router draws a hard line between “I did not set this” and “I set this wrong”:

  • Absent, or blank after trimming whitespace — treated as unset. The default applies. Never an error.
  • Present but malformed — rejected with a 400. The Router does not silently fall back to a default, because a header that quietly does nothing trains you to believe a setting took effect when it did not.

A client that unconditionally emits X-0G-Provider-Sort: with an empty value is safe. A client that emits X-0G-Provider-Sort: fastest gets a 400.

Header Values Default Invalid value
X-0G-Provider-Address On-chain address (0x…) unset — Router selects Rejected by the provider registry
X-0G-Provider-Sort latency or price, exact lowercase unset — Router default strategy 400 invalid_provider_header
X-0G-Provider-Trust-Mode standard, verified, or private unset — no tier restriction 400 invalid_trust_mode
X-0G-Provider-Allow-Fallbacks true or false, case-insensitive true; false when an address is pinned 400 invalid_provider_header
X-0G-Provider-Require-Parameters true or false, case-insensitive false — soft preference 400 invalid_provider_header
X-0G-Provider-Max-Price-Usd-Prompt Finite, non-negative decimal unset — no ceiling 400 invalid_max_price_usd
X-0G-Provider-Max-Price-Usd-Completion Finite, non-negative decimal unset — no ceiling 400 invalid_max_price_usd
X-0G-Provider-Max-Price-Usd-Image Finite, non-negative decimal unset — no ceiling 400 invalid_max_price_usd
Element Case sensitivity
Header names Insensitive, all headers
X-0G-Provider-Sort value Sensitive — must be exactly latency or price
Allow-Fallbacks and Require-Parameters values Insensitive — TRUE and true both work
X-0G-Provider-Trust-Mode value Use the exact lowercase tier names

Pins the request to one provider by on-chain address. When set, X-0G-Provider-Sort is ignored, since there is nothing to sort. Pinning also implies Allow-Fallbacks: false: if the pinned provider fails, so does the request. Send X-0G-Provider-Allow-Fallbacks: true alongside it to re-enable cross-provider retry.

Find addresses with GET /v1/providers?model=… — see Model Catalog.

latency routes to the provider with the lowest recently observed latency for the model. price routes to the cheapest. The value must be exactly latency or price; Latency and LATENCY are rejected, unlike the boolean headers.

Restricts selection to a trust tier. The tiers are ordered standard < verified < private and act as a floor: asking for verified is also satisfied by the stronger private.

Value Routes to Guarantee
standard Any TEE-backed provider TEE-backed execution; the upstream discloses no independent verifiability method
verified TeeML and TeeTLS providers Verifiable execution — the response provably came from the real model
private TeeML providers only Verifiability and privacy — the model runs inside the enclave, so prompts never leave it

Omit the header for no restriction, which lets the Router balance across tiers for performance.

The Router never silently downgrades. If no provider in the requested tier is available, the request fails with 503 no_provider_for_trust_mode rather than serving you from a weaker tier. That condition is about tier supply and is transient: retry, or pick a model with providers in that tier. An out-of-domain value gives 400 invalid_trust_mode.

A trust mode set per key overrides anything your code sends. See Trust Modes for the concept.

Terminal window
curl https://router-api.0g.ai/v1/chat/completions \
--max-time 120 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ZG_API_KEY" \
-H "X-0G-Provider-Trust-Mode: private" \
-H "X-0G-Provider-Sort: latency" \
-d '{
"model": "<MODEL_ID>",
"messages": [{"role": "user", "content": "Hello"}]
}'

Controls cross-provider retry when a provider fails. Only true and false are accepted, case-insensitively. 1, 0, and yes — the common SDK mistakes — return 400 invalid_provider_header.

By default the Router treats requested sampling and reasoning parameters as a soft preference: among providers that pass every hard filter, it prefers ones advertising support for what you asked for, and falls back to the rest if none do. You never get a 400 for this, and no usable provider is discarded.

Setting X-0G-Provider-Require-Parameters: true upgrades that preference to a hard filter for this request. Providers that do not advertise support are dropped, and if none remain the request fails with 400 model_not_capable.

It also brings output capacity into the filter. When the header is on and the request sets a maximum output length, the Router routes only to providers whose advertised max_completion_tokens can hold it, including excluding providers that have never reported a cap. No qualifying provider gives 400 no_provider_within_max_tokens. With the header off, an unreported cap is treated as unknown rather than incapable, and the provider is left to reject the request itself.

A pinned X-0G-Provider-Address skips these filters.

A hard ceiling on what you will pay, in USD. Any provider above the ceiling on a relevant dimension is dropped from the candidate pool entirely.

The filter runs before sorting and before failover. That ordering is the point: a fallback during an outage can never route you to a provider you have priced out. It is a filter, not a preference.

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

The ceiling is service-type aware:

Service type Endpoints Dimensions enforced Unit
Chat /v1/chat/completions, /v1/messages Prompt, Completion USD per 1M tokens
Image /v1/images/generations, /v1/images/edits, /v1/async/images/* Image USD per generated image
Speech-to-text /v1/audio/transcriptions none yet

Sending Image to a chat call, or Prompt to an image call, is silently inert. A cross-endpoint SDK that always sends all three headers will not accidentally filter every provider out. Speech-to-text is billed per second of audio, which has no equivalent dimension in the current pricing schema, so no ceiling is enforced there yet.

Two failure modes worth designing for:

  • No provider qualifies400 no_provider_within_max_price, not 503. The pool is empty structurally, not transiently, so retrying without raising the ceiling will not help.
  • Pin above the ceiling400 pinned_provider_exceeds_max_price. The pin is never silently overridden.
Header Present on Meaning
X-RateLimit-Limit-Requests Every inference response Your current request limit
X-RateLimit-Remaining-Requests Every inference response Requests left in the current window
X-RateLimit-Reset-Requests Every inference response ISO-8601 timestamp when the window resets
Retry-After 429 responses Seconds to wait before retrying
ZG-Res-Key Every inference response The provider’s chat ID for this response

Read X-RateLimit-Remaining-Requests on every response. A batch job that watches it approach zero and slows down never trips a 429 at all, which is strictly better than absorbing rejections that still cost a round trip. Limits are per account, not per key: issuing more sk- keys does not buy more throughput.

Threshold numbers are not published, because they depend on account state and change as the network is tuned. A hardcoded number would be wrong for your account or wrong next month. X-RateLimit-Limit-Requests reports your real limit on every response.

When you do exceed the limit, the Router returns 429 with Retry-After in seconds. Honor it; a tight retry loop only collects more 429s. See the 429 row in Error Codes.

Terminal window
curl -s -D headers.txt -o /dev/null \
https://router-api.0g.ai/v1/chat/completions \
--max-time 120 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ZG_API_KEY" \
-d '{"model": "<MODEL_ID>", "messages": [{"role": "user", "content": "Hello"}]}'
grep -i 'retry-after\|x-ratelimit\|zg-res-key' headers.txt

ZG-Res-Key carries the chatID you need to verify a response independently of the Router, by fetching the provider’s signature and checking it yourself rather than trusting the Router’s tee_verified flag. Prefer it over the response body id, which is only a fallback. See Trust Modes.

Code Status Trigger
invalid_provider_header 400 Out-of-domain Sort, Allow-Fallbacks, or Require-Parameters value
invalid_trust_mode 400 Trust-Mode outside standard / verified / private
invalid_max_price_usd 400 A price value that is not a finite, non-negative decimal
no_provider_within_max_price 400 The price ceiling filtered out every candidate
pinned_provider_exceeds_max_price 400 The pinned address is priced above the ceiling
model_not_capable 400 Require-Parameters: true and no provider supports the requested parameters
no_provider_within_max_tokens 400 Require-Parameters: true and no provider advertises enough output capacity
no_provider_for_trust_mode 503 No provider in the requested trust tier is available
rate_limit_exceeded 429 Over the request limit; read Retry-After

Full table with retry guidance: Error Codes.

  • Error Codes — every status, type, code, and what is retryable
  • Model Catalog — finding a model ID or a pinnable provider address
  • Trust Modes — what standard, verified, and private actually guarantee