Token Economics Basics
9 examples to get you started with token economics - 6 basic and 3 intermediate.
Search across all documentation pages
9 examples to get you started with token economics - 6 basic and 3 intermediate.
pip install anthropicexport ANTHROPIC_API_KEY=sk-ant-...anthropic.Anthropic(), which reads that environment variable automatically.Get an exact token count for a request without paying for a completion.
import anthropic
client = anthropic.Anthropic()
count = client.messages.count_tokens(
model="claude-sonnet-5",
messages=[{"role": "user", "content": "Summarize the Q3 report in three bullets."}],
)
print(count.input_tokens)count_tokens mirrors the messages.create signature, so you pass the same system, tools, and messages you'd send for real.input_tokens, since output length isn't known until generation happens.Related: How Claude Token Pricing Actually Works - why input and output are priced differently.
Turn a token count into a dollar estimate using a model's published rate.
SONNET_INPUT_PER_MTOK = 2.00 # intro pricing, through 2026-08-31
count = client.messages.count_tokens(
model="claude-sonnet-5",
messages=[{"role": "user", "content": "Summarize the Q3 report in three bullets."}],
)
estimated_input_cost = (count.input_tokens / 1_000_000) * SONNET_INPUT_PER_MTOK
print(f"${estimated_input_cost:.6f}")1_000_000 converts a raw token count into millions of tokens, matching how per-MTok pricing is quoted.max_tokens by the output rate and add it to this estimate.Get exact, billed token counts after a real call.
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=300,
messages=[{"role": "user", "content": "Summarize the Q3 report in three bullets."}],
)
print(response.usage.input_tokens, response.usage.output_tokens)response.usage is the source of truth, it reflects what you're actually billed for.count_tokens before the call and usage after the call should report the same input_tokens for an identical request.output_tokens is only available here, never from a pre-call estimate.Combine input and output usage with per-model rates for an exact cost.
RATES = {
"claude-sonnet-5": {"input": 2.00, "output": 10.00},
"claude-haiku-4-5": {"input": 1.00, "output": 5.00},
}
def cost_of(response, model: str) -> float:
rate = RATES[model]
usage = response.usage
return (
(usage.input_tokens / 1_000_000) * rate["input"]
+ (usage.output_tokens / 1_000_000) * rate["output"]
)
print(f"${cost_of(response, 'claude-sonnet-5'):.6f}")Related: Building a Pre-Request Cost Calculator with the Token Counting API - wiring this into a pipeline gate.
Confirm that tool definitions count toward the input total.
tools = [
{
"name": "get_weather",
"description": "Get the current weather for a city.",
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
}
]
count = client.messages.count_tokens(
model="claude-sonnet-5",
tools=tools,
messages=[{"role": "user", "content": "What's the weather in Austin?"}],
)
print(count.input_tokens)See how token count grows as conversation history accumulates.
conversation = [
{"role": "user", "content": "What's our refund policy?"},
{"role": "assistant", "content": "Refunds are accepted within 30 days of purchase."},
{"role": "user", "content": "Does that apply to opened items?"},
]
count = client.messages.count_tokens(
model="claude-sonnet-5",
messages=conversation,
)
print(count.input_tokens)Refuse to send a request if its estimated cost exceeds a budget.
def send_if_affordable(client, max_cost_usd: float, **kwargs):
count = client.messages.count_tokens(
model=kwargs["model"],
messages=kwargs["messages"],
system=kwargs.get("system"),
tools=kwargs.get("tools"),
)
rate = RATES[kwargs["model"]]
input_cost = (count.input_tokens / 1_000_000) * rate["input"]
# Worst case: assume the full max_tokens budget is used as output.
worst_case_output_cost = (kwargs.get("max_tokens", 0) / 1_000_000) * rate["output"]
if input_cost + worst_case_output_cost > max_cost_usd:
raise ValueError(
f"Estimated cost ${input_cost + worst_case_output_cost:.4f} exceeds budget ${max_cost_usd}"
)
return client.messages.create(**kwargs)
response = send_if_affordable(
client,
max_cost_usd=0.05,
model="claude-sonnet-5",
max_tokens=300,
messages=[{"role": "user", "content": "Summarize the Q3 report in three bullets."}],
)max_tokens as an upper bound, since real output length is unknown pre-call.max_tokens, a flat cap can be too conservative.Accumulate cost across many requests in a loop.
def process_documents(client, documents: list[str], model: str) -> float:
total_cost = 0.0
for doc in documents:
response = client.messages.create(
model=model,
max_tokens=200,
messages=[{"role": "user", "content": f"Extract the key entities from:\n{doc}"}],
)
total_cost += cost_of(response, model)
return total_cost
total = process_documents(client, ["doc one text...", "doc two text..."], "claude-haiku-4-5")
print(f"Total run cost: ${total:.4f}")cost_of(...) per call turns a batch job into a job with a known, auditable total cost.Related: Model Tiering: Routing Simple Tasks to Haiku, Hard Tasks to Opus - choosing the model this loop calls.
Verify your pre-call estimate matches what you were actually billed.
count = client.messages.count_tokens(
model="claude-sonnet-5",
messages=[{"role": "user", "content": "Summarize the Q3 report in three bullets."}],
)
estimated_input_tokens = count.input_tokens
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=300,
messages=[{"role": "user", "content": "Summarize the Q3 report in three bullets."}],
)
actual_input_tokens = response.usage.input_tokens
assert estimated_input_tokens == actual_input_tokens, "Estimate and actual usage diverged"count_tokens input and usage.input_tokens should always match exactly.Stack versions: Written against the Claude model lineup current as of ~June 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (the default), and Claude Haiku 4.5 - and the official
anthropicPython SDK (latest 0.x release). Model names, pricing, and SDK versions move quickly - verify current specifics at platform.claude.com/docs before relying on them.
Reviewed by Chris St. John·Last updated Jul 19, 2026