Everything you send and receive is priced and bounded by tokens. Count them before you send, keep a conversation under the context window, and estimate what a call will cost.
Why: models read and bill in tokens, not characters or words — roughly 4 characters or 0.75 words each in English, more for code and other languages. When: reason in tokens whenever you think about cost, limits, or truncation. Where: both your input and the generated output count, and each has its own price.
"Streaming APIs are great" -> ~5 tokens
1,000 English words -> ~1,300 tokens
A page of code -> more tokens (symbols split up)
You pay for input tokens + output tokens.
Output is usually the pricier of the two.Why: you can measure a request’s input size before paying for it, which lets you reject oversized input or pick a cheaper model. When: count when input length is user-controlled (uploaded docs, long chats) so you never blow the context window by surprise. Where: the count endpoint is free and exact for the target model.
count = client.messages.count_tokens(
model="claude-opus-4-8",
messages=[{"role": "user", "content": "How many tokens is this?"}],
)
print(count.input_tokens)
# Gate on it: refuse input that would exceed your budget for this feature.
if count.input_tokens > 8000:
raise ValueError("Input too long — summarize or split it first.")Why: the context window is finite — a long chat eventually exceeds it and the call fails, so you must trim or summarize old turns. When: once the running total nears the limit, drop or compress the oldest messages while keeping the system prompt and recent turns. Where: this "context management" is what makes long-running assistants possible.
def trim_history(messages, keep_last=10):
"""Keep the system prompt (handled separately) and the most recent turns.
Production systems summarize the dropped turns instead of discarding them."""
if len(messages) <= keep_last:
return messages
return messages[-keep_last:]
messages = trim_history(messages) # before each new API callWhy: multiplying token counts by the per-token price turns "it felt expensive" into a number you can budget and alert on. When: log usage on every call and compute cost so you can attribute spend per user and per feature. Where: prices differ by model and by direction — input is cheaper than output — so read them from your provider’s pricing page.
# Example rates (USD per 1M tokens) — check your provider's current pricing.
PRICE_IN, PRICE_OUT = 5.00, 25.00
def cost(usage):
return (usage.input_tokens / 1_000_000 * PRICE_IN +
usage.output_tokens / 1_000_000 * PRICE_OUT)
print(f"This call cost ${cost(response.usage):.5f}")
# Log this per request to attribute spend and catch runaway costs early.