◉CLAUDE LABJP
●2.1.302 — Fork subagents are now on by default in claude -p, the Agent SDK and the desktop app. Turn them off with CLAUDE_CODE_FORK_SUBAGENT=0 (10/16)●2.1.301 — Unattended retries now stop on their own when a usage limit is hit instead of waiting (10/15). Latest is 2.1.304 (10/19)●SONNET 4.5 — Retires on the Claude API on 11/30, 40 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.302 — Fork subagents are now on by default in claude -p, the Agent SDK and the desktop app. Turn them off with CLAUDE_CODE_FORK_SUBAGENT=0 (10/16)●2.1.301 — Unattended retries now stop on their own when a usage limit is hit instead of waiting (10/15). Latest is 2.1.304 (10/19)●SONNET 4.5 — Retires on the Claude API on 11/30, 40 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/API & SDK
⬡ API & SDK/2026-09-07Intermediate

A 75% cheaper cache read moved one bill by 29% and another by 2.8%

Fable 5.1 and Mythos 5.1 changed the cache read multiplier from 0.1 to 0.025. Here is how to estimate your own saving from your token mix, and how to fix code that hard-codes the multiplier.

claude-api83prompt-caching15pricing8cost-optimization31token-usage

I sat down in early September to update a pricing table and stopped almost immediately. None of the per-token prices had moved.

What had moved was the multiplier. My cost helper carried a line reading cacheRead = input * 0.1, and I had quietly filed that 0.1 under "constants that never change." I had a habit of checking prices. I had no habit of checking multipliers.

Across the Lab sites I run a number of jobs that re-read a long operating guideline on every turn. Those are exactly the workloads this change should reward — and there had to be shapes it barely touches. So before pasting anything in, I worked out the numbers for myself.

The price did not change. The read multiplier did.

Prompt caching is billed as a multiplier on the base input price, and that is where the change landed.

Cache operationMultiplierDuration
5-minute cache write1.25x base input5 minutes
1-hour cache write2x base input1 hour
Cache read (hit)0.1x base input
Fable 5.1 and Mythos 5.1 only: 0.025x
Same as the preceding write

So a cache read on Fable 5.1 went from $1.00 to $0.25 per million tokens. Base input at $10, output at $50, and the two write rates at $12.50 and $20 all stayed exactly where they were. The exception currently covers those two models only — Opus 5, Sonnet 5, and Haiku 4.5 are still at 0.1x. The figures come from the Claude Platform pricing page.

If you compress this into "Fable 5.1 is 75% cheaper," you will hand someone a broken estimate. What got cheaper is one line of the invoice, the cache read line.

Estimate your own saving before you migrate

You only need four numbers, and they are already sitting in the usage block of your responses. Pull them from real traffic rather than guessing.

# usage from a single request
usage = {
    "input_tokens": 2000,               # fresh input that missed the cache
    "cache_read_input_tokens": 60000,   # read back from cache
    "cache_creation_input_tokens": 0,   # written this turn
    "output_tokens": 1500,
}
 
def request_cost(usage, base_in, base_out, read_mult, write_mult=1.25):
    """Cost of one request in USD. Prices are per million tokens."""
    return (
        usage["input_tokens"] * base_in
        + usage["cache_read_input_tokens"] * base_in * read_mult
        + usage["cache_creation_input_tokens"] * base_in * write_mult
        + usage["output_tokens"] * base_out
    ) / 1_000_000
 
before = request_cost(usage, 10.0, 50.0, read_mult=0.1)
after = request_cost(usage, 10.0, 50.0, read_mult=0.025)
print(f"{before:.6f} -> {after:.6f}  ({(before - after) / before:.1%} lower)")
# 0.155000 -> 0.110000  (29.0% lower)

The part that matters is that the multiplier is a parameter. Bake it in as a literal and your estimate drifts the moment you switch models — silently, which is the worse kind of wrong.

Three shapes, and a tenfold difference

I ran three requests of genuinely different character through the same function, holding the Fable-tier prices of $10 and $50 constant.

Workload shapecache read / new input / output0.1x0.025xReduction
Agent re-reading a long preamble each turn60,000 / 2,000 / 1,500$0.1550$0.110029.0%
Classification and summarisation batch20,000 / 500 / 300$0.0400$0.025037.5%
Short preamble, long generated output8,000 / 1,000 / 4,000$0.2180$0.21202.8%

The top row and the bottom row differ by roughly a factor of ten. Both received the identical 75% discount.

What separates them is the share of the bill that cache reads occupy in the first place: 38.7% for the agent, 50.0% for the batch, and 3.7% for the generation-heavy call. When output tokens carry the invoice, trimming the input side barely registers.

The announcement sets the discount rate. Your token mix sets the invoice. My first estimate took the headline figure as my own expected saving, and on the generation-heavy jobs it was nowhere close.

Move the multiplier out of your code and into the table

The fix is small. Keep the multiplier alongside the price, per model, rather than in the arithmetic.

PRICING = {
    # base_in, base_out, cache_read_mult (USD per million tokens)
    "claude-fable-5-1": (10.0, 50.0, 0.025),
    "claude-fable-5":   (10.0, 50.0, 0.1),
    "claude-opus-5":    (5.0,  25.0, 0.1),
    "claude-sonnet-5":  (2.0,  10.0, 0.1),
    "claude-haiku-4-5-20251001": (1.0, 5.0, 0.1),
}
 
def cost_for(model, usage):
    if model not in PRICING:
        # never let an unpriced model slide through as zero
        raise ValueError(f"no pricing registered for model: {model}")
    base_in, base_out, read_mult = PRICING[model]
    return request_cost(usage, base_in, base_out, read_mult)

To find the risky spots in your own repository, one line is enough.

grep -rn "0\.1\s*\*\|\* 0\.1\b" --include='*.py' --include='*.ts' src/ | grep -i cache

Because I believed prices move and multipliers do not, I had externalised the price table and left the multiplier in the code. These days I keep the price and the multiplier in the same record, so that updating one without the other is not possible.

This does not change how you choose between 5m and 1h

I expected it to. A read that costs a quarter of what it did ought to shift the TTL decision too.

When your calls sit more than five minutes apart but inside an hour, a 5-minute cache is rewritten every time. Solving for the number of calls per hour, K, at which the two options break even gives this:

Read multiplierBreak-even K (calls per hour)Conclusion
0.1x1.65Two or more calls favour the 1-hour TTL
0.025x1.61Two or more calls favour the 1-hour TTL

The boundary hardly moves, because the write multipliers of 1.25x and 2x dominate the comparison. The same holds for "is caching worth it at all" — a single read repays the write under either multiplier.

A cheaper read thins the bill of a setup where caching already works. It is not a reason to redesign your caching. If your hit rate is weak, switching models will not rescue it; I wrote up how to measure that in halving a monthly bill with prompt caching.

One next step

Take a single day of responses, sum cache_read_input_tokens, and work out what fraction of your total cost that line represents. Multiply that fraction by 0.75 and you have the ceiling on what a migration can give you.

I nearly skipped that step and spent an afternoon puzzled that the invoice had barely moved. Thank you for reading — I hope it saves you a round of rework.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⬡ API & SDK2026-04-26
How I Cut My Claude API Bill in Half With Prompt Caching
Done right, Anthropic's prompt caching can roughly halve your monthly API spend on workloads with long, repeated system prompts. Here is the design playbook I use after six months in production, including the arithmetic that links hit rate to the bill and the break-even points (about 22% on the 5-minute TTL, 53% on the 1-hour TTL).
⬡ API & SDK2026-05-25
A Two-Tier Setup — Haiku 4.5 Orchestrator with Opus 4.6 Worker for Balancing Cost and Quality
An indie developer's two-tier setup — Haiku 4.5 as orchestrator, Opus 4.6 as worker — costed line by line against published rates, plus the price increase I planned around that never arrived and the tokenizer split that quietly moves every token-denominated threshold.
⬡ API & SDK2026-05-13
Design Decisions Every Indie Developer Faces When Integrating Claude API into Mobile Apps
The design decisions indie mobile developers hit when integrating Claude API — model selection, async UX, context management, offline resilience, and cost control — with working code and a per-user cost table recalculated for the September 2026 price change.