◉CLAUDE LABJP
●2.1.292 — Claude Code 2.1.292 (Oct 6) fixes cloud sessions dropping answers to permission prompts and the last messages of a session being lost on quit●MODELS API — The Models API now reports in capabilities whether a model accepts thinking turned off (Oct)●11/30 — 54 days until Sonnet 4.5 retires on the Claude API. Move to Sonnet 5.5, and check your thinking settings and tool_choice first●MODS — A Zenn post walks through installing Claude Code Mods safely. The real question is what to check before you install, and how to back out●NEW — When Pro looks unpaid, the screens to check depend on whether you bought on the web or in the store. I sorted that out step by step●THINKING — Sonnet 5.5 thinking blocks only work in the account that produced them. Sent from another account, they are silently dropped●2.1.292 — Claude Code 2.1.292 (Oct 6) fixes cloud sessions dropping answers to permission prompts and the last messages of a session being lost on quit●MODELS API — The Models API now reports in capabilities whether a model accepts thinking turned off (Oct)●11/30 — 54 days until Sonnet 4.5 retires on the Claude API. Move to Sonnet 5.5, and check your thinking settings and tool_choice first●MODS — A Zenn post walks through installing Claude Code Mods safely. The real question is what to check before you install, and how to back out●NEW — When Pro looks unpaid, the screens to check depend on whether you bought on the web or in the store. I sorted that out step by step●THINKING — Sonnet 5.5 thinking blocks only work in the account that produced them. Sent from another account, they are silently dropped
Articles/API & SDK
⬡ API & SDK/2026-08-23Beginner

The September Price Increase for Sonnet 5 Isn't Happening. Rebuilding a Forecast I Got Wrong in July

Sonnet 5's introductory $2/$10 pricing was supposed to rise to $3/$15 on September 1. It won't. Here's how to recompute your own effective cost from the usage numbers you already have, with working code.

Claude API125Sonnet 58pricing8cost estimationprompt caching4

I had August 31 circled in my notebook. That was the day Sonnet 5's introductory pricing was supposed to end.

I sat down to redo my September forecast, lined up recent usage totals, and swapped the rates for $3 / $15. At the scale an indie developer works at, a few tens of dollars a month is not noise. The number came out higher than I expected, so I went back to the primary source to double-check.

The official pricing page said something different. The $2 / $10 introductory rate is now the standard price. The increase scheduled for September 1 will not happen.

I published an article in July built entirely on that increase. The premise is gone. The table I'd just rebuilt was useless — but reading the price list line by line turned up a footnote I'd been skipping for months. That footnote is what this post is really about.

Check the current rates yourself

First, the facts. Here is the official price list as of August 23, 2026, in USD per million tokens.

ModelInput5m cache writeCache readOutput
Claude Fable 5$10$12.50$1$50
Claude Opus 5$5$6.25$0.50$25
Claude Sonnet 5$2$2.50$0.20$10
Claude Sonnet 4.6$3$3.75$0.30$15
Claude Haiku 4.5$1$1.25$0.10$5

Cache rates are derived mechanically from the base input rate: a 5-minute cache write costs 1.25x input, a 1-hour cache write costs 2x, and a cache read (hit) costs 0.1x. The Batch API halves input and output. Pinning inference_geo to "us" multiplies every category by 1.1.

These numbers move, so open the Claude Platform pricing page before you make a decision based on them. Not checking monthly is exactly how I ended up wrong in July.

Compute your effective cost from your own usage

Staring at a rate table is slower than plugging in your own numbers. Every API response carries a usage object with four counts:

  • input_tokens — input that did not come from cache
  • cache_creation_input_tokens — input written to cache
  • cache_read_input_tokens — input served from cache
  • output_tokens — tokens generated

Keep those four separate when you aggregate. It pays off in a moment. This script turns them into a cost breakdown.

M = 1_000_000
 
# tokenizer: "new" = Claude 4.7 and later, "old" = Claude Sonnet 4.6 and earlier
RATES = {
    "sonnet-5":   {"in": 2.0, "write5m": 2.50, "read": 0.20, "out": 10.0, "tokenizer": "new"},
    "opus-5":     {"in": 5.0, "write5m": 6.25, "read": 0.50, "out": 25.0, "tokenizer": "new"},
    "sonnet-4-6": {"in": 3.0, "write5m": 3.75, "read": 0.30, "out": 15.0, "tokenizer": "old"},
    "haiku-4-5":  {"in": 1.0, "write5m": 1.25, "read": 0.10, "out": 5.0,  "tokenizer": "old"},
}
 
 
def breakdown(model, usage, batch=False, us_only=False):
    """Return a cost breakdown. `usage` uses the same keys as the API response."""
    r = RATES[model]
    mult = (0.5 if batch else 1.0) * (1.1 if us_only else 1.0)
    items = {
        "uncached_input": usage.get("input_tokens", 0) * r["in"],
        "cache_write":    usage.get("cache_creation_input_tokens", 0) * r["write5m"],
        "cache_read":     usage.get("cache_read_input_tokens", 0) * r["read"],
        "output":         usage.get("output_tokens", 0) * r["out"],
    }
    items = {k: v * mult / M for k, v in items.items()}
    items["total"] = sum(items.values())
    return items
 
 
if __name__ == "__main__":
    daily = {   # replace with your own totals
        "input_tokens": 120_000,
        "cache_creation_input_tokens": 800_000,
        "cache_read_input_tokens": 4_200_000,
        "output_tokens": 260_000,
    }
    b = breakdown("sonnet-5", daily)
    for k in ("uncached_input", "cache_write", "cache_read", "output", "total"):
        print(f"  {k:<15} ${b[k]:.4f} / day   ${b[k] * 30:7.2f} / 30 days")

Running it gives:

  uncached_input  $0.2400 / day   $   7.20 / 30 days
  cache_write     $2.0000 / day   $  60.00 / 30 days
  cache_read      $0.8400 / day   $  25.20 / 30 days
  output          $2.6000 / day   $  78.00 / 30 days
  total           $5.6800 / day   $ 170.40 / 30 days

The breakdown matters more than the total, because each line points at a different fix.

If output dominates, look at max_tokens and your response format. If cache writes dominate, suspect your cache breakpoints, or gaps between requests that exceed the 5-minute TTL. If cache reads dominate, that is the healthy shape — the 0.1x multiplier is doing its job. A single total number hides all three.

For reference, the same usage at $3 / $15 comes to $255.60 over 30 days. The cancelled increase is worth $85.20 a month in this example.

Comparing models by rate alone will mislead you

What actually stopped me was a two-line footnote under the table.

Models from Claude 4.7 onward use a newer tokenizer that produces roughly 30% more tokens for the same text. Claude Sonnet 4.6 and earlier use the previous tokenizer.

So Sonnet 5 and Opus 5 count one way, while Sonnet 4.6 and Haiku 4.5 count another. Lining them up by dollars-per-million-tokens compares two different rulers.

To model a switch honestly, scale the token counts too:

def swap_model(src, dst, usage, tokenizer_ratio=1.30):
    """Cost of moving usage measured on `src` over to `dst`."""
    a, b = RATES[src]["tokenizer"], RATES[dst]["tokenizer"]
    scale = 1.0 if a == b else (1 / tokenizer_ratio if a == "new" else tokenizer_ratio)
    scaled = {k: v * scale for k, v in usage.items()}
    return breakdown(dst, scaled)["total"], scale

Applied to the same daily numbers:

haiku-4-5:
  rate swap only        $  85.20 / 30 days  (0.50x of Sonnet 5)
  with 0.77 token scale $  65.54 / 30 days  (0.38x of Sonnet 5)
opus-5:
  rate swap only        $ 426.00 / 30 days  (2.50x of Sonnet 5)
  with 1.00 token scale $ 426.00 / 30 days  (2.50x of Sonnet 5)

Haiku 4.5 is not "half the rate, therefore half the bill." In this example it lands at 0.38x. Opus 5 shares a tokenizer with Sonnet 5, so no scaling applies and it stays at 2.5x.

Cost is not the only thing affected. If the same text becomes 1.3x the tokens, the same context window holds proportionally less. If you run close to the window limit, you will feel that before you feel the billing difference.

Measure the 30% against your own text

Let me be straight about one thing: 1.30 is the figure the documentation gives as an approximation. I did not measure it. The real ratio depends on what you are sending — Japanese versus English, code versus prose.

Measuring your own input is more reliable, and the token counting endpoint is not billed. Count the same text on both models and take the ratio.

import anthropic
 
client = anthropic.Anthropic()   # reads ANTHROPIC_API_KEY from the environment
 
def count(model, text):
    r = client.messages.count_tokens(
        model=model,
        messages=[{"role": "user", "content": text}],
    )
    return r.input_tokens
 
sample = open("prompts/typical_request.txt", encoding="utf-8").read()
new_tok = count("claude-sonnet-5", sample)
old_tok = count("claude-haiku-4-5", sample)
print(f"new={new_tok} old={old_tok} ratio={new_tok / old_tok:.3f}")

Feed the result into tokenizer_ratio and the estimate becomes yours rather than a generic one. Three representative requests averaged together is enough to work with.

If you want to size a prompt before sending it, I wrote about that in The 200K-Token Cliff That Doubled My Nightly Bill.

One thing worth doing today

Sum the last seven days of usage and run it through the script above. You will see which of the four lines is largest.

That alone tells you where to work next. For me it was cache writes, which led me to a stretch of the day where request intervals were crossing the 5-minute cache TTL. Reading the rate table would never have surfaced that.

Once hand-editing constants every time pricing shifts gets tedious, the next step is attaching validity windows to the rates themselves. That is what my July piece, Effective-Dated Cost Forecasting Around the Sonnet 5 Introductory Price Expiry, sets out to build. There is some irony in that: the September 1 step it was designed around never arrived. The underlying conclusion — never store prices as static constants — held up better than my forecast did.

What I failed to account for was that a scheduled change can be withdrawn, not just applied. If this saves someone else the same oversight, that is enough.

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 $15 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-09-28
The Night Claude Returned 529, My Fallback Failed Too — Strip cache_control at the Provider Boundary
My Claude API fallback threw a TypeError because content blocks still carried cache_control when they reached another vendor. Here is the stripping function, the pre-send guard, and the weekly forced-fallback routine that finally made the fallback a real safety net.
⬡ API & SDK2026-05-12
Combining Haiku 4.5, Streaming, and Prompt Caching to Cut Costs in a Personal App — An Implementation Record
A hands-on record of combining Claude Haiku 4.5, streaming, and prompt caching to improve both cost and response speed in a personal iOS/Android app — including the mistakes made along the way.
⬡ API & SDK2026-04-27
Claude API Revenue Models Compared — Pay-per-Use, Subscription, One-Shot, and Revenue Share for Indie Developers
When you build something with Claude API to make money, the hardest decision is rarely the API itself — it's the pricing model. This guide compares the four most common models from an indie developer's point of view.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links