Follow Discord
Sweep 23 Oct 2026 · 21:48Z Build v2.1.310 529 read Stable v2.1.308 Latest v2.1.310 Next v2.1.310 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · claude-code

Track cost and usage changedagent-sdk/cost-tracking

Nearest release: v2.1.290, published 3 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Upstream edited this page at 5 Oct 2026 22:11 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 23 Oct 2026 19:07 UTC.

Upstream edited
Recorded here
Lines+31added
Lines−31removed
From line 4 where the diff opens
First seen 14 Aug 2026 this site's first read of the page
Recorded edits13to this page, all time

The whole hunk

from line 4, old and new numbered
/
lines
from line 4
44 
55The Claude Agent SDK provides detailed token usage information for each interaction with Claude. This guide explains how to properly track usage and understand cost reporting, especially when dealing with parallel tool uses and multi-step conversations.
66 
7For complete API documentation, see the [TypeScript SDK reference](/docs/en/agent-sdk/typescript.md) and [Python SDK reference](/docs/en/agent-sdk/python.md).
7For complete API documentation, see the [TypeScript SDK reference](https://code.claude.com/docs/en/agent-sdk/typescript.md) and [Python SDK reference](https://code.claude.com/docs/en/agent-sdk/python.md).
88 
99> [!WARNING]
1010>
11> The `total_cost_usd` and `costUSD` fields are client-side estimates, not authoritative billing data. The SDK computes them locally from a price table bundled at build time, unless a [`modelPricing`](/docs/en/settings-reference#modelpricing) table is in effect. They can drift from what you are actually billed when:
11> The `total_cost_usd` and `costUSD` fields are client-side estimates, not authoritative billing data. The SDK computes them locally from a price table bundled at build time, unless a [`modelPricing`](https://code.claude.com/docs/en/settings-reference#modelpricing) table is in effect. They can drift from what you are actually billed when:
1212>
1313> * pricing changes
1414> * the installed SDK version does not recognize a model
from line 29
2929 
3030Cost tracking depends on understanding how the SDK scopes usage data:
3131 
32* **`query()` call:** one invocation of the SDK's `query()` function. A single call can involve multiple steps: Claude responds, uses tools, gets results, and responds again. Each call produces one [`result`](/docs/en/agent-sdk/typescript#sdkresultmessage) message at the end, except in [streaming input mode](/docs/en/agent-sdk/streaming-vs-single-mode.md), where one `query()` call carries multiple user turns and each turn emits its own `result` message.
32* **`query()` call:** one invocation of the SDK's `query()` function. A single call can involve multiple steps: Claude responds, uses tools, gets results, and responds again. Each call produces one [`result`](https://code.claude.com/docs/en/agent-sdk/typescript#sdkresultmessage) message at the end, except in [streaming input mode](https://code.claude.com/docs/en/agent-sdk/streaming-vs-single-mode.md), where one `query()` call carries multiple user turns and each turn emits its own `result` message.
3333* **Step:** a single request/response cycle within a `query()` call. Each step produces assistant messages with token usage.
3434* **Session:** a series of `query()` calls linked by a session ID through the `resume` option. A resumed call's results report the session's whole spend, not just that call's own. See [Accumulate costs across multiple calls](#accumulate-costs-across-multiple-calls) for how the totals carry over.
3535 
from line 43
4343 
4444**2. The result message provides the cumulative estimate**
4545 
46When the `query()` call completes, the SDK emits a result message with `total_cost_usd` and cumulative `usage`, typed as [`SDKResultMessage`](/docs/en/agent-sdk/typescript#sdkresultmessage) in TypeScript and [`ResultMessage`](/docs/en/agent-sdk/python#resultmessage) in Python. If you only need the estimated total, you can ignore the per-step usage and read this single value.
46When the `query()` call completes, the SDK emits a result message with `total_cost_usd` and cumulative `usage`, typed as [`SDKResultMessage`](https://code.claude.com/docs/en/agent-sdk/typescript#sdkresultmessage) in TypeScript and [`ResultMessage`](https://code.claude.com/docs/en/agent-sdk/python#resultmessage) in Python. If you only need the estimated total, you can ignore the per-step usage and read this single value.
4747 
4848If you make multiple independent `query()` calls, each result reflects only the cost of that individual call. A call that resumes a session also counts the session's earlier spend.
4949 
from line 51
5151 
5252## Track costs in streaming input mode
5353 
54In [streaming input mode](/docs/en/agent-sdk/streaming-vs-single-mode.md), one `query()` call carries multiple user turns and each turn emits its own result message. The result fields differ in scope:
54In [streaming input mode](https://code.claude.com/docs/en/agent-sdk/streaming-vs-single-mode.md), one `query()` call carries multiple user turns and each turn emits its own result message. The result fields differ in scope:
5555 
5656* **`usage`**: covers only that turn, and within it only the main agent loop, not any subagents it ran.
5757* **`total_cost_usd` and `modelUsage`, or `model_usage` in Python**: carry the running total for the whole call so far, plus any spend restored when the call resumed a session.
from line 66
6666 
6767To total the whole call, add the last result from before each `/clear` to the call's final result. Every other result, including the `/clear` turn's own, is superseded by a later one.
6868 
69In TypeScript, the SDK also emits an [`SDKConversationResetMessage`](/docs/en/agent-sdk/typescript#sdkconversationresetmessage) at each reset, so you can detect resets from the stream. In Python, the SDK likewise emits a `ConversationResetMessage`. Before Python SDK v0.2.137, the Python iterator dropped that message, so on those versions count the resets yourself from the `/clear` turns your app sends.
69In TypeScript, the SDK also emits an [`SDKConversationResetMessage`](https://code.claude.com/docs/en/agent-sdk/typescript#sdkconversationresetmessage) at each reset, so you can detect resets from the stream. In Python, the SDK likewise emits a `ConversationResetMessage`. Before Python SDK v0.2.137, the Python iterator dropped that message, so on those versions count the resets yourself from the `/clear` turns your app sends.
7070 
7171`maxBudgetUsd` (TypeScript) or `max_budget_usd` (Python) counts only the call's own spend: totals restored from a resumed session don't count against it, and a `/clear` starts the budget over.
7272 
7373## Get the total cost of a query
7474 
75The result message, typed as [`SDKResultMessage`](/docs/en/agent-sdk/typescript#sdkresultmessage) in TypeScript and [`ResultMessage`](/docs/en/agent-sdk/python#resultmessage) in Python, marks the end of the agent loop for a `query()` call. It includes `total_cost_usd`, the cumulative estimated cost across all steps in that call. A call that resumes a session also counts the session's earlier spend. Two caveats apply when you read the value:
75The result message, typed as [`SDKResultMessage`](https://code.claude.com/docs/en/agent-sdk/typescript#sdkresultmessage) in TypeScript and [`ResultMessage`](https://code.claude.com/docs/en/agent-sdk/python#resultmessage) in Python, marks the end of the agent loop for a `query()` call. It includes `total_cost_usd`, the cumulative estimated cost across all steps in that call. A call that resumes a session also counts the session's earlier spend. Two caveats apply when you read the value:
7676 
7777* In Python the field is typed as optional, so check that it isn't `None` before you read it.
7878* Success and error results both carry it, though the final result of a [session crash](#recover-totals-after-a-session-crash) may carry it zeroed.
from line 79
7979 
8080In streaming input mode, read call totals as described in [Track costs in streaming input mode](#track-costs-in-streaming-input-mode).
8181 
82The three result-level fields differ in what they count when the agent spawns [subagents](/docs/en/agent-sdk/subagents.md). Use `modelUsage`, or `model_usage` in Python, for whole-tree token accounting; the `usage` field undercounts as soon as nesting occurs.
82The three result-level fields differ in what they count when the agent spawns [subagents](https://code.claude.com/docs/en/agent-sdk/subagents.md). Use `modelUsage`, or `model_usage` in Python, for whole-tree token accounting; the `usage` field undercounts as soon as nesting occurs.
8383 
8484| Field | Subagent activity |
8585| - | - |
from line 87
8787| `total_cost_usd` | Included. Counts subagent requests alongside the top-level loop |
8888| `modelUsage` / `model_usage` | Included. Counts subagent requests alongside the top-level loop, broken down by model |
8989 
90In [single message input mode](/docs/en/agent-sdk/streaming-vs-single-mode.md#single-message-input), when background subagents are still running at the end of the final turn, Claude Code waits for them, up to the cap described in [background tasks at exit](/docs/en/headless.md#background-tasks-at-exit), before emitting the result. The result's `total_cost_usd`, `duration_api_ms`, and `modelUsage`, or `model_usage` in Python, include the work done during that wait.
90In [single message input mode](https://code.claude.com/docs/en/agent-sdk/streaming-vs-single-mode.md#single-message-input), when background subagents are still running at the end of the final turn, Claude Code waits for them, up to the cap described in [background tasks at exit](https://code.claude.com/docs/en/headless.md#background-tasks-at-exit), before emitting the result. The result's `total_cost_usd`, `duration_api_ms`, and `modelUsage`, or `model_usage` in Python, include the work done during that wait.
9191 
9292The following examples iterate over the message stream from a `query()` call and print the total cost when the `result` message arrives:
9393 
from line 129
129129asyncio.run(main())
130130```
131131 
132To bound how much subagents can add to `total_cost_usd`, set the [depth, concurrency, and spend limits](/docs/en/agent-sdk/subagents.md#cap-subagent-depth-concurrency-and-spend) on the query.
132To bound how much subagents can add to `total_cost_usd`, set the [depth, concurrency, and spend limits](https://code.claude.com/docs/en/agent-sdk/subagents.md#cap-subagent-depth-concurrency-and-spend) on the query.
133133 
134134## Track per-step and per-model usage
135135 
136The examples in this section use TypeScript field names. In Python, the equivalent fields are [`AssistantMessage.usage`](/docs/en/agent-sdk/python#assistantmessage) and `AssistantMessage.message_id` for per-step usage, and [`ResultMessage.model_usage`](/docs/en/agent-sdk/python#resultmessage) for per-model breakdowns.
136The examples in this section use TypeScript field names. In Python, the equivalent fields are [`AssistantMessage.usage`](https://code.claude.com/docs/en/agent-sdk/python#assistantmessage) and `AssistantMessage.message_id` for per-step usage, and [`ResultMessage.model_usage`](https://code.claude.com/docs/en/agent-sdk/python#resultmessage) for per-model breakdowns.
137137 
138138### Track per-step usage
139139 
from line 182
182182 
183183### Break down usage per model
184184 
185The result message includes [`modelUsage`](/docs/en/agent-sdk/typescript#modelusage), a map of model name to per-model token counts and cost. This is useful when you run multiple models (for example, Haiku for subagents and Opus for the main agent) and want to see where tokens are going.
185The result message includes [`modelUsage`](https://code.claude.com/docs/en/agent-sdk/typescript#modelusage), a map of model name to per-model token counts and cost. This is useful when you run multiple models (for example, Haiku for subagents and Opus for the main agent) and want to see where tokens are going.
186186 
187Each entry's `costBasis` says which price table priced that model's latest request: `list` for list price, `managed` for a [`modelPricing`](/docs/en/settings-reference#modelpricing) table, or `unknown` when neither matched the model ID. The field requires Claude Code v2.1.246 or later.
187Each entry's `costBasis` says which price table priced that model's latest request: `list` for list price, `managed` for a [`modelPricing`](https://code.claude.com/docs/en/settings-reference#modelpricing) table, or `unknown` when neither matched the model ID. The field requires Claude Code v2.1.246 or later.
188188 
189189The following example runs a query and prints the cost and token breakdown for each model used:
190190 
from line 216
216216Each `query()` call returns `total_cost_usd` on its results. How you combine the values depends on whether the calls share a session:
217217 
218218* **Independent calls, with no `resume` or `continue` option**: each result covers only its own call, so add the totals yourself, as the examples below do.
219* **Calls that resume the same session**: Claude Code saves the session's totals to its [transcript](/docs/en/sessions.md#where-transcripts-are-stored) when the process exits normally and restores them when a later call resumes or forks the session. Each result already includes the session's earlier spend. Read the latest result for the session total; summing results double-counts the restored spend. Before v2.1.277, a session that you resumed through the SDK or `claude -p` started its totals at zero, so each call's results covered only that call.
219* **Calls that resume the same session**: Claude Code saves the session's totals to its [transcript](https://code.claude.com/docs/en/sessions.md#where-transcripts-are-stored) when the process exits normally and restores them when a later call resumes or forks the session. Each result already includes the session's earlier spend. Read the latest result for the session total; summing results double-counts the restored spend. Before v2.1.277, a session that you resumed through the SDK or `claude -p` started its totals at zero, so each call's results covered only that call.
220220 
221221Either way, the combined figure is still a [client-side estimate](#estimates-not-billing).
222222 
from line 299
299299 
300300The API reports the real output count at the end of the response, and Claude Code adds it to the result message. Read output tokens from the result's `usage`, or from `modelUsage` for a per-model breakdown.
301301 
302To watch a response's output count grow while it streams, set `includePartialMessages`, or `include_partial_messages` in Python, and read `usage` from each `message_delta` stream event, typed as [`SDKPartialAssistantMessage`](/docs/en/agent-sdk/typescript#sdkpartialassistantmessage) in TypeScript and [`StreamEvent`](/docs/en/agent-sdk/python#streamevent) in Python.
302To watch a response's output count grow while it streams, set `includePartialMessages`, or `include_partial_messages` in Python, and read `usage` from each `message_delta` stream event, typed as [`SDKPartialAssistantMessage`](https://code.claude.com/docs/en/agent-sdk/typescript#sdkpartialassistantmessage) in TypeScript and [`StreamEvent`](https://code.claude.com/docs/en/agent-sdk/python#streamevent) in Python.
303303 
304304### Track costs on failed conversations
305305 
from line 329
329329* `cache_creation_input_tokens`: tokens used to create new cache entries (charged at a higher rate than standard input tokens).
330330* `cache_read_input_tokens`: tokens read from existing cache entries (charged at a reduced rate).
331331 
332Track these separately from `input_tokens` to understand caching savings. In TypeScript, these fields are typed on the [`Usage`](/docs/en/agent-sdk/typescript#usage) object. In Python, they appear as keys in the [`ResultMessage.usage`](/docs/en/agent-sdk/python#resultmessage) dict (for example, `message.usage.get("cache_read_input_tokens", 0)`).
332Track these separately from `input_tokens` to understand caching savings. In TypeScript, these fields are typed on the [`Usage`](https://code.claude.com/docs/en/agent-sdk/typescript#usage) object. In Python, they appear as keys in the [`ResultMessage.usage`](https://code.claude.com/docs/en/agent-sdk/python#resultmessage) dict (for example, `message.usage.get("cache_read_input_tokens", 0)`).
333333 
334334### Extend the prompt cache TTL to one hour
335335 
336Your own turns fall in the [main conversation TTL bucket](/docs/en/prompt-caching.md#which-ttl-each-request-gets), together with the helpers Claude Code runs inline with them. The requests Claude Code makes outside that conversation, such as [subagents](/docs/en/agent-sdk/subagents.md), have a [separate TTL control](/docs/en/prompt-caching.md#choose-the-ttl-yourself).
336Your own turns fall in the [main conversation TTL bucket](https://code.claude.com/docs/en/prompt-caching.md#which-ttl-each-request-gets), together with the helpers Claude Code runs inline with them. The requests Claude Code makes outside that conversation, such as [subagents](https://code.claude.com/docs/en/agent-sdk/subagents.md), have a [separate TTL control](https://code.claude.com/docs/en/prompt-caching.md#choose-the-ttl-yourself).
337337 
338Cache entries for your own turns use a 5-minute TTL by default when you authenticate with an API key or run on Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry, or [Claude Platform on AWS](/docs/en/claude-platform-on-aws.md). If your workload runs many short sessions against the same system prompt and context with gaps longer than 5 minutes between them, the cache expires between sessions and each new session pays full input price.
338Cache entries for your own turns use a 5-minute TTL by default when you authenticate with an API key or run on Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry, or [Claude Platform on AWS](https://code.claude.com/docs/en/claude-platform-on-aws.md). If your workload runs many short sessions against the same system prompt and context with gaps longer than 5 minutes between them, the cache expires between sessions and each new session pays full input price.
339339 
340To request a 1-hour TTL on cache writes, set the [`ENABLE_PROMPT_CACHING_1H`](/docs/en/env-vars) environment variable. You can export it in your shell or container environment, or pass it through `options.env`.
340To request a 1-hour TTL on cache writes, set the [`ENABLE_PROMPT_CACHING_1H`](https://code.claude.com/docs/en/env-vars) environment variable. You can export it in your shell or container environment, or pass it through `options.env`.
341341 
342The following example enables 1-hour TTL for an agent running on Amazon Bedrock. Because it sets `CLAUDE_CODE_USE_BEDROCK`, it requires working AWS credentials for [Amazon Bedrock](/docs/en/amazon-bedrock.md); without them the query fails.
342The following example enables 1-hour TTL for an agent running on Amazon Bedrock. Because it sets `CLAUDE_CODE_USE_BEDROCK`, it requires working AWS credentials for [Amazon Bedrock](https://code.claude.com/docs/en/amazon-bedrock.md); without them the query fails.
343343 
344344```python Python theme={null}
345345from claude_agent_sdk import ClaudeAgentOptions, query
from line 381
381381 
382382`ENABLE_PROMPT_CACHING_1H` asks for the 1-hour TTL on every request in both buckets. To choose a TTL for each bucket separately, use these controls instead. Each takes `5m` or `1h` and takes precedence over `ENABLE_PROMPT_CACHING_1H`:
383383 
384* Main conversation: the `CLAUDE_CODE_PROMPT_CACHE_TTL` [environment variable](/docs/en/env-vars.md), or the [`promptCacheTtl`](/docs/en/settings-reference#promptcachettl) setting
385* Everything else: the `CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL` environment variable, or the [`subagentPromptCacheTtl`](/docs/en/settings-reference#subagentpromptcachettl) setting
384* Main conversation: the `CLAUDE_CODE_PROMPT_CACHE_TTL` [environment variable](https://code.claude.com/docs/en/env-vars.md), or the [`promptCacheTtl`](https://code.claude.com/docs/en/settings-reference#promptcachettl) setting
385* Everything else: the `CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL` environment variable, or the [`subagentPromptCacheTtl`](https://code.claude.com/docs/en/settings-reference#subagentpromptcachettl) setting
386386 
387Setting `promptCacheTtl` to `1h` keeps the 1-hour cache on the main conversation while you're drawing on usage credits. For the full precedence order, see [choose the TTL yourself](/docs/en/prompt-caching.md#choose-the-ttl-yourself).
387Setting `promptCacheTtl` to `1h` keeps the 1-hour cache on the main conversation while you're drawing on usage credits. For the full precedence order, see [choose the TTL yourself](https://code.claude.com/docs/en/prompt-caching.md#choose-the-ttl-yourself).
388388 
389389## Related documentation
390390 
391* [TypeScript SDK Reference](/docs/en/agent-sdk/typescript.md) - Complete API documentation
392* [SDK Overview](/docs/en/agent-sdk/overview.md) - Getting started with the SDK
393* [SDK Permissions](/docs/en/agent-sdk/permissions.md) - Managing tool permissions
391* [TypeScript SDK Reference](https://code.claude.com/docs/en/agent-sdk/typescript.md) - Complete API documentation
392* [SDK Overview](https://code.claude.com/docs/en/agent-sdk/overview.md) - Getting started with the SDK
393* [SDK Permissions](https://code.claude.com/docs/en/agent-sdk/permissions.md) - Managing tool permissions
394394 
Feedback