Price Claude calls from all four usage fields, reserve an estimate before the call so parallel requests can't blow through a cap, and fall back to a cheaper model near the limit.
---
title: Per-customer budget caps for Anthropic API calls (with prompt caching priced right)
published: true
description: Price Claude calls from all four usage fields, reserve an estimate before the call so parallel requests can't blow through a cap, and fall back to a cheaper model near the limit.
tags: anthropic, claude, typescript, redis
---
If your product calls Claude on behalf of your customers, one heavy account can spend a month's margin in a weekend. Anthropic's console limits protect your organization. They don't know which of *your* customers sent the traffic, so they can't stop one of them without stopping everyone.
This post builds a per-customer monthly cap for the Anthropic Messages API in TypeScript:
1. Price each call correctly, including prompt-cache reads **and writes**.
2. Check the budget **before** the call, in a way that holds up under concurrent requests.
3. Switch to a cheaper model near the cap, and refuse at the cap.
It uses `@anthropic-ai/sdk` and Redis (`ioredis`). The ideas carry over to any store with atomic operations.
A Claude response's `usage` has four token counts that matter for cost:
| Field | What it is | Billed at |
|---|---|---|
| `input_tokens` | input after the last cache breakpoint | base input price |
| `cache_read_input_tokens` | prefix read from the prompt cache | 0.1x base for most models (0.05x for Opus 5.5 and Sonnet 5.5) |
| `cache_creation_input_tokens` | prefix written to the cache this call | 1.25x base (5-minute TTL), 2x (1-hour TTL) |
| `output_tokens` | generated tokens, including thinking | output price |
The trap is that `input_tokens` is **not** the total input. Total input is `input_tokens + cache_read_input_tokens + cache_creation_input_tokens`. If you only price `input_tokens`, a cached chat app looks almost free. And if you ignore cache writes, you under-count the first call of every conversation by 25% or more on its prefix.
When the 1-hour TTL is in play, `usage.cache_creation` splits writes into `ephemeral_5m_input_tokens` and `ephemeral_1h_input_tokens`, so you can price them separately.
// prices.ts: USD per 1M tokens, standard tier.
// From https://docs.anthropic.com/en/docs/about-claude/pricing, read 2026-11-02. Check before relying on these.
type Price = { input: number; output: number; cacheRead: number; cacheWrite5m: number; cacheWrite1h: number };
export const PRICES: Record<string, Price> = {
"claude-sonnet-5-5": { input: 2.0, output: 10.0, cacheRead: 0.1, cacheWrite5m: 2.5, cacheWrite1h: 4.0 },
// Haiku 5.5 has a higher price for prompts over 100K tokens; this is the up-to-100K tier.
"claude-haiku-5-5": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite5m: 0.125, cacheWrite1h: 0.2 },
};
export interface ClaudeUsage {
input_tokens: number;
output_tokens: number;
cache_read_input_tokens?: number | null;
cache_creation_input_tokens?: number | null;
cache_creation?: { ephemeral_5m_input_tokens?: // artículos relacionados
Twitter/X: @elder_plinius @LYSIOS The timing makes the contrast hard to miss: Anthropic is IPO-ing at $70–78…
Twitter/X: @JakeDSBD24 @Kevin_Logan @bot People that had ultra like my self down graded to the $30 to keep t…
Twitter/X: 🚨 BREAKING: Claude can now map out your retirement better than most people charging $2,000 ever …