Before you can optimize cost, you have to measure it. A token is the unit into which text is broken before the model processes it — roughly three-quarters of an English word. Claude's pricing is quoted per million tokens (MTok), and the single most important fact is that input and output tokens are priced differently: output consistently costs five times as much as input.
Key Points
- Output is 5× input across every model — bounding output with
max_tokens (a hard ceiling) is the central lever of cost control.
- Large input context is comparatively cheap, and caching makes repeated input cheaper still — don't over-fear input size.
- The
usage object is the source of truth; total input = input_tokens + cache_creation_input_tokens + cache_read_input_tokens.
count_tokens is free, has independent rate limits, and forecasts cost before you spend — never estimate with tiktoken.
- Newer models (Opus 4.7+, Fable 5, Sonnet 5) tokenize ~30% larger — recount against the exact model you'll use.
Standard (non-cached, non-batched) pricing
| Model | Input $/MTok | Output $/MTok | Output/Input ratio |
| Claude Fable 5 | $10.00 | $50.00 | 5× |
| Claude Opus 4.8 | $5.00 | $25.00 | 5× |
| Claude Sonnet 5 (intro, through Aug 31 2026) | $2.00 | $10.00 | 5× |
| Claude Sonnet 5 (from Sept 1 2026) | $3.00 | $15.00 | 5× |
| Claude Haiku 4.5 | $1.00 | $5.00 | 5× |
The pattern is that output costs five times as much as input across every model. Two design implications follow: bound your output (right-size max_tokens so a runaway generation can't cost 5× what you expected), and don't over-fear input (large context is comparatively cheap, and caching makes repeated input cheaper still).
The four token buckets in usage
| Field | Meaning | Billed at |
input_tokens | Uncached prompt tokens (remainder after any cache breakpoint) | Base input rate |
output_tokens | Tokens the model generated | Output rate |
cache_creation_input_tokens | Tokens written to cache this request | ~1.25× or 2× input |
cache_read_input_tokens | Tokens served from cache this request | ~0.1× input |
The crucial subtlety: input_tokens is not the total prompt size when caching is in play — it is only the uncached remainder after the last breakpoint. To reconstruct full prompt size, add all three input buckets. A simple cost forecast for 100,000 support-ticket classifications on Haiku 4.5 (~400-token input, ~20-token output each): input = 100,000 × 400 × ($1.00/1M) = $40; output = 100,000 × 20 × ($5.00/1M) = $10; total realtime, no caching = $50. This baseline is what caching and batching drive downward.
Animation slot: interactive cost calculator — slide input/output token counts and model to watch the per-request bill (and the 5× output multiplier) update live.
Most production prompts are mostly repetition. Prompt caching lets Claude reuse identical leading segments across requests: you pay full price once and roughly a tenth of the price every time after. The whole mechanism rests on one invariant — caching is an exact prefix match; any byte that changes at or before a breakpoint invalidates that entry and every entry after it. Prompts always render in the fixed order tools → system → messages.
Key Points
- Exact prefix match. Put stable content (frozen system prompt, sorted tools) before the breakpoint; volatile content (timestamps, IDs, the question) after.
- A cache read costs ~90% less; a write costs a small premium (1.25× for 5-min, 2× for 1-hour TTL) — caching is a bet that pays off with enough reads.
- Break-even: 5-minute cache wins after 2 requests, 1-hour cache after 3. If the prefix changes every time, don't cache at all.
- Rules: max 4 breakpoints per request, a 20-block lookback window, and a per-model minimum (1024 Opus/Sonnet, 2048 Fable, 4096 Haiku) — below it, caching silently does nothing (no error).
- Verify hits via
cache_read_input_tokens; a silent invalidator yields zero savings and zero errors.
Cache pricing on Opus 4.8 ($5/MTok base input)
| Category | Multiplier | Price per MTok |
| Base input | 1× | $5.00 |
| 5-minute cache write | 1.25× | $6.25 |
| 1-hour cache write | 2× | $10.00 |
| Cache read (hit) | ~0.1× | $0.50 |
| Output | — | $25.00 |
A cache hit costs about 90% less than reprocessing the same tokens. But a cache write costs slightly more than a plain request, so caching is a bet: you pay a small premium to write, and win only if enough reads land before the entry expires. ephemeral is the only supported cache type.
Figure 4.1: Fixed prompt render order and where a cache prefix ends
flowchart LR
T["tools (rendered first)"] --> S["system prompt"]
S --> BP{{"cache_control breakpoint"}}
BP -->|"caches tools + system as one prefix"| CACHE["Cached prefix (exact-byte match)"]
BP --> M["messages (volatile: user's question)"]
M --> UNCACHED["Billed as input_tokens each request"]
CACHE -.->|"hit on next request"| READ["cache_read_input_tokens (~0.1x)"]
Figure 4.2: Prompt cache read/write decision path per request
flowchart TD
START["Request arrives with cache_control prefix"] --> MIN{"Prefix >= model minimum? (1024-4096 tok)"}
MIN -->|No| NOCACHE["No caching (silent): both cache buckets = 0"]
MIN -->|Yes| HIT{"Matching entry still live in cache?"}
HIT -->|"Miss (first request or TTL expired)"| WRITE["Cache WRITE: 1.25x (5-min) or 2x (1-hour)"]
HIT -->|Hit| READ["Cache READ: ~0.1x (about 90% cheaper)"]
WRITE --> TTL["Entry lives for TTL (5 min or 1 hour)"]
READ --> TTL
Break-even worked example
A 10,000-token contract, asked 5 questions on Opus 4.8. Without caching: 5 × 10,000 × ($5/1M) = $0.250. With 5-minute caching: request 1 writes (10,000 × $6.25/1M = $0.0625), requests 2–5 read (4 × 10,000 × $0.50/1M = $0.0200) = $0.0825 — a 67% cut on repeated input. Output is unaffected; caching applies to input only.
Common silent invalidators
| Silent invalidator | Why it breaks the cache |
datetime.now() / Date.now() in the system prompt | Prefix changes every request |
| A UUID or request ID early in the content | Every request is unique |
json.dumps(d) without sort_keys=True | Non-deterministic key order → different bytes |
| A session/user ID interpolated into the system prompt | Per-user prefix; no cross-user sharing |
| A tool set that varies per user | Tools render first; nothing caches across users |
Animation slot: prefix-diff visualizer — highlight the byte that changed between two requests and show the cache entry (and everything after it) invalidating in real time.
Batch processing attacks cost from a different angle than caching: it trades latency for a flat 50% discount. If a workload doesn't need answers right now, hand the requests to the platform, let it process them asynchronously, and pay half. The Message Batches API (POST /v1/messages/batches) takes a list of requests, each with a unique custom_id, and you poll for completion.
Key Points
- 50% of standard prices on all tokens (input, output, and special), in exchange for a 24-hour window (most batches finish in under an hour).
- Size cap: 100,000 requests or 256 MB, whichever comes first (over 256 MB →
413 request_too_large).
- Results come back in any order — always match by
custom_id, never by position. This is the most common batch bug.
- Only
succeeded results are billed; errored, canceled, and expired are free. Results retained 29 days from creation. No streaming.
- Caching stacks on batching — the discounts compound; prefer the 1-hour TTL for batches sharing a large context (hit rates are best-effort, ~30–98%).
Figure 4.3: Message Batches API lifecycle
stateDiagram-v2
[*] --> in_progress: create (up to 100k requests / 256 MB)
in_progress --> ended: all requests complete
in_progress --> ended: 24-hour window elapsed
in_progress --> canceling: cancel requested
canceling --> ended
ended --> results: poll processing_status == "ended"
results --> [*]: retained 29 days from creation
note right of results
Per-request result type:
succeeded (billed) | errored | canceled | expired (not billed)
Match by custom_id, never by position
end note
Batch pricing (50% of standard)
| Model | Batch Input $/MTok | Batch Output $/MTok |
| Claude Fable 5 | $5.00 | $25.00 |
| Claude Opus 4.8 | $2.50 | $12.50 |
| Claude Sonnet 5 (intro) | $1.00 | $5.00 |
| Claude Sonnet 5 (from Sept 1 2026) | $1.50 | $7.50 |
| Claude Haiku 4.5 | $0.50 | $2.50 |
Our 100,000-classification job that cost $50 realtime becomes: input 100,000 × 400 × ($0.50/1M) = $20; output 100,000 × 20 × ($2.50/1M) = $5; total batch = $25 — exactly half. The only cost is that answers may take up to (but rarely) 24 hours instead of seconds. The defining constraint is the 24-hour processing window: results are guaranteed when all requests complete or after 24 hours, whichever comes first — a batch that doesn't finish in 24 hours expires, and expired requests are not billed.
Result types
| Result type | Meaning | Billed? |
succeeded | Completed; includes the message result | Yes |
errored | Invalid request or internal server error | No |
canceled | Canceled before being sent to the model | No |
expired | Hit the 24-hour limit before running | No |
Animation slot: batch lifecycle timeline — submit 100k requests, watch them return out-of-order and get reassembled by custom_id, with the running 50%-off bill ticking up only for succeeded results.
The three levers are most powerful in combination. Caching removes repeated cost, batching halves all cost, and model choice lowers the per-token cost — different axes, so they multiply. The engineering discipline is applying each where it fits: cache the shared rulebook (identical across requests), batch the whole run (nobody's waiting), and route by difficulty (don't pay Opus prices for a Haiku task).
Key Points
- Cut context bloat first — right-size
max_tokens (output is 5×), trim the prompt, use context editing/compaction, and count_tokens to route by size.
- The levers compound: caching (repeated cost) + batching (all cost, 50%) + model choice (per-token cost) run a workload for a small fraction of the naive bill.
- Concurrency caveat: a cache entry is only readable after the first response begins streaming — for fan-out, send one request, await its first token, then fire the rest.
- Log the
usage object on every response (all four buckets + dollar cost + request_id) — your ground-truth ledger.
- Alert on cache-hit rate and forecast with
count_tokens before large runs, so surprises become caught bugs, not invoice shocks.
Stacking optimizations on a 10,000-document pipeline (8,000-token rulebook, Opus 4.8)
| Configuration | Effect on the shared rulebook |
| Naive: realtime, no caching, Opus 4.8 | Full input price × 10,000 |
| + Caching: cache the rulebook | First request writes; the rest read at ~0.1× |
| + Batching: run the whole set as one batch | Another 50% off input and output |
| + Model choice: route simple docs to Haiku 4.5 | 5× cheaper input, 5× cheaper output than Opus |
Figure 4.4: Choosing realtime vs. batch processing
flowchart TD
Q1{"Is a human or user-facing system waiting on the response?"}
Q1 -->|Yes| RT["Realtime Messages API (seconds; streaming supported)"]
Q1 -->|No| Q2{"Can it tolerate up to 24h latency? (usually < 1 hour)"}
Q2 -->|No| RT
Q2 -->|Yes| BATCH["Message Batches API (50% of standard price)"]
BATCH --> USES["Evals, bulk generation, moderation, data analysis"]
RT --> USES2["Chat, autocomplete, voice, interactive apps"]
Realtime vs. batch at a glance
| Dimension | Realtime (Messages API) | Batch (Message Batches API) |
| Latency | Seconds | Up to 24h (usually < 1 hour) |
| Cost | Standard | 50% of standard |
| Best for | Interactive chat, voice, anything a human waits on | Evals, moderation, bulk generation, data analysis |
| Streaming | Supported | Not supported (stream: true rejected) |
| Rate limits | Standard Messages limits | Separate; does not affect Messages quota |
Animation slot: optimization-stacking bar chart — start from the naive Opus bill and watch each lever (caching, batching, model routing) shave the bar down, showing the compounding fraction of the original cost.