OpenRouter Guide: API, Pricing, Provider Routing and BYOK
What is OpenRouter?
OpenRouter is a cloud gateway to language models: one OpenAI-compatible API and one credit balance give you access to hundreds of models from different labs. OpenRouter sends each request to one of the providers that serve the model. There's no markup on inference prices; the fee is charged when you buy credits.
TL;DR
- -To connect, change base_url to https://openrouter.ai/api/v1 and use an OpenRouter key. The model is a vendor/model string such as anthropic/claude-haiku-5.5. An Anthropic-compatible /api/v1/messages endpoint serves Anthropic-format clients.
- -OpenRouter passes provider prices through without markup. The fee comes at top-up: 5.5% with an $0.80 minimum on Standard, 5% for crypto, 8% on Business. A $5 top-up costs $0.80 in fees, or 16%.
- -One model can sit behind several providers with different quantization, prices and parameter support. In a November 7 test, the quantizations: ["fp8"] filter moved qwen/qwen3-coder from DeepInfra (fp4) to Venice, and the request cost 28% more.
- -Fallback through the models list bills the price of whichever model answered. In testing, a chain of a :free model and Haiku 5.5 was answered by the paid Haiku twice, because the free pool was busy at the provider.
- -OpenRouter doesn't store prompts by default, but each provider sets its own retention and training policy. For sensitive data, turn on provider.zdr: true or ZDR only mode in account settings.
OpenRouter is a cloud gateway to language models. One OpenAI-compatible API and one credit balance give you hundreds of models from different labs, from Claude and GPT to open Qwen, DeepSeek and Gemma. You pick a model with a string like anthropic/claude-haiku-5.5, and OpenRouter routes the request to one of the providers serving it. Inference prices carry no markup; the fee is charged when you top up. In its August 19, 2026 announcement, OpenRouter cited 400+ models and 10+ million developers.
Your first request takes a base_url change. The trouble starts with money and routing. A $5 top-up costs $0.80 in fees. A “free model first, paid model second” fallback chain turns out to be paid in practice. The same open model runs in different quantizations, with different parameter sets, at different providers. And a request with tool_choice can land on a provider that silently ignores it.
This guide covers how the OpenRouter catalog and providers work, what a top-up really costs, how to control provider selection and fallback, what happens to your data and cache, and how to connect Claude Code, OpenCode and Codex CLI. API behavior was tested on November 7, 2026 with a key capped at $5: a Python script using only the standard library, POST /api/v1/chat/completions, a short prompt and max_tokens: 30. All tests together cost $0.0018. The top-up fee, BYOK, ZDR and Claude Code through OpenRouter weren’t tested; those parts come from the documentation.
What OpenRouter is and when you need it
OpenRouter handles four jobs. It gives you one API format for many labs: code written for the OpenAI SDK switches between Claude, GPT and Qwen by changing the model string. It keeps one balance and one bill instead of an account with every vendor. It fails over between providers of one model and, if you ask, between different models. And it shows spend by key, model and provider in one place.
| OpenRouter | Direct provider API | LiteLLM Proxy | |
|---|---|---|---|
| Where it runs | OpenRouter cloud | Provider cloud | Your server |
| Keys | One OpenRouter key (or your own via BYOK) | A key per vendor | Provider keys stay with you, virtual keys for the team |
| Billing | Credits, fee at top-up | A bill from each vendor | Provider bills, the software is free |
| Fallback across labs | Yes, the models parameter | No | Yes, in config.yaml |
| Data path | Through OpenRouter and the chosen provider | Provider only | Through your host and the provider |
| What you maintain | Nothing | Nothing | Server, database, updates |
A direct API makes more sense when you work with one vendor and need its features on release day, with no fee and no extra hop. The Claude API guide covers Anthropic’s API directly. A self-hosted gateway fits when provider keys must stay inside your perimeter or you need per-employee budgets; see the LiteLLM guide. Where a gateway sits in a multi-provider setup is covered in Multi-Provider LLM Routing.
Models and providers: how the catalog works
The catalog needs no key: GET https://openrouter.ai/api/v1/models. On November 7, 2026 it had 460 entries, including :free and :batch variants and service routers. The vendors with the most models were openai (98), google (43), qwen (43) and anthropic (30). The count changes almost daily.
A model ID is vendor/model. Besides pinned versions there are tilde aliases: ~anthropic/claude-sonnet-latest always points to the newest model in the family (latest resolution). An alias is handy for a prototype. In production, pin the version so behavior doesn’t change without a release on your side.
IDs take suffixes. Per the FAQ, there are two kinds:
| Suffix | Kind | What it does |
|---|---|---|
:free | Catalog | Free version of the model, a separate entry with its own limits |
:batch | Catalog | Batch processing, half price for Claude 5.5 |
:nitro | Routing | Providers sorted by throughput, plus priority endpoints |
:floor | Routing | Providers sorted by price, plus flex endpoints |
:exacto | Routing | Providers ordered by tool-calling reliability |
:online | Routing, deprecated | Web search in the prompt; replaced by the server tool openrouter:web_search |
Catalog variants exist only for models that list them in /models. Routing suffixes work on any model.
One model, different providers
Several providers serve most models, each through its own endpoint. You can see the list without a key: GET /api/v1/models/<vendor>/<model>/endpoints. For open models the gap between providers can be large.
Snapshot for qwen/qwen3-coder on November 7, 2026:
| Provider | Quantization | Price per 1M (input / output) | Parameters | tool_choice | Context |
|---|---|---|---|---|---|
| DeepInfra | fp4 | $0.30 / $1.00 | 15 | none, auto, required, function | 262,144 |
| Venice | fp8 | $0.35 / $1.50 | 11 | none and auto only | 256,000 |
Of these two providers, only DeepInfra supports logit_bias, min_p, repetition_penalty and seed. If a request with tool_choice: "required" lands at Venice, you won’t get an error: per the documentation, without special settings an unsupported parameter is simply ignored.
Closed models vary less, but they still vary. On the same date Haiku 5.5 was served by Anthropic, Amazon Bedrock, Google Vertex, Azure and Claude Platform on AWS. Global endpoints cost $0.10 per 1M input tokens; regional ones (google-vertex/europe, amazon-bedrock/eu-west-1 and others) cost $0.11.
Quick start: your first request
You need an account and a key from openrouter.ai/settings/keys; the key looks like sk-or-v1-.... The API base URL is https://openrouter.ai/api/v1. OpenRouter implements OpenAI-compatible /chat/completions, /completions and /responses (FAQ). The Quickstart examples now use /responses, but /chat/completions works the same way.
curl
curl https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-H "HTTP-Referer: https://example.com" \
-H "X-OpenRouter-Title: My App" \
-d '{
"model": "anthropic/claude-haiku-5.5",
"max_tokens": 30,
"messages": [{"role": "user", "content": "Reply with exactly: ok"}]
}'
The HTTP-Referer and X-OpenRouter-Title headers are optional: they attribute your app in the openrouter.ai rankings. Per the documentation, the old X-Title name is still accepted.
OpenAI SDK
import os
from openai import OpenAI
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
)
resp = client.chat.completions.create(
model="anthropic/claude-haiku-5.5",
max_tokens=30,
messages=[{"role": "user", "content": "Reply with exactly: ok"}],
)
print(resp.choices[0].message.content)
TypeScript works the same way: baseURL: "https://openrouter.ai/api/v1" in the OpenAI constructor. Parameters the OpenAI SDK doesn’t know about (models, provider) go through extra_body; there’s an example in the fallback section below.
What comes back in the response
Besides the usual OpenAI-format fields, the response includes provider (who actually served the request), model (which model answered, which matters with fallback) and usage.cost (cost in dollars). Per the usage accounting docs as of November 7, usage with cost comes back in every response. The usage: {include: true} parameter is deprecated and has no effect.
Verified: November 7, 2026, anthropic/claude-haiku-5.5, prompt “Reply with exactly: ok”. The answer “ok” arrived in 1.05 s from provider Claude Platform on AWS, with 18 input and 4 output tokens and a cost of $0.0000038. That matches the price of $0.10 / $0.50 per 1M tokens. Usage in GET /api/v1/key showed 0 right after the tests and updated a few minutes later.
OpenRouter pricing and fees
OpenRouter passes provider prices through unchanged, and the FAQ says so directly: there’s no markup on inference. The platform makes its money on a fee when you buy credits.
| Plan | Top-up fee | BYOK | Limits |
|---|---|---|---|
| Free | Doesn’t apply | No | 50 requests a day, free models only |
| Standard | 5.5%, $0.80 minimum; crypto 5% with no minimum | $25,000 a month at list price with no fee, 5% above that | Pay-as-you-go |
| Business | 8% | Same as Standard | Pay-as-you-go |
| Enterprise | By contract | Custom | By contract |
The 5.5% and 8% rates come from the Pricing page. The $0.80 minimum and the 5% crypto rate come from the fee post (updated June 11, 2026). Terms are as of November 2026. The actual charge couldn’t be verified: the test account already had a balance, and no new top-up was made.
Because of the $0.80 minimum, the effective rate depends on the amount:
| Top-up | Fee | Effective rate |
|---|---|---|
| $5 | $0.80 | 16% |
| $10 | $0.80 | 8% |
| $25 | $1.38 | 5.5% |
| $100 | $5.50 | 5.5% |
| $1,000 | $55.00 | 5.5% |
A few more conditions from the Terms (version of August 31, 2026). A single purchase is $5 to $25,000. You can request a refund of unused credits only within 24 hours of payment; the fee isn’t refunded, and crypto payments are never refunded. OpenRouter may expire unused credits 365 days after purchase, so topping up a year ahead doesn’t pay off.
Claude 5.5 and Fable 5.1 prices in the catalog
As of November 7, 2026, per 1M tokens:
| Model | Input | Output | Cache read |
|---|---|---|---|
| Fable 5.1 | $10 | $50 | $0.25 |
| Opus 5.5 | $4 | $20 | $0.20 |
| Sonnet 5.5 | $2 | $10 | $0.10 |
| Haiku 5.5 | $0.10 | $0.50 | $0.01 |
All four have :batch variants at half price. How to measure cost per solved task rather than per token is covered in LLM Cost Optimization.
Provider routing: how to pick a provider
If you don’t name a provider, OpenRouter picks one. The default algorithm weighs provider price and stability, and it changes over time. When tested on November 7, the documentation described it as comparing effective price, speed, time to first token, 429 and error rates, and tool-call quality. If a provider fails, the request moves to the next one automatically. Setting sort, order, :nitro, :floor or your own provider key turns the default algorithm off.
The provider object in the request body controls the choice:
| Field | Default | What it does |
|---|---|---|
order | - | Providers in priority order |
allow_fallbacks | true | With false, only providers from order; otherwise an error |
only / ignore | - | Provider allowlist and blocklist |
sort | - | price, throughput or latency |
quantizations | - | Filter: int4, int8, fp4, fp8, fp16, bf16, unknown and others |
require_parameters | false | Only providers that support every parameter in the request |
data_collection | "allow" | "deny" excludes providers that store data and may train on it |
zdr | - | ZDR endpoints only |
max_price | - | Price cap per 1M tokens; if no provider fits, the request fails |
preferred_min_throughput, preferred_max_latency | - | Soft speed thresholds: slow providers move down the list but aren’t excluded |
Example: fp8 only, no more than $1 per 1M input and $2 per 1M output tokens.
{
"model": "qwen/qwen3-coder",
"messages": [{"role": "user", "content": "Reply with exactly: ok"}],
"provider": {
"quantizations": ["fp8"],
"max_price": {"prompt": 1, "completion": 2}
}
}
Verified: November 7, 2026, qwen/qwen3-coder, the same short prompt.
| Request | Provider | cost, $ |
|---|---|---|
sort: "price" | DeepInfra | 0.0000059 |
sort: "throughput" | DeepInfra | 0.0000059 |
quantizations: ["fp8"] | Venice | 0.00000755 |
Without a filter the request went to DeepInfra, which runs fp4 per /endpoints. With the fp8 filter, Venice served it, and the request cost 28% more. On an open model, quantization affects answer quality, so set it explicitly.
404 errors and routing_funnel
OpenRouter’s routing errors are detailed, which helps with debugging.
Verified: November 7, 2026, anthropic/claude-haiku-5.5, provider: {only: ["nonexistent-provider"], allow_fallbacks: false}. The response was a 404. Its metadata listed the model’s providers (google-vertex, claude-on-aws, azure, anthropic, amazon-bedrock), a step-by-step routing_funnel and failed_routing_step. The funnel: 10 endpoints, 5 after the regional markup filter, 0 after the provider filter. The error shows the full model ID: anthropic/claude-haiku-5.5-20261007.
The funnel tells you right away which filter killed the route: a typo in a provider slug, a max_price that’s too strict, or account privacy settings.
Model fallbacks and Auto Router
Fallback between providers of one model is on by default. You set fallback between different models with a models list in priority order (model fallbacks). OpenRouter tries the next model on any error from the first: context overflow, moderation refusal, rate limit, downtime. You pay for the model that answered, and its name comes back in the model field.
With the OpenAI SDK, pass the list through extra_body. The model in model goes first, and models holds the fallbacks in order:
resp = client.chat.completions.create(
model="anthropic/claude-haiku-5.5",
messages=[{"role": "user", "content": "Reply with exactly: ok"}],
extra_body={
"models": ["anthropic/claude-sonnet-5.5"], # fallback models, in order
},
)
print(resp.model) # the model that actually answered
Verified: November 7, 2026. A request with models: ["nonexistent-vendor/no-such-model", "anthropic/claude-haiku-5.5"] returned 400 “is not a valid model ID”. OpenRouter validates the model list before routing, so a typo in the first model fails the whole request instead of falling through to the next one. Two requests in a row with models: ["google/gemma-4-26b-a4b-it:free", "anthropic/claude-haiku-5.5"] both returned 200 from anthropic/claude-haiku-5.5 at $0.0000038 each. The free model was rate-limited at the provider at that moment, and the request quietly went to the paid one.
The documentation warns about this: if a paid model follows a :free one in models, fallback bills the paid price. To keep a request guaranteed free, list only :free models, or use the openrouter/free router, which switches only between free models. Log model from the response in your app, or a switch to the fallback model goes unnoticed.
For the Anthropic format (/api/v1/messages) there’s a fallbacks parameter instead of models. It takes at most 3 entries, each with only a model field, and it can’t be combined with models. Breaking any of these rules returns 400.
Auto Router
Auto Router (openrouter/auto) picks a model for each request. The router itself costs nothing extra: you pay the price of the chosen model, and provider.max_price still applies. OpenRouter updates its routers often. On November 7 the catalog had several entries with the openrouter/ prefix (auto, auto-code, free and others), and the Auto Router page already described a new generation with a cost_tier parameter. Auto Router wasn’t run in testing. For predictable production spend, set the model explicitly.
Free models (:free)
Models with the :free suffix cost $0. They’re separate catalog entries with their own limits and providers. On November 7, 2026 the catalog had 12 of them plus the openrouter/free router. Limits per the documentation:
| Credits bought (all time) | Requests per minute | Requests per day |
|---|---|---|
| Fewer than 10 | 20 | 50 |
| 10 or more | 20 | 1,000 |
GET /api/v1/key returns the current daily counter in the free_model_daily_requests field. The documentation adds a caveat to the threshold: to cover rounding and fees, the higher daily limit kicks in one credit early. With a negative balance, you may see errors even on free models.
Verified: November 7, 2026, google/gemma-4-26b-a4b-it:free. The response was 429 “temporarily rate-limited upstream”, limit_source: upstream_provider_shared_pool, provider Google AI Studio. The remedy_hint suggested adding your own key (BYOK) or picking another provider. The response had no X-RateLimit-* headers.
You can get a 429 on :free with your personal limit untouched: the free model’s pool at the provider is shared, and your own counter won’t explain it. Beyond experiments, free models aren’t reliable. Mind privacy too: the account setting that allows providers who train on data is separate for paid and free models (provider logging).
BYOK: bring your own provider keys
BYOK (bring your own key) means connecting your own provider key, for example Anthropic or Bedrock. Requests still go through the OpenRouter API, but you pay for inference on your provider account, and the rate limits are yours too. Per the BYOK docs and Pricing, on the Standard and Business plans the first $25,000 a month at list price carries no fee. Above that, OpenRouter deducts 5% of the cost of the same request from your credits. The Free plan has no BYOK. Older summaries mention a “1 million free BYOK requests a month” rule; the cost-based limit replaced it.
Two details affect the bill:
- Shared capacity fallback. By default, if your key hits a limit or returns an error, OpenRouter falls back to its own endpoints and spends your credits. To prevent that, pick “Never use shared capacity” in the key settings.
- Priority. Keys are either Prioritized (tried before OpenRouter endpoints) or Fallback (tried after them). Without
orderin the request, providers you hold a Prioritized key for go first.
BYOK wasn’t tested: it needs a separate provider key.
Privacy, logging and ZDR
Per the FAQ, OpenRouter logs request metadata (time, model, token counts) and doesn’t store prompts or responses unless you turn logging on. If you do, OpenRouter gives a 1% discount on usage.
The request still goes to a provider, and every provider has its own policy. As of November 7, the ZDR documentation splits endpoints into three tiers:
| Tier | What happens to data |
|---|---|
| ZDR (Zero Data Retention) | Prompts and responses usually aren’t stored after processing |
| Safety Retention | The provider or OpenRouter may keep data only for abuse prevention, no training |
| Retention and Training | Stored per the provider’s policy, training possible |
How to restrict the route:
provider.zdr: truein the request: ZDR endpoints only (plus Safety Retention if the account allows it).provider.data_collection: "deny": no providers that collect data.- Account privacy settings or guardrails: ZDR only mode, no training. If you set
providerand no provider matches the account settings, the request fails.
Self-serve accounts allow Safety Retention by default; Enterprise accounts get ZDR only. ZDR covers inference but not plugins and server tools such as web search, which follow their own third-party policies. When tested, the ZDR page also said that all requests, ZDR traffic included, are screened for CSAM, and suspicious content may be kept for review. For sensitive data, check the specific endpoint’s policy before sending, and keep a data policy layer in your application, as in Multi-Provider LLM Routing.
Prompt caching through OpenRouter
The prompt cache lives at the provider, so a repeat request has to reach the same provider. OpenRouter handles this with sticky routing (prompt caching). It turns on only when the provider’s cache read is cheaper than normal input, and it doesn’t work with a manual provider.order. OpenRouter identifies a conversation by a hash of the first system message and the first non-system message, or by an explicit session_id in the body or the x-session-id header (up to 256 characters). Per the documentation as of November 7, a session lives for 60 minutes without requests.
The rules differ by provider:
| Provider | How it’s enabled | Cache write | Read |
|---|---|---|---|
| Anthropic | Explicitly, cache_control (on a block or at the top level of the request) | 1.25x input (5-minute TTL), 2x (1-hour TTL) | 0.1x input; 0.05x on Opus 5.5 and Sonnet 5.5, 0.025x on Fable 5.1 |
| OpenAI | Automatically from 1,024 tokens | Free on models before GPT-5.6, 1.25x on GPT-5.6 and later (30-minute TTL) or 2.5x (12 hours) | 0.1x or 0.05x input on GPT-6 and GPT-6.1, 0.25x or 0.5x on older models |
| Alibaba Qwen | Explicitly, cache_control | 1.25x, 5-minute TTL | 0.1x input |
Gemini, DeepSeek and a cache break-even formula are covered in how prompt caching works across providers.
The minimum cacheable prompt for Claude 5.5 and Fable 5.1 is 512 tokens. Here’s an example with the cache on the system prompt:
{
"model": "anthropic/claude-haiku-5.5",
"messages": [
{"role": "system", "content": [
{"type": "text", "text": "<long instructions or document>",
"cache_control": {"type": "ephemeral"}}
]},
{"role": "user", "content": "Reply with exactly: ok"}
]
}
How much the cache saves: a Haiku 5.5 test
Verified: November 7, 2026, anthropic/claude-haiku-5.5, a 12,635-token system prompt with cache_control: {type: "ephemeral"}, two identical requests 2 s apart.
| Request | cached_tokens | cost, $ | Time, s |
|---|---|---|---|
| First (cache write) | 0 | 0.00158 | 1.51 |
| Second (cache read) | 12,619 | 0.00013 | 1.41 |
The second request was 12 times cheaper than the first. The first cost more than a normal request: 12,635 tokens at $0.10 per 1M would be $0.00126, but $0.00158 was charged, which is the 1.25x cache write premium. The same provider served both requests; otherwise the cache read wouldn’t have happened.
The cache pays off from the second hit, and a prompt you send only once costs 25% more with cache_control. Cache metrics come back in usage.prompt_tokens_details.cached_tokens and cache_write_tokens. How caching works on Anthropic’s side is covered in the Claude API guide.
Tool calling and structured outputs: what differs
In the November 7 catalog, 398 of 460 entries support tools, 393 support tool_choice, 387 structured_outputs and 401 response_format. That’s support at the model level. A specific provider can support less, as Venice does for Qwen3 Coder.
Per the documentation, tools, the response format (response_format, structured outputs) and verbosity act as soft preferences: if the model has providers that support them, the request goes there. With require_parameters: false, a provider that doesn’t support any other parameter simply ignores it. To send a request only to providers that support all of its parameters, set require_parameters: true.
{
"model": "qwen/qwen3-coder",
"messages": [{"role": "user", "content": "What time is it?"}],
"tools": [{"type": "function", "function": {
"name": "get_time", "parameters": {"type": "object", "properties": {}}}}],
"tool_choice": "required",
"provider": {"require_parameters": true}
}
Verified: November 7, 2026, qwen/qwen3-coder, one tool get_time, tool_choice: "required", provider: {require_parameters: true}. The response was 200 from DeepInfra and included tool_calls. That matches the /endpoints data: Venice doesn’t support tool_choice: required, and DeepInfra does.
For agents that rely on tool calls, require_parameters: true is a sensible default. The alternative is the :exacto suffix, which orders providers by tool-calling reliability; it wasn’t run in testing.
Connecting agents: Claude Code, OpenCode, Codex CLI
Claude Code
Per the official OpenRouter guide, Claude Code connects through environment variables with no local proxy, because OpenRouter accepts the Anthropic Messages API.
export ANTHROPIC_BASE_URL="https://openrouter.ai/api"
export ANTHROPIC_AUTH_TOKEN="$OPENROUTER_API_KEY"
export ANTHROPIC_API_KEY="" # must be explicitly empty
# optional: pin models per class
export ANTHROPIC_DEFAULT_SONNET_MODEL="~anthropic/claude-sonnet-latest"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="~anthropic/claude-haiku-latest"
claude
If you previously signed in to Claude Code with an Anthropic account, run /logout once; otherwise the cached session conflicts with the gateway key. Put the variables in your shell profile, not in a project .env: the native Claude Code installer doesn’t read it. Check the connection with /status: the Auth token line should name ANTHROPIC_AUTH_TOKEN.
The setup comes with two warnings. The OpenRouter guide itself says it’s guaranteed to work only with the Anthropic first-party provider and recommends putting that provider first in provider routing. And the Claude Code documentation says plainly that Anthropic doesn’t endorse or audit third-party gateways and doesn’t support routing Claude Code to non-Claude models through any gateway. Anthropic gives no official support for Claude Code with OpenRouter, so you run it at your own risk. Claude Code through OpenRouter wasn’t run for this article.
OpenCode
OpenRouter is a built-in provider in OpenCode (guide). In the TUI, run /connect, choose OpenRouter and enter the key, then pick a model with /models. Add more models to opencode.json by their OpenRouter slug. Agent configuration and model tests are covered in the OpenCode guide.
Codex CLI
Codex CLI connects through a provider block in ~/.codex/config.toml (guide):
model_provider = "openrouter"
model = "<vendor/model from the catalog>"
[model_providers.openrouter]
name = "openrouter"
base_url = "https://openrouter.ai/api/v1"
[model_providers.openrouter.auth]
command = "sh"
args = ["-c", "echo $OPENROUTER_API_KEY"]
env_key = "OPENROUTER_API_KEY" also works, but then Codex doesn’t load the OpenRouter model catalog and shows an unknown-model warning for non-OpenAI models.
Limits and errors
| Code | When | What to do |
|---|---|---|
| 400 | Invalid model ID (including in models), extra fields in fallbacks | Check the ID against /api/v1/models |
| 402 | Not enough credits, or the in-flight budget is used up | Check metadata.reason, lower max_tokens, top up |
| 404 | No provider passed the filters (only, max_price, privacy) | Check routing_funnel and failed_routing_step |
| 429 | :free limit or the provider’s shared pool | Check limit_source, retry with backoff, add a fallback |
The in-flight budget (limits) applies to some prepaid accounts with small balances and to new accounts. OpenRouter reserves the estimated cost of running requests and returns 402 when that runs short, even with a positive balance. reason: "in_flight_budget_exhausted" is temporary: wait for Retry-After. reason: "weight_exceeds_budget" means a single request costs more than the whole budget. Retrying won’t help; cut max_tokens or the prompt.
The documentation doesn’t name a fixed RPM for paid models. Capacity is managed globally, and extra accounts or keys don’t raise the limit. When a provider returns 429, OpenRouter first tries other providers of the same model and only then passes the error to the client. GET /api/v1/key shows spend and the remaining limit for a key: limit_remaining, usage_daily, usage_weekly, usage_monthly. You can set a spend limit on each key, which is an easy way to cap an experiment or a single service.
OpenRouter limitations and when to use something else
- Data goes through a third party. Even with ZDR, the request passes through OpenRouter’s and the provider’s servers. If keys and traffic must stay inside your perimeter, you need a self-hosted gateway such as LiteLLM or a local model. The options are collected in the local LLM guide, setup is covered in the Ollama guide, and the choice between the two popular apps in LM Studio vs Ollama.
- Quality depends on the provider. Quantization and parameter support differ between providers of one model, and the default provider can change without you doing anything. For reproducible results, pin
quantizations,orderoronlyand logproviderfrom the response. - The catalog changes. Models get an
expiration_date, and prices and provider lineups shift. A hardcoded ID with no monitoring will start returning errors one day. - Fees on small amounts. A $5 top-up costs 16% on top. You can get credits refunded only in the first 24 hours, and unused credits can expire after a year.
- One vendor and its new features. If you work only with Anthropic or OpenAI and need new API features on release day, the direct API is simpler and cheaper by the size of the fee.
How to tie the gateway, fallback, evals and monitoring into one system is covered in Production LLM Stack.
Where to start
- Create a key on openrouter.ai and set a spend limit on it right away.
- If you plan regular use, top up at least $25: at that amount the fee is 5.5%, not 16%. Keep the 24-hour refund window and the 365-day expiry in mind.
- Connect the OpenAI SDK by changing
base_url, and logmodel,providerandusage.costfrom every response. - For open models, check
/api/v1/models/<id>/endpointsand pinquantizationsororder. - For agents and tool calls, set
provider.require_parameters: true. - For sensitive data, turn on ZDR only mode in privacy settings or send
provider.zdr: truewith requests. - Send long system prompts to Claude with
cache_controland checkcached_tokenson the second request.