METHODOLOGY

Where your Claude API bill comes from

AUGUST 25, 2026 · 9 MIN
TL;DR

An API bill is a simple sum you can reconstruct from the four counters on every response. The surprise line item is almost never the system prompt — it's cache writes and cache misses, driven by how you shape and time requests, not by how much text you send.

The subscription version of this cut me off for a week — I hit the Claude Max weekly cap twice running and blamed my instruction file, which turned out to be the wrong suspect. The pay-as-you-go API is the same machinery with a different meter: it doesn't cut you off, it just bills you. I flipped on extra-usage credits exactly once and watched it rack up $100 in twenty minutes — a small, memorable reminder that the meter never pauses to warn you. And when the invoice comes in bigger than last month, everyone reaches for the same wrong explanation.

The guess is almost always "our system prompt is too long." And the money almost always went somewhere else: a cache miss, invisible in a per-token chart, driven by how you shape requests rather than how much you cut. The good news is that unlike a subscription, an API bill is fully explainable — every response hands you the receipt.

The meter is dollars, and it's on every response

The API bills per token, and the price is a simple sum: each kind of token times its rate. Every response includes a usage object with four counters:1

Log those four per request and you can reconstruct every line of your invoice and — more usefully — see which kind of token is growing. Most teams only watch the total, and the total hides everything that matters. (The schema has since grown a nested cache_creation object that splits writes into ephemeral_5m_input_tokens and ephemeral_1h_input_tokens by cache tier; the four-counter mental model still holds, but read the sub-fields if you want the TTL breakdown.)1

Two asides worth banking. Cache reads don't count against your input-tokens-per-minute rate limit on current models, so caching raises your throughput ceiling, not just lowers your bill.1 And anything that isn't time-sensitive — evals, backfills, nightly summaries — belongs on the Batch API, which is 50% off.2

Four kinds of token, priced like postage

"Input tokens" is not one price. A model reads tokens (chunks of about 3–4 characters, roughly three-quarters of a word), and every input token is billed in one of three categories, weighted like postage — a letter and a parcel both go through the mail, they don't cost the same.3

cache read0.1×
fresh input
cache write · 5 min1.25×
cache write · 1 hr
outputown rate

Cache read is the cheap glance; cache write is the expensive event. Output is billed at its own higher rate — set separately per model — and includes "thinking."

Token postage rates · price per token, relative to base input

Whenever a request is "50,000 tokens," ask which kind: 50,000 cache-read tokens cost about as much as 5,000 fresh ones.

The whiteboard: how caching works

The API has no memory between requests — each is a fresh envelope, so a chat re-sends its whole history every time. If every request re-processed its whole prefix (the stable beginning: system prompt, tool definitions, earlier turns) from scratch, big prompts and long conversations would be ruinous. They aren't, because of prompt caching.

The cache is a whiteboard in the model's office. The first time you send a block of context, the model writes it on the board — a cache write at 1.25× or 2×. Every later request that starts with the exact same prefix glances at the board — a cache read at 0.1×. On the API you control this: you place a cache_control marker (a breakpoint) on a content block, and everything up to that point becomes cacheable.3

Write once, read cheaply — until a miss erases the board
  1. Request 1 · WRITE1.25–2× base
  2. Requests 2…N · READ0.1× each — cheap
  3. Gap or change · MISSboard erased
  4. Next request · REWRITEfull write price again

The rule that follows is the most important sentence here: put the stable stuff first and the changing stuff last. System prompt, then tools, then long reference material, then history, then the user's new message — breakpoint after the last stable block. Anything that varies before the breakpoint spoils the match for everything after it.

system prompt tool defs reference doc◆ breakpoint history new message
Stable first, dynamic last · cache everything up to the breakpoint
MYTH VS REALITYThe myth: "our 3,000-token system prompt is billed full price every request, so trimming it slashes the bill." The reality: if it's cached — and it should be — it's billed at 0.1× on every request after the first, so trimming saves roughly 10× less than the myth suggests. Full-price savings show up only on cache-write and cache-miss requests. If your cache_creation_input_tokens is large next to cache_read_input_tokens, that's where the money is going — and no amount of prompt trimming fixes it.[^3]

When the whiteboard gets erased

A cache miss rewrites the entire prefix at full price — not just what changed, all of it. Four common causes on the API:

1. The gap trap. The cache has a timer (a TTL). Every read resets it; let more time than the TTL pass between requests that share a prefix and the board is erased. For a chat product that's a user who wanders off; for a background job it's bursty traffic with quiet gaps, or a low-traffic customer whose shared prompt never stays warm. The timer is measured from the start of the request, so a slow four-minute response leaves only about a minute of a five-minute window.3

2. Something changed inside the prefix. The cache matches exact bytes. Change a word, list two tool definitions in a different order, or let a library serialize your tool list with its fields shuffled, and the prefix no longer matches. Even whitespace counts.3

3. Switching models. Caches are per model. Route the same conversation to a different model — deliberately, or because a routing layer picked one for you — and it starts with an empty board.

4. Dynamic content up front. The classic. You add the current date, the user's name, or a request ID to the top of the system prompt. Now every request has a different prefix, nothing caches, and every request is a full-price write. The same thing happens the moment you "optimize" a live system prompt: every active conversation misses at once.

There are two cache tiers — the default 5-minute (1.25× to write, goes cold fast) and the 1-hour (2× to write, survives gaps). The break-even is simple: the 1-hour tier costs an extra 0.75× on one write; if it saves even a single rewrite you'd have paid 1.25× for, it's already ahead. Bursty or low-frequency traffic wants the 1-hour tier; a tight loop of requests seconds apart is fine on five minutes.3

Where the dollars actually go

The ranking of what inflates an API bill looks nothing like the folk wisdom. Highest impact first — the top three amplify each other:4

cache misseshighest
no caching / no breakpoints
oversized context per request
tool-result bloat in history
dynamic content before static
big model on trivial calls
over-budgeted thinking
heavy tool catalogs
long (cached) system promptthe one everyone blames

Bar lengths show ordering, not measured proportions. The top of the list is about when the prefix gets rewritten, not how big the prompt is.

Where the dollars go · relative impact, highest first

A note on tool-result bloat: a tool returns a 40 KB JSON blob, you append it to the message list, and it now rides along in every future request of that conversation — every receipt in the backpack, and you carry the backpack everywhere. Summarize or truncate tool results before they enter history. And on heavy tool catalogs: one measurement put a five-server MCP setup at ~55,000 tokens of tool definitions before any user input.5 Claude Code now loads tool descriptions on demand once they exceed roughly 10% of the context window, but a raw API integration doesn't — it sends the whole catalog every time.6

The playbook

Same shape as the companion post: none of these send less to the model; they change the order, the timing, and what rides along.

"system": [
  { "type": "text", "text": "You are a support assistant for Acme. …(stable)…" },
  { "type": "text", "text": "…(product manual, stable)…",
    "cache_control": { "type": "ephemeral" } }
],
"tools": [ …stable tool definitions… ],
"messages": [ …history…, { "role": "user", "content": "the new question" } ]
u = response.usage
log({ "input": u.input_tokens, "output": u.output_tokens,
      "cache_write": u.cache_creation_input_tokens,
      "cache_read": u.cache_read_input_tokens })

Read the ratio like a diagnosis: cache_readcache_write means caching works, so look at context size and model; cache_write large with gaps in traffic points at the TTL; cache_write ≈ input every request means something varies in the prefix; all counters zero means no breakpoints are set.

The reframe

The lesson isn't "shorten the prompt." It's stop paying to rewrite the cache — and read the evidence before you act. The usage object is your audit log; the fix follows from what it says, and it never once says "trim the system prompt first." Cache misses are the expensive event, ordering is the cheapest fix, and the biggest cached document is nearly free.

Reading usage per request is the API version of a habit I wanted everywhere. On the Claude Code side I started building AgentWrangler — a local dashboard that reads the tool's own session logs, shows where the tokens went, and flags the oversized context and the model mismatch before the bill does. It keeps only the counts and discards the content, which is the audit-evidence posture I'd want for my own telemetry. It's Claude-Code-focused, and the code's still local; an early PRD is up at github.com/Doogit/AgentWrangler if you want to follow along. Stay tuned.

Footnotes

  1. Anthropic, Prompt caching and API rate limits documentation — the four usage counters (with the newer nested cache_creation sub-fields ephemeral_5m_input_tokens / ephemeral_1h_input_tokens); cache-read tokens do not count toward input-tokens-per-minute limits on current models. platform.claude.com/docs/en/docs/build-with-claude/prompt-caching. First-party. 2 3

  2. Anthropic, models overview — "Batch API requests are 50% off"; extended thinking is billed as output tokens and counts toward output rate limits. platform.claude.com/docs/en/docs/about-claude/models/overview. First-party.

  3. Anthropic, Prompt caching documentation — cache-write 1.25× (5-minute) / 2× (1-hour) and cache-read 0.1× of base input; exact-prefix matching, any change (including whitespace) invalidates; the lifetime is measured from the start of the request. First-party. 2 3 4 5

  4. Build to Launch, "Claude Code Token Optimization" (2026), and Anthropic documentation — ordering of cost drivers adapted for API workloads from practitioner reports and docs, not a controlled measurement. Community/practitioner + first-party.

  5. startdebugging.net (May 2026) — a typical five-server MCP setup measured at roughly 55,000 tokens of tool definitions loaded before any user input. Community/practitioner.

  6. Anthropic, MCP tool search (Jan 14, 2026, Claude Code v2.1.7) — defers MCP tool descriptions when they exceed roughly 10% of the context window, loading only the relevant handful per query. First-party.

"A written rule is a suggestion. A gate is a control."
The operating principle behind every project here. The same bug shipped three times past written rules — and zero times past a CI gate. Deterministic enforcement beats advisory documentation, in agent harnesses and security programs alike.