The Cheapest Token Is a Cached One: Prompt Caching + Sticky Routing

OpenRouter ·

The Cheapest Token Is a Cached One: Prompt Caching + Sticky Routing

Your agent sends the same system prompt, tool definitions, schemas, and policy instructions on every turn. In a 6-turn session, you can get billed for that same opening block 6 times, even though the only thing that changed is the user’s latest message or the agent’s latest tool result.

Prompt caching fixes that. The provider reads the repeated part of your prompt from cache instead of charging you full price for it every time. Sticky routing keeps that working across turns by sending a session back to the same provider that holds the warm cache.

This post covers the money side: what cached tokens cost, why cache reads and writes are priced differently, how session_id keeps an agent’s session warm from turn one, and how to check that caching is actually working.

Tl;dr

  • A cache read costs 0.1x to 0.5x of a fresh input token, depending on the provider. On Claude Sonnet 4.6, a cache read runs at $0.30/M against $3.00/M input, exactly 0.1x.
  • The first request pays a cache write. Anthropic writes cost 1.25x (5-minute TTL) or 2.0x (1-hour TTL) of input, so a single unreused write costs more than not caching at all.
  • A warm cache only helps if your next request lands on the same provider endpoint. Across 70+ providers, turn two can hit a cold endpoint, and you pay full price.
  • Our sticky routing pins follow-up requests to the provider holding the warm cache, and session_id forces that from the first successful request, before any cache hit has happened.
  • Cache misses come from 4 causes: a prompt that’s too short, an expired cache, an opening block that keeps changing, or a request that moved to a different provider. Check cached_tokens in the usage response to confirm a hit.

How much does prompt caching cut your token cost?

A cache read costs 0.1x to 0.5x of normal input pricing, depending on the provider. That range is why caching can make agent loops much cheaper.

The repeated part is usually the expensive part: a long system prompt, tool definitions, JSON schemas, guardrails, retrieved documents, or examples that keep the model consistent. Without caching, each turn pays full price for all of it again. With caching, the first request writes it to the cache, and later requests read it back at the cheaper rate.

Here’s the provider-level view:

ProviderCache readCache writeHow to enable
Anthropic Claude (5-min TTL)0.1x input1.25x inputAutomatic or explicit
Anthropic Claude (1-hour TTL)0.1x input2.0x inputExplicit (ttl: "1h")
OpenAI (before GPT-5.6)0.25x-0.50x inputFreeAutomatic
OpenAI (GPT-5.6 and later)0.25x-0.50x input1.25x inputAutomatic or explicit
Google Gemini (implicit)0.25x inputFreeAutomatic
Grok (xAI)0.25x inputFreeAutomatic
Moonshot AI0.25x inputFreeAutomatic
Groq0.5x inputFreeAutomatic (Kimi K2 models)
DeepSeek0.1x input1.0x inputAutomatic
Alibaba Qwen0.1x input1.25x inputExplicit (cache_control)
Z.AI~0.2x inputFreeAutomatic

The prompt caching docs have the full breakdown. The exact dollar amount still depends on the model and provider route; the multiplier tells you how cached input compares with normal input for that provider.

For agent builders, the pattern is simple: the first turn may pay to set up the cache, but every turn after that gets much cheaper as long as the same opening block is reused.

Where does the cost go: cache writes versus cache reads?

Prompt caching has two costs: the write and the read.

The write happens when the provider stores the reusable part of the prompt. The read happens when a later request reuses that stored content. You come out ahead once the same content gets read enough times to cover the write.

On some providers, the write costs more than normal input. Anthropic cache writes cost 1.25x input for the default 5-minute TTL and 2.0x input for the 1-hour TTL. A single Anthropic cache write that’s never reused costs more than sending the same prompt without caching.

For a one-off request, caching may not help. For a multi-turn agent, repetition is the default: the agent carries the same instructions, tools, schemas, and policy context across the whole session. So the write pays for itself over a few turns.

Use the 5-minute cache lifetime (TTL) for short bursts where the next turn arrives quickly. Use the 1-hour one when a session may pause long enough for the default cache to expire, but the content is still worth keeping around.

Why doesn’t a warm cache always help on the next request?

A warm cache only helps if the next request lands on the provider endpoint that holds it.

When requests can route to many providers, turn one can write a cache on one provider while turn two lands somewhere else. The second provider has no warm cache to read from. The request still works, but you pay full price and cached_tokens stays low or zero.

That’s why we pair sticky routing with prompt caching. After a cached request, we route follow-up requests for the same model back to the same provider endpoint when that provider’s cache-read pricing is cheaper than normal input. If that sticky provider becomes unavailable, OpenRouter falls back to the next available provider instead of failing the request.

By default, OpenRouter recognizes a conversation by hashing its first system or developer message and its first non-system message. That works when those opening messages stay the same.

Agents often break that. Some rewrite their first messages as they summarize state, reorder tool context, or add new run metadata. When the opening messages change, the hash changes, and the conversation can land on a different provider. The fix is an explicit session_id.

Diagram of an agent session where session_id keeps turns 1 through N on the same provider for cache writes and cheap cache reads, with automatic failover to a new provider if the sticky one fails

Force a warm cache from turn one with session_id

For agent loops, set session_id. When you pass it, OpenRouter uses it directly as the sticky routing key instead of deriving a key from the opening messages.

With session_id, sticky routing kicks in after the first successful request, before any cache hit has happened. Without it, stickiness only starts after a cache hit is detected. For multi-turn agents, that’s the difference between a cache that’s reliable from turn one and one that’s only sometimes warm.

You can send session_id as a top-level request body field or through the x-session-id header. Keep it stable for the conversation or agent run, and keep it under 256 characters.

curl https://openrouter.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4.6",
    "session_id": "my-agent-session-abc123",
    "messages": [{"role": "system", "content": "..."}]
  }'
from openrouter import OpenRouter

client = OpenRouter()

resp = client.chat.send(
    model="anthropic/claude-sonnet-4.6",
    session_id="my-agent-session-abc123",
    messages=[{"role": "system", "content": "..."}],
)
import { OpenRouter } from '@openrouter/sdk';

const openRouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });

const response = await openRouter.chat.send({
  model: 'anthropic/claude-sonnet-4.6',
  session_id: 'my-agent-session-abc123',
  messages: [{ role: 'system', content: '...' }],
});

Use a value that matches the unit of work: a chat thread, ticket, workflow run, or agent task. Don’t create a new session_id for every turn, or requests stop landing on the provider that holds the cache.

If you use router models such as Auto Router or Pareto Router, session stickiness also pins the model the router picked, not just the provider. That keeps the conversation from switching models mid-session, so behavior stays consistent and the cache stays warm.

How do I confirm prompt caching is even working?

The fastest way to check is to inspect usage.

In the response, usage.prompt_tokens_details.cached_tokens shows how many tokens were read from cache. If it’s greater than zero, the request hit the cache. cache_write_tokens shows how many tokens were written during a cache-write request.

{
  "usage": {
    "prompt_tokens": 10339,
    "completion_tokens": 60,
    "total_tokens": 10399,
    "prompt_tokens_details": {
      "cached_tokens": 10318,
      "cache_write_tokens": 0
    }
  }
}

In this example, most of the prompt tokens came from cache, and this turn didn’t write a new cache entry.

You can inspect cache behavior in three places: the detail view on the Activity page, the /api/v1/generation API, and the usage.prompt_tokens_details object returned with API responses.

Use cache_discount to see what a generation saved. 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.

Annotated usage object showing cached_tokens, cache_write_tokens, and cache_discount fields and what each one confirms about caching

Why does your cache miss, and how do you stop it?

When caching looks broken, it usually comes down to one of 4 things: the prompt is too short, the cache expired, the opening content changed, or the request moved to a different provider.

The prompt is below the provider’s minimum

Every provider has a minimum prompt size, and below it nothing gets cached. On Anthropic, Claude Opus 4.5 through 4.8 and Claude Haiku 4.5 need 4,096 tokens; Claude Haiku 3.5 needs 2,048; Claude Sonnet 4, 4.5, and 4.6 (and Opus 4 / 4.1) need 1,024. OpenAI needs 1,024. Gemini 2.5 Pro needs 4,096; Gemini 2.5 Flash needs 1,024.

If your reusable content sits below that minimum, caching won’t start. Don’t pad the request with filler text just to force it. Use caching where you already have a lot of reusable content: tools, schemas, retrieved documents, examples, or policy text.

The cache expired between turns

Caches don’t live long. Anthropic’s default is 5 minutes, with a 1-hour option for longer sessions. Gemini’s implicit cache lasts about 3-5 minutes and doesn’t reset when you read from it. Once a cache expires, the next request has to write a new one.

If your users often pause between turns, use a longer TTL where supported, or build the agent to accept a new write after idle periods.

The start of the prompt keeps changing

Automatic and implicit caching work best when the start of the prompt stays the same. Put the stable stuff first: system instructions, tools, schemas, and fixed reference material. Put the changing stuff later: user questions, timestamps, temporary state, tool outputs, and short-lived metadata.

Small details count here. A timestamp in the first system message makes the prompt look new on every turn. Move it into a later user or tool message if it doesn’t need to be part of the cached content.

The request drifted to a different provider

A cache lives where it was written. If a later request routes to a different provider endpoint, that endpoint can’t read the earlier cache.

For agent workflows, set session_id and let sticky routing keep the session on the warm provider. One catch: if you set provider.order yourself, your order wins over sticky routing. Use provider routing controls if you need a specific provider order.

Putting caching and sticky routing together for an agent loop

If your agent sends the same content every turn, here’s the checklist:

  1. Put stable content first: system prompt, tool definitions, schemas, policies, and long-lived context.
  2. Put changing content later: user messages, tool results, timestamps, and run-specific state.
  3. Enable prompt caching for providers that need explicit cache_control.
  4. Set a stable session_id for the conversation or workflow run.
  5. Inspect cached_tokens and cache_discount to confirm that reads are happening.

For a rough picture, imagine an agent that repeats the same 10,000 tokens over 6 turns.

ScenarioTurn 1Turns 2-6Total cost (vs. 1 uncached turn)
No cachingFull inputFull input each turn6.0x
Anthropic 5-minute cache + sticky routing1.25x write0.1x reads1.75x
Free-write provider + 0.25x reads1.0x input/write0.25x reads2.25x
Free-write provider + 0.5x reads1.0x input/write0.5x reads3.5x

This example covers only the repeated content. It ignores the smaller changing messages and the model’s output tokens. The savings grow with the number of turns.

Worked example table comparing 10 turns without caching at full price against caching plus sticky routing, ending at roughly 75-90% fewer input tokens billed

When to use what:

  • Use automatic caching for multi-turn conversations where the reused content grows with the conversation.
  • Use explicit cache breakpoints when you know exactly which large blocks should be cached: retrieved documents, long reference files, character cards, CSV data, or policy text.
  • Use session_id for agent sessions, support tickets, chat threads, workflow runs, and any conversation where the opening messages may change between turns.
  • Use the 1-hour cache for longer Anthropic sessions where the default 5-minute one may expire between turns. Use the default for short, dense back-and-forths.

When your agent sends the same expensive content again and again, cached reads and sticky routing keep it from becoming the most expensive part of the loop.

FAQ

Does OpenRouter support prompt caching?

Yes. OpenRouter supports prompt caching across supported providers and models. Most providers enable it automatically, while Anthropic and Alibaba Qwen use cache_control for explicit caching. Cache reads cost 0.1x to 0.5x of normal input pricing depending on the provider, so a reused prefix gets much cheaper after the first request.

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 to 0.50x. Gemini, Grok, and Moonshot read at 0.25x. Groq reads at 0.5x.

Why is prompt caching not working through OpenRouter?

The common causes are a prompt below the provider’s token minimum, an expired cache, an unstable prompt prefix, or provider drift between turns. For agent workflows, start by setting a stable session_id, then check cached_tokens in the usage response, where any value above zero confirms a cache hit.

How do I keep a cache warm across an agent’s turns?

Pass a stable session_id for the conversation, ticket, or workflow run. OpenRouter uses it as the sticky routing key, so follow-up requests route back to the same provider endpoint that holds the warm cache. With session_id set, stickiness activates after the first successful request, before any cache hit is observed.

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, or open the detail view on the Activity page or the /api/v1/generation API.

Does caching work with the Auto Router?

Yes. With a session_id set, router models such as Auto Router and Pareto Router pin both the resolved model and the provider for the conversation, so follow-up turns keep hitting the same warm cache.