OpenRouter Prompt Caching + Sticky Routing: Agent Cost Math for 2026
On July 21, 2026, OpenRouter published a tutorial titled "The Cheapest Token Is a Cached One: Prompt Caching + Sticky Routing." It is the clearest public breakdown of how their aggregation layer handles cache reads, cache writes, and session pinning across 70+ upstream providers. For anyone running multi-turn agents, the cost math in that post is the difference between a $5,000 month and a $500 month on the same workload.
This article distills the OpenRouter post into the parts that matter for production builders:
- The provider-by-provider cache pricing matrix (Anthropic, OpenAI pre/post GPT-5.6, Gemini, Grok, Moonshot, Groq, DeepSeek, Alibaba Qwen, Z.AI).
- A concrete 6-turn × 10,000-token example showing what sticky routing actually saves.
- The four causes of cache misses and how to stop each one.
- The
session_idparameter and why it changes stickiness from "sometimes warm" to "reliably warm." - The
cached_tokens,cache_discount, andcache_write_tokensfields that confirm caching is working.
All pricing facts are verified from the OpenRouter blog post dated 2026-07-21 and OpenRouter's prompt caching docs as of late July 2026.
What Is Prompt Caching on OpenRouter?
OpenRouter is a unified API that fronts 300+ models across 70+ providers. The "prompt caching" feature means OpenRouter (or the upstream provider) reuses part of the prompt instead of re-tokenizing and re-billing the full input on every turn. The reusable part is usually the expensive part — system prompts, tool definitions, JSON schemas, guardrails, retrieved documents, examples — that stay the same across turns.
Two separate cost components matter:
- Cache write — the first request that stores the reusable prefix. On some providers this costs more than the regular input token price (Anthropic charges 1.25x for 5-min TTL, 2.0x for 1-hour TTL). On other providers it's free (Gemini, Grok, Moonshot, pre-GPT-5.6 OpenAI, Groq).
- Cache read — every later request that reuses the stored prefix. This is the cheap part: anywhere from 0.1x to 0.5x of the normal input price, depending on the provider.
A cache read of 0.1x means a 10,000-token system prompt that would cost $30 of input on Claude Sonnet 4.6 costs $3 when read from cache. Multiply that across 6 turns of a long-running agent and the savings stack fast.
Provider-by-Provider Cache Pricing Matrix (verified 2026-07-21)
The following table is the OpenRouter-published breakdown, captured directly from the blog post:
| Provider | Cache read multiplier | Cache write multiplier | How to enable |
|---|---|---|---|
| Anthropic Claude (5-min TTL) | 0.1x input | 1.25x input | Automatic or explicit |
| Anthropic Claude (1-hour TTL) | 0.1x input | 2.0x input | Explicit (ttl: "1h") |
| OpenAI (before GPT-5.6) | 0.25x–0.50x input | Free | Automatic |
| OpenAI (GPT-5.6 and later) | 0.25x–0.50x input | 1.25x input | Automatic or explicit |
| Google Gemini (implicit) | 0.25x input | Free | Automatic |
| Grok (xAI) | 0.25x input | Free | Automatic |
| Moonshot AI | 0.25x input | Free | Automatic |
| Groq | 0.5x input | Free | Automatic (Kimi K2 models) |
| DeepSeek | 0.1x input | 1.0x input | Automatic |
| Alibaba Qwen | 0.1x input | 1.25x input | Explicit (cache_control) |
| Z.AI | ~0.2x input | Free | Automatic |
Three patterns stand out:
- Anthropic, DeepSeek, and Alibaba Qwen offer the cheapest cache reads (0.1x), but their writes cost more than normal input. If your agent doesn't reuse the prefix enough to amortize the write, caching can actually cost you.
- Google Gemini, Grok, and Moonshot give free writes with 0.25x reads. Best of both worlds for one-shot agents that benefit from cache hits but rarely need multi-hour TTL.
- OpenAI moved to paid writes on GPT-5.6. Pre-GPT-5.6 OpenAI had free writes; GPT-5.6+ charges 1.25x for cache writes. If you migrated to GPT-5.6 in June 2026, your cache economics silently shifted.
Concrete Savings: 6-Turn Agent × 10K Cached Tokens
The OpenRouter post runs the same hypothetical agent: 6 turns, the same 10,000 tokens of repeated content (system prompt + tool definitions + schemas + policy context) on every turn. Output tokens and changing messages are excluded.
| Scenario | Turn 1 | Turns 2–6 | Total cost vs. 1 uncached turn |
|---|---|---|---|
| No caching | Full input | Full input each turn | 6.0x |
| Anthropic 5-min cache + sticky routing | 1.25x write | 0.1x reads | 1.75x |
| Free-write provider + 0.25x reads | 1.0x input/write | 0.25x reads | 2.25x |
| Free-write provider + 0.5x reads | 1.0x input/write | 0.5x reads | 3.5x |
Read the table as: "for the same repeated content, the total token cost across 6 turns is N times what one uncached turn would cost."
Anthropic with sticky routing is the 3.4x cheaper than uncached baseline. Free-write providers with 0.5x reads (Groq) are still 1.7x better than uncached, but a long way behind Anthropic's aggressive cache-read pricing.
The savings grow with the number of turns. A 20-turn deep-research agent with a 30K-token prefix sees the gap widen by another factor.
Why Doesn't a Warm Cache Always Help?
This is the gotcha most engineers hit first. A warm cache only helps if the next request lands on the same provider endpoint that holds the cached prefix. OpenRouter fronts 70+ providers; on each turn, the router picks one. Turn two can route to a different provider — and you pay full price even though "the cache should have been warm."
OpenRouter's sticky routing is the fix. After a cached request succeeds on a provider, OpenRouter pins follow-up requests for the same model back to that provider endpoint when its cache-read pricing is cheaper than normal input. If the sticky provider becomes unavailable, OpenRouter falls back to the next available provider instead of failing the request.
The pinning uses a key. By default, OpenRouter hashes the first system or developer message and the first non-system message. That works if those opening messages stay the same. It does not work if the system prompt changes between turns, or if you inject a per-request timestamp into the prefix.
Force a Warm Cache From Turn One With session_id
For agent loops, the default hashing key is fragile. OpenRouter recommends passing a stable session_id for the conversation, ticket, or workflow run:
- Without
session_id, sticky routing only kicks in after a cache hit is observed. On turn one there's no cache yet, so the router has no signal to pin to. Turn two might land on a cold endpoint. - With
session_id, OpenRouter uses the session ID directly as the sticky routing key. Stickiness activates after the first successful request — before any cache hit has happened. For multi-turn agents, that is the difference between a cache that is reliably warm from turn one and one that is only sometimes warm.
The implementation in your OpenRouter client is one line:
import requests
response = requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers={"Authorization": f"Bearer {OPENROUTER_API_KEY}"},
json={
"model": "anthropic/claude-sonnet-4.6",
"messages": [...], # your agent's full message history
"session_id": "support-ticket-9821", # stable per-conversation key
# Optional: explicitly set cache TTL on Anthropic 1-hour models
# "provider": {"cache_control": {"ttl": "1h"}}
}
)
For ticket-style workflows where the agent runs against a stable identifier (ticket ID, thread ID, user ID, conversation ID), session_id is the cheapest optimization available.
How Do I Confirm Prompt Caching Is Working?
Three fields in the OpenRouter response confirm caching is live:
usage.prompt_tokens_details.cached_tokens— number of input tokens served from cache. Any value above zero confirms a hit.usage.prompt_tokens_details.cache_write_tokens— number of input tokens stored on the write turn.usage.cache_discount— per-generation cost effect (negative on the write turn if writes are paid, positive on later cache-read turns).
You can also inspect the detail view on the Activity page in the OpenRouter dashboard, or hit /api/v1/generation for full per-turn telemetry.
A practical health check in production:
import requests
def cache_health_check(response_json):
usage = response_json.get("usage", {})
details = usage.get("prompt_tokens_details", {})
cached = details.get("cached_tokens", 0)
discount = usage.get("cache_discount", 0)
return {
"cached_tokens": cached,
"cache_discount": discount,
"cache_active": cached > 0,
}
If cache_active stays False across multiple turns, you have one of the four common cache-miss causes.
Why Does Your Cache Miss (and How to Fix Each Cause)?
When caching looks broken, it almost always comes down to one of four things:
- Prompt is too short. Each provider has a minimum cacheable token count — Anthropic requires 1,024 tokens, OpenAI requires 1,024, Gemini requires 4,096. Short prompts won't trigger caching regardless of how stable they are.
- Cache expired. Anthropic's default TTL is 5 minutes; the 1-hour TTL requires explicit
ttl: "1h". If a turn is idle longer than the TTL, the prefix is gone. - Opening content changed. Any change to the system prompt, tool definitions, or the first user message invalidates the cache prefix hash. Even adding a current timestamp into the system message breaks it.
- Request moved to a different provider. Without
session_id, the router can hand turn two to a different provider than turn one. The cache is warm on provider A; your request lands on provider B and pays full price.
The fixes are mechanical:
- For (1): consolidate small prompts or accept that short requests don't benefit from caching.
- For (2): pick a TTL that matches your agent's typical turn cadence. For 1-hour Anthropic caching, set
provider: { cache_control: { ttl: "1h" } }. - For (3): move any per-request data (timestamps, request IDs, user-specific tokens) to the end of the prompt, not the start.
- For (4): set
session_id. Without it, sticky routing only kicks in after a cache hit, which is too late for turn one.
Does Caching Work With the Auto Router?
Yes. With session_id set, router models such as Auto Router and Pareto Router pin both the resolved model and the provider endpoint for the session. Without session_id, Auto Router is allowed to switch models between turns, which is fine for exploration but invalidates any cache the previous model would have held.
If you are using Auto Router for cost optimization, the value of session_id is even higher. It tells the router "stay on the model you picked for this conversation." Without it, you may pay cache-write costs on every turn because the model flips and the prefix is new each time.
One catch: if you set provider.order yourself, your explicit order wins over sticky routing. To get sticky routing on a multi-provider model, leave provider.order unset and let OpenRouter pick. Use the provider routing controls only when you have a specific provider order requirement that overrides the cache benefits.
Putting It Together: The Agent-Loop Checklist
For any agent that sends the same expensive content every turn:
- Put stable content first — system prompt, tool definitions, JSON schemas, policies, long-lived context.
- Put changing content later — user messages, tool results, timestamps, run-specific metadata.
- Set a stable
session_idfor the conversation, ticket, or workflow run. - Inspect
cached_tokensandcache_discountin the response to confirm reads are happening. - For 1-hour Anthropic TTLs, set
provider: { cache_control: { ttl: "1h" } }. - Don't set
provider.order— let sticky routing pick the warm endpoint.
The cheap-token trick is mechanical, but the order matters. If you fix the cache reads but the opening prefix keeps changing, no amount of session_id magic will save you. Stable prefix + stable session ID + provider that offers low cache reads is the combination that turns 6.0x into 1.75x.
Affiliate Recommendation: FreeModel for Multi-Provider Agent Routing
If you are running multi-turn agents across multiple model providers, FreeModel offers a unified API surface that aggregates many of the same providers OpenRouter does, with its own routing and caching layer. For workloads where you don't need every provider OpenRouter supports but want similar cache-routing behavior, FreeModel is a leaner alternative worth benchmarking against your current setup.
For OpenRouter itself, the public affiliate program is at openrouter.ai/affiliates — link your readers to that page if you cover OpenRouter in your own product or newsletter.
FAQ
How much do cached tokens cost on OpenRouter?
Cache reads cost 0.1x to 0.5x of normal input pricing, depending on the provider. Anthropic, DeepSeek, and Alibaba Qwen can read at 0.1x. OpenAI reads at 0.25x-0.50x. Gemini, Grok, and Moonshot read at 0.25x. Groq reads at 0.5x. Cache writes cost between free (Gemini, Grok, Moonshot, pre-GPT-5.6 OpenAI, Groq) and 2.0x input (Anthropic 1-hour TTL). Verified from the OpenRouter blog post dated 2026-07-21.
Why is prompt caching not working through OpenRouter?
The common causes are a prompt below the provider's token minimum (Anthropic requires 1,024, Gemini requires 4,096), an expired cache (5-min default TTL on Anthropic), an unstable prompt prefix (any change to the first system/developer message breaks the hash), or provider drift between turns. Set a stable session_id, put per-request data at the end of the prompt, and inspect cached_tokens to confirm hits.
Does OpenRouter support prompt caching across all providers?
OpenRouter supports prompt caching across all providers and models that implement it. Most providers enable it automatically - Anthropic and Alibaba Qwen use cache_control for explicit caching. Check the OpenRouter prompt caching docs for the per-model breakdown; not every model on every provider implements the feature.
How do I check whether caching saved money?
Inspect usage.prompt_tokens_details.cached_tokens for cache reads and cache_write_tokens for cache writes. A cached_tokens value above zero confirms a hit. You can also read cache_discount in the response to see the per-generation cost effect. On providers with paid writes, you may see a negative discount on the write turn because the cache write costs more than normal input. On later cache-read turns, the discount should turn positive.
What is sticky routing on OpenRouter?
Sticky routing pins follow-up requests to the provider that holds the warm cache. After a cached request succeeds on a provider, OpenRouter routes later requests for the same model back to that endpoint when its cache-read pricing is cheaper than normal input. If the sticky provider becomes unavailable, OpenRouter falls back to the next available provider instead of failing the request.
Does caching work with the OpenRouter Auto Router?
Yes. With a session_id set, Auto Router and Pareto Router pin both the resolved model and the provider endpoint for the session. Without session_id, Auto Router may switch models between turns, which invalidates the cache. The combination of session_id + Auto Router gives you cost-optimized model selection with reliable cache reuse.
Should I use Anthropic or DeepSeek for the cheapest cache reads?
Both Anthropic and DeepSeek offer 0.1x cache reads, the cheapest tier on OpenRouter. Anthropic charges 1.25x for the 5-min TTL write (or 2.0x for 1-hour). DeepSeek charges 1.0x for the write. If your agent loop is dense (turns every few minutes), Anthropic's higher write cost is quickly amortized; for sparser sessions, DeepSeek's lower write cost may net out cheaper.
What happens if I set provider.order myself?
Your explicit provider order wins over sticky routing. The request will always land on your first available provider, even if a cached prefix is sitting on a different endpoint. Use the provider routing controls only when you have a specific provider preference that overrides the cache benefits. For most agent workloads, leave provider.order unset.
How long does an OpenRouter cache last?
It depends on the provider and the TTL you set. Anthropic's default is 5 minutes; setting ttl: 1h extends it to one hour. OpenAI pre-GPT-5.6 caches for up to 5-10 minutes. Gemini's implicit cache TTL is around 1 hour. Alibaba Qwen's cache_control TTL is configurable per request. For long-running agents, the 1-hour Anthropic TTL or 1-hour Gemini implicit cache will cover most conversation patterns without per-turn write costs.
Can I disable prompt caching on OpenRouter?
Yes. Set provider: { cache_control: { ttl: no-cache } } on Anthropic or Alibaba Qwen to opt out. On other providers where caching is implicit and free, there is no per-request opt-out - caching happens automatically but only saves you money when reads occur. If you prefer not to cache at all, route to providers that don't implement it (and pay full input price each turn).