TLDR
An LLM call isn't made of two token types but of five, each with its own price. If you use prompt caching well, a repeated prompt costs about 90 % less. If you use it badly, the first call costs 25 % more and you save nothing afterwards. Routers decide whether caching happens at all, and for open-weight models some charged far more than their listed price. Every number in this series is measured; scripts and raw data are public on GitHub.
Introduction
Price per million input tokens, price per million output tokens, done: that's what every price table looks like. The invoice at the end of the month still looks different. The culprit is three levers that no price table shows: prompt caching, reasoning effort ("thinking level") and the choice of provider or router.
This article opens a series. It summarises what we measured on 19 October 2026 at OpenAI, Anthropic, xAI, Google Gemini, Mistral, IONOS and the routers Cortecs, EU Router, Requesty and OpenRouter. The four deep dives follow over the next weeks.
We don't compare feature lists. We measured, with the same prompts and the same evaluation, and every statement has evidence behind it.
1. One call, five prices

Price-wise, a single call splits into five token types:
| Token type | What it is | Claude Sonnet 5 | GPT-6.1 Sol | Grok 4.7 | Gemini 3.8 Flash |
|---|---|---|---|---|---|
| Input (uncached) | Part of the prompt that is processed again | $2.00 | $2.00 | $2.00 | $0.75 |
| Cache read | Part of the prompt served from the cache | $0.20 (0.1×) | $0.10 (0.05×) | $0.50 (0.25×) | $0.075 (0.1×) |
| Cache write | Part of the prompt written to the cache | $2.50 / $4.00 (5 min / 1 h) | $2.50 (1.25×) | – | – |
| Output | The answer | $10.00 | $10.00 | $6.00 | $3.75 |
| Reasoning | "Thinking" before the answer | like output | like output | like output | like output |
Prices per 1 million tokens, as of 2026-10-19, from the providers' pricing pages or pricing APIs.
Anthropic charges a cache write at 1.25× the input price for 5 minutes and 2× for 1 hour. The cache-read factor isn't uniform even within one provider: Claude Sonnet 5.5 reads at 0.05×, Claude Sonnet 5 at 0.1×. At OpenAI, the read factor for GPT-6.1 Sol is 0.05×, not the often-quoted 0.1×. xAI even publishes its prices through an API, cache price included.
Note: A token isn't the same size everywhere. The same system prompt counted 7,229 tokens on Claude and 4,568 on OpenAI. That's a 58 % difference. So a price comparison per million tokens compares apples with slightly smaller apples.
On the accounting itself: every response contains a usage block in which the provider lists the tokens consumed. At Anthropic, input_tokens doesn't include cached tokens; in OpenAI-compatible APIs, prompt_tokens does. The field names for the same quantity differ at every provider anyway. If you recalculate costs yourself, you have to normalise this per provider. Otherwise you count cached tokens twice or not at all.
2. The three levers
2.1 Prompt caching
When the start of a prompt (the prefix) repeats, such as the system prompt, tool definitions or documents, the provider can read it from a cache. With Claude Sonnet 5, our 7,200-token prompt cost 1.45 cents uncached, 1.81 cents with a cache write and 0.15 cents from the cache. So the first call is more expensive, and from the second call on you save about 90 %.
The mechanics differ by provider:
- Anthropic caches only when you ask for it with
cache_control, a marker in the request; without the marker, 0 of 4 follow-up calls hit the cache. - OpenAI, xAI and Gemini cache automatically. OpenAI from 1,024 tokens , Gemini 3.8 Flash from 4,096 , and Gemini caches only part of the prompt.
- Below the minimum size, nothing happens: no cache, no error message.
This is what it looks like in the request: at Anthropic, cache_control isn't a header but a field in the content block. OpenAI needs nothing at all. Both report the hit in the response, just under different names (second call each, trimmed from our raw data):
// Anthropic – POST /v1/messages
{
"model": "claude-sonnet-5-5",
"system": [{
"type": "text",
"text": "You are the assistant of …",
"cache_control": { "type": "ephemeral" } // ← cache marker on the block
}],
"messages": [ … ]
}
// Response
"usage": {
"input_tokens": 16, // only the uncached rest
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 7224, // ← from the cache
"output_tokens": 4
}
// OpenAI – POST /v1/responses
{
"model": "gpt-6.1-sol",
"instructions": "You are the assistant of …", // no marker needed
"input": "Reply with the single word OK."
}
// Response
"usage": {
"input_tokens": 4576, // includes the cached tokens
"input_tokens_details": {
"cached_tokens": 4573 // ← from the cache
},
"output_tokens": 5
}
Part 1 of the series shows what breaks the cache, among other things a change of reasoning effort, which costs the cache on some models and not on others.
2.2 Reasoning effort
Almost every current model can "think" before it answers, and almost every provider names the control differently: reasoning.effort, output_config.effort, thinkingLevel, reasoning_effort. We sent each of the seven usual values from none to max to every model. The result is a patchwork:
- GPT-6.1 Sol rejects
noneandminimal. - Claude rejects
noneandminimalbut acceptsmax; the oldbudget_tokensgets an HTTP 400. - Mistral accepted only
noneandhigh. - xAI can't be switched off:
noneis rejected.
Thinking is expensive in any case: reasoning tokens are billed as output, even when the answer doesn't show them. Claude Haiku 5.5 billed 53 thinking tokens for an eight-character answer without showing a single one.
In the request, the control sits in a different place at each provider, and in the response the thinking tokens have a different name each time (same arithmetic puzzle with high, trimmed):
// OpenAI – POST /v1/responses
{
"model": "gpt-6.1-sol",
"input": "A bat and a ball cost 1.10 EUR …",
"reasoning": { "effort": "high" } // ← object reasoning, field effort
}
// Response
"usage": {
"output_tokens": 24,
"output_tokens_details": { "reasoning_tokens": 14 } // included in output_tokens
}
// Anthropic – POST /v1/messages
{
"model": "claude-haiku-5-5",
"messages": [ … ],
"output_config": { "effort": "high" } // ← object output_config
}
// Response
"usage": {
"output_tokens": 62,
"output_tokens_details": { "thinking_tokens": 53 } // included in output_tokens
}
// Gemini – POST /v1beta/models/gemini-3.8-flash:generateContent
{
"contents": [ … ],
"generationConfig": {
"thinkingConfig": { "thinkingLevel": "high" } // ← two levels deep
}
}
// Response: usageMetadata instead of usage
"usageMetadata": {
"candidatesTokenCount": 5,
"thoughtsTokenCount": 247 // on top of the 5 answer tokens
}
Routers accept values that the provider itself rejects. Cortecs accepted none for Claude; Anthropic direct didn't. A router that accepts every value is polite. Whether it also follows it is a different question. Part 2 looks into it.
2.3 Routers and hosts

Routers such as Cortecs, EU Router or Requesty bundle many models behind one API. They offer choice, failover and — at the European providers — processing in the EU. The provider a router actually forwards the call to is called the upstream. Fixing it in the request instead of letting the router choose is called pinning. Hosts such as IONOS, by contrast, run the models themselves. For costs, this means:
- Without
cache_control, Claude doesn't cache through any of the routers; with the marker, it caches through all of them. EU Router passes the marker through, although its docs don't mention it. - The router picks the upstream. Without a preference, Cortecs sent Claude to Google Vertex — 0 of 4 cache hits. Pinned to AWS Bedrock: 4 of 4.
- Listed isn't charged. For open-weight models (models whose weights are freely available), the price actually charged by Cortecs and EU Router was up to 170 % above the listed price, because the router chose a more expensive upstream. This surprised us most: for open-weight models through routers, the listed price is more of a floor.
- Surcharges exist too. EU Router lists Claude Sonnet 5 10 % above Anthropic, OpenRouter and Requesty.
For open-weight models, the host is the deciding factor anyway: the same gpt-oss-120b cached at Cortecs and Requesty, but not at IONOS.
3. Cost transparency: who delivers what?
To control costs per application, customer or department, you need costs per call. Not every provider delivers them:
- Per call, in the response: xAI in
cost_in_usd_ticks, Requesty inusage.cost, EU Router in euros and Cortecs as an integer in micro-euros, contrary to its own API reference. - Only aggregated via admin APIs, i.e. management interfaces with their own key: OpenAI reports costs only per day. Anthropic blocks this API for individual organisations.
- Not via API at all: for the Gemini API there's only Cloud Billing (not measurable).
Where costs appear in the response, they're in the usage block, but in a different unit each time (trimmed from our raw data):
// xAI – POST /v1/responses (grok-4.7)
"usage": {
"input_tokens": 5809,
"input_tokens_details": { "cached_tokens": 5760 },
"output_tokens": 65,
"cost_in_usd_ticks": 33680000 // ← 10 bn ticks = $1, so $0.003368
}
// Cortecs – POST /v1/chat/completions (gpt-oss-120b)
"usage": {
"prompt_tokens": 4636,
"completion_tokens": 16,
"cost": 631, // ← integer in micro-euros, so €0.000631
"cost_details": { "prompt_cost": 613, "cache_read_cost": 9, "completion_cost": 9 }
}
// EU Router – POST /api/v1/chat/completions (claude-sonnet-5)
"usage": {
"prompt_tokens": 7239,
"completion_tokens": 4,
"cost": 0.0159698,
"cost_currency": "USD",
"cost_eur": 0.01419156277 // ← the same amount in euros
}
Where the provider reports costs, our formula matched to the cent: 0.0 % deviation at xAI, Requesty, EU Router and OpenAI's daily totals.
Tip: xAI, Cortecs, EU Router, Requesty and OpenRouter publish prices through an API; OpenAI, Mistral and Gemini publish them only on web pages. A price catalogue like the one we run for CompanyWizard closes exactly this gap. Part 3 shows how to build one from models.dev, LiteLLM and the router APIs.
4. The comparison matrix
As of 19 October 2026. Every cell is measured; details and raw data are in the repository.
| Provider | Caching (hit on 2nd call) | Cache control | Cache write in usage | Effort values accepted (of 7) | Cost per call | Prices via API |
|---|---|---|---|---|---|---|
| Anthropic | 100 % | explicit (cache_control) |
yes | 5 | no | no |
| OpenAI | 100 % | automatic | yes (GPT-5.6+) | 4–6 | no | no |
| xAI | 99 % | automatic | no | 5 | yes (USD) | yes |
| Google Gemini 3.8 Flash | 66 % | automatic | no | 3 | no | no |
| Mistral | partly (Magistral only) | prompt_cache_key |
no | 2 | no | no |
| IONOS (open weight) | 0 % | – | no | 3–4 | no | no |
| Cortecs | depends on upstream | automatic / pinned | yes | 7 | yes (µEUR) | yes (EUR) |
| EU Router | with cache_control |
passed through | yes | 5–7 | yes (EUR) | yes |
| Requesty | with cache_control or auto_cache |
passed through / automatic | yes | 6 | yes (USD) | yes |
| OpenRouter | with cache_control |
passed through, sticky routing | yes | 6–7 | yes (USD) | yes |
OpenRouter passes cache_control through, including the 1-hour TTL (the lifetime of the cache entry) , and keeps follow-up calls with a session key, a freely chosen ID per conversation, on the same upstream. This is called sticky routing.
5. Which provider for which purpose
| If what matters to you is … | … then | Why |
|---|---|---|
| maximum savings on long, repeated prompts | Anthropic or OpenAI direct, set the cache deliberately | 90–95 % discount on cache reads, writes visible in usage |
| caching without code changes | OpenAI, xAI | they cache automatically, with no marker in the request |
| cost per call for controlling | xAI, Requesty, EU Router, Cortecs | cost field in every response |
| processing in the EU with Claude | router with a pinned EU upstream and cache_control |
otherwise the router decides on upstream and cache |
| open-weight models at list price | the host directly, or a router with a fixed upstream | routers that pick the upstream freely charged up to 170 % more |
| fine control of reasoning effort | OpenAI, Anthropic direct | routers accept values they can't pass on |
6. How we solved it in .NET
In CompanyWizard, all providers are priced with one formula. If a cache price is missing, the input price applies — better slightly overestimated than costs left out:
public static Decimal Calculate(ModelDefinition model, String? promptCacheTtl, TurnTokenUsage tokens)
{
var billedInput = Math.Max(0, tokens.Input - tokens.CacheRead - tokens.CacheWrite);
var readPrice = model.CacheReadPricePer1M ?? model.InputPricePer1M;
var writePrice = (promptCacheTtl == OneHourTtl ? model.CacheWrite1hPricePer1M : model.CacheWritePricePer1M)
?? model.InputPricePer1M;
return (billedInput * model.InputPricePer1M
+ tokens.CacheRead * readPrice
+ tokens.CacheWrite * writePrice
+ tokens.Output * model.OutputPricePer1M) / TokensPerMillion;
}
Source: ModelCostCalculator.cs (excerpt)
The formula is simple. The real work happens before it: normalising the usage fields so that tokens.Input means the same thing at every provider.
Lesson Learned: In CompanyWizard, Anthropic's automatic cache marker at first never hit across several conversation turns. A system message with the current date sat in front of the actual system prompt and made every prefix unique. Only a separate breakpoint on the system prompt (a marker up to which Anthropic caches the prefix), with the date message behind it, brought the hits.
7. How we measured
- One reference date: all measurements on 19 October 2026, with separate measurement keys.
- Raw HTTP instead of SDKs: every call is archived as JSON, without headers and without keys.
- A claims register: 91 statements, each with a status (confirmed, refuted, deviating, not measurable, not measured) and evidence.
- Everything can be re-measured: scripts, prompts, raw data and tables are at github.com/evanto-media-ag/llm-caching-reasoning-costs.
What we deliberately left open: Gemini 4 Argon couldn't be measured because of a quota limit. We didn't reconcile the admin APIs of Anthropic (blocked for individual organisations) and Cortecs (no management key). We tested DeepSeek only through routers, not through its own API. And a measurement on one day is a snapshot. Prices and models change every month.
Disclosure: evanto uses Cortecs as its partner for Managed AI in CompanyWizard. The measurements ran on separate measurement accounts; Cortecs didn't see the results before publication.
8. Measure it yourself with curl
To see the effect yourself, you don't need a programming language or an SDK, just curl, jq and an API key in an environment variable. Both examples use our test prompt from the repository. At about 7,200 tokens it is safely above the minimum size for caching. With a short prompt you would see nothing, because below that size caching silently doesn't happen.
The examples run in bash or zsh, so on macOS and Linux, and on Windows in WSL or Git Bash. Set the key once per terminal session beforehand, e.g. with export ANTHROPIC_API_KEY=… or export XAI_API_KEY=…. First we download the prompt. -s suppresses the progress bar, -O saves the file as large.txt in the current directory:
curl -sO https://raw.githubusercontent.com/evanto-media-ag/llm-caching-reasoning-costs/main/prompts/large.txt
8.1 Caching and reasoning effort at Anthropic
The same call three times, with a cache marker on the system prompt and changing reasoning effort:
ask() {
jq -n --rawfile sys large.txt --arg effort "$1" '{
model: "claude-haiku-5-5",
max_tokens: 256,
system: [{type: "text", text: $sys, cache_control: {type: "ephemeral"}}],
messages: [{role: "user", content: "Reply with the single word OK."}],
output_config: {effort: $effort}
}' | curl -s https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d @- | jq '.usage'
}
ask high; ask low; ask high
What happens here:
ask() { … }defines a shell function calledask. The call is written out only once and can be repeated withask high,ask lowand so on. The word afteraskends up in$1and thus in the effort value.jq -nbuilds the JSON request.--rawfile sys large.txtreads the prompt into the variable$sysand escapes quotes and line breaks along the way;--arg effort "$1"passes the effort value. Hand-written JSON would break on the long prompt.cache_control: {type: "ephemeral"}is the cache marker. Anthropic keeps the entry for 5 minutes, so all three calls have to run within that time. For 1 hour, the marker is{type: "ephemeral", ttl: "1h"}.| curl … -d @-sends the JSON produced byjqas the request body.@-means: read the body from standard input.anthropic-versionis a required header at Anthropic.| jq '.usage'shows only the usage block of the response. To see the full response, writejq ..
This is what it looked like for us (Claude Haiku 5.5, raw data from 2026-10-19):
| Call | effort |
cache_creation_input_tokens |
cache_read_input_tokens |
output_tokens |
of which thinking_tokens |
|---|---|---|---|---|---|
| 1 | high | 7,223 | 0 | 19 | 15 |
| 2 | low | 0 | 7,223 | 4 | 0 |
| 3 | high | 0 | 7,223 | 35 | 31 |
Call 1 writes the cache, calls 2 and 3 read it. So on this model, changing the reasoning effort didn't break the cache. The answer was "OK" every time, yet at high up to 35 output tokens were billed instead of 4. Your numbers will differ by a few tokens, and more so for thinking: effort is a guideline, and the model decides for itself whether it actually thinks. In a control run on 2026-10-19, call 1 didn't think at all and call 3 used 21 thinking tokens.
To vary it: without cache_control, cache_read_input_tokens stays at 0. Other effort values and the control names of the other providers are in section 2.2.
8.2 Recalculating costs at xAI
xAI caches automatically and reports the cost in every response. Two identical calls are enough:
ask_xai() {
jq -n --rawfile sys large.txt '{
model: "grok-4.7",
instructions: $sys,
input: "Reply with the single word OK.",
max_output_tokens: 16,
store: false
}' | curl -s https://api.x.ai/v1/responses \
-H "Authorization: Bearer $XAI_API_KEY" \
-H "content-type: application/json" \
-d @- | jq '.usage | {input_tokens, cached: .input_tokens_details.cached_tokens,
output_tokens, reasoning: .output_tokens_details.reasoning_tokens,
cost_in_usd_ticks}'
}
ask_xai; ask_xai
New compared with 8.1:
- xAI's Responses API expects the system prompt as
instructionsand the question asinput. store: falsemakes sure xAI doesn't store the response on its servers.max_output_tokens: 16limits the answer. Output tokens still came out higher for us, because reasoning comes on top.- The
jqfilter at the end picks only the five values you need for the recalculation from the usage block and gives them short names.
For us, the second call reported 5,809 input tokens, 5,760 of them from the cache, 65 output tokens (64 of them reasoning) and 33,680,000 ticks. With the prices from section 1 you can recalculate this:
(5,809 − 5,760) × $2.00 = $98
5,760 × $0.50 = $2,880
65 × $6.00 = $390
$3,368 per 1M tokens = $0.003368
Ten billion ticks are one dollar, so $0.003368 is exactly 33,680,000 ticks. The first call, with hardly any cache hits, cost 102,860,000 ticks, about three times as much.
At other providers the endpoint, the control name and the usage fields change, but the principle stays: send the prompt twice, compare the usage, recalculate with the price table. Part 3 shows which field is where.
Conclusion: five rules for realistic LLM costs
- Count all five token types. Input, cache read, cache write, output, reasoning.
- Caching isn't a switch, it's prompt architecture. Stable parts first, changing parts last, mind the minimum size.
- Check effort values against the specific model. An accepted value isn't a followed value.
- Pin the upstream when you use a router, if cache or price matters.
- Measure for yourself. Section 8 shows how with two curl calls. Where providers report costs, their figures matched ours to the cent.
The series
- Part 1: Prompt caching compared — what carries the cache and what breaks it
- Part 2: Reasoning effort compared — seven values, twelve interpretations (coming soon)
- Part 3: Cost transparency — formulas, field names, price sources (coming soon)
- Part 4: Routers compared — Cortecs, EU Router, Requesty, OpenRouter (coming soon)
References
- Measurement repository: evanto-media-ag/llm-caching-reasoning-costs
- OpenAI: Prompt caching, Pricing
- Anthropic: Prompt caching, Pricing
- xAI: Prompt caching, Cost tracking
- Google: Gemini caching, Pricing
- Cortecs: Prompt caching · EU Router: API · Requesty: Auto-caching
Planning an AI application and want a realistic cost estimate up front? Let's spend 30 minutes on your workflow. The call is free, and you leave with suggestions you can put into practice right away. Book a 30-minute call
Note: Article created with AI assistance.