Organization › Analytics › Cost
Get Cost Over Time
GET /v1/organizations/analytics/cost_report
Get cost in USD over time across a date range.
Returns cost bucketed by minute, hour, or day, optionally broken down by product, model, context window, inference region, speed, cost type, or token type. Available to organizations on a Claude Enterprise plan. Requires an API key with the read:analytics scope.
Query parameters
starting_at: stringStart of range, inclusive. RFC 3339 tz-aware. Must be within the last 365 days and no earlier than 2026-01-01T00:00:00Z.
format: date-time
bucket_width: optional "1d" or "1h" or "1m"Time bucket granularity.
default: 1d
"1d""1h""1m"
claude_tag_categories: optional array of "dm" or "engaged" or "monitoring" or 2 moreFilter to Claude Tag (Claude in Slack) usage in specific spend categories. Usage with no category never matches.
dmusage is reported under the user's product rather thanclaude-tag, so combining this filter withproducts[]=claude-tagexcludes it. Usegroup_by[]=claude_tag_categoryto break out per-category values.maxItems: 100
"dm""engaged""monitoring""proactive""scheduled"
claude_tag_user_ids: optional array of stringFilter to Claude Tag (Claude in Slack) usage attributed to specific Slack users, by Slack user ID (for example
U0123ABCDEF), not claude.ai user ID. Usage that is not Claude Tag, and Claude Tag usage not attributed to a single user, never matches. Usegroup_by[]=claude_tag_user_idto break out per-user values.maxItems: 100
context_windows: optional array of "0-200k" or "200k-1M"Filter to specific context-window pricing tiers. Use
group_by[]=context_windowto break out per-tier values.maxItems: 100
"0-200k""200k-1M"
ending_at: optional stringEnd of range, exclusive. When omitted, defaults to the earlier of now and
starting_at+ 31 days. The range may span at most 31 days.format: date-time
group_by: optional array of "claude_tag_category" or "claude_tag_user_id" or "context_window" or 8 moreDimensions to break each time bucket out by. Defaults to no grouping (one total per bucket). Each bucket reports at most its top 100 groups; a group beyond that cap has no row in that bucket (there is no remainder row), so grouped buckets are not exhaustive when a dimension has more than 100 distinct values.
maxItems: 100
"claude_tag_category""claude_tag_user_id""context_window""cost_type""inference_geo""model""product""rbac_group_id""slack_channel_id""speed""token_type"
inference_geos: optional array of "global" or "not_available" or "us"Filter to specific inference regions.
not_availablematches rows where the region is unset. Usegroup_by[]=inference_geoto break out per-region values.maxItems: 100
"global""not_available""us"
limit: optional numberMaximum number of time buckets per page. Defaults and caps vary by
bucket_width(1d: default 7, max 31;1h: default 24, max 168;1m: default 60, max 256).minimum: 1
models: optional array of stringModels to include. Defaults to all models. Use
group_by[]=modelto break out per-model values.maxItems: 100
page: optional stringOpaque cursor from a previous response's
next_pagefield.products: optional array of "chat" or "claude-tag" or "claude_code" or 4 moreProduct surfaces to include. Defaults to all products. Use
group_by[]=productto break out per-product values.maxItems: 100
"chat""claude-tag""claude_code""claude_design""claude_in_chrome""cowork""office_agent"
rbac_group_ids: optional array of stringFilter to usage attributed to specific RBAC groups. Accepts tagged RBAC group IDs (
rbac_group_...) or bare group UUIDs. A row matches when the user belonged to any of the listed groups on the (UTC) day the usage occurred; usage with no group attribution never matches.maxItems: 100
slack_channel_ids: optional array of stringFilter to usage originating from specific Slack channels. Use
group_by[]=slack_channel_idto break out per-channel values.maxItems: 100
speeds: optional array of "fast" or "standard"Filter to fast or standard inference mode. Use
group_by[]=speedto break out per-mode values.maxItems: 100
"fast""standard"
user_ids: optional array of stringFilter to specific users by tagged user ID.
maxItems: 100
Returns
BetaCostBucket objectdata: array of objectTime buckets for this page, oldest first: one per
bucket_widthinterval, including intervals with no data (theirresultslist is empty). A page holds at mostlimitbuckets.ending_at: stringEnd of the time bucket (exclusive) in RFC 3339 format.
format: date-time
results: array of objectRows for this time bucket. Empty when the bucket has no data; otherwise a single combined row when
group_by[]is omitted, or one row per group (subject to the per-bucket group cap described on thegroup_by[]parameter).amount: stringAmount (post-discount, pre-credit) in fractional cents.
claude_tag_category: "dm" or "engaged" or "monitoring" or 2 more or nullClaude Tag (Claude in Slack) spend category:
engaged(a person addressed Claude in a channel or thread),proactive(Claude responded without being addressed),scheduled(a scheduled routine ran),monitoring(Claude watching a channel it was asked to monitor), ordm(direct messages with Claude). Populated only whenclaude_tag_categoryis ingroup_by[]; null for usage that is not Claude Tag. Direct-message usage is billed to the individual user and is reported under that user's product, not underclaude-tag. New categories may be added over time."dm""engaged""monitoring""proactive""scheduled"
claude_tag_user_id: string or nullSlack user ID (for example
U0123ABCDEF) of the member the Claude Tag (Claude in Slack) usage is attributed to, not a claude.ai user ID. Populated only whenclaude_tag_user_idis ingroup_by[]; null for usage that is not Claude Tag and for Claude Tag usage that is not attributed to a single user (for examplemonitoring, andproactiveusage Claude initiated), so per-user rows can sum to less than the Claude Tag total. Cannot be combined withgroup_by[]=rbac_group_idor therbac_group_ids[]filter.context_window: "0-200k" or "200k-1M" or nullContext-window pricing tier of the usage or cost. Null unless
context_windowis ingroup_by[]; it can also be null on grouped rows with no context-window tier, such as code execution."0-200k""200k-1M"
cost_type: "code_execution" or "tokens" or "web_search" or nullCost component when
group_by[]=cost_type; null otherwise (amount is the combined total)."code_execution""tokens""web_search"
currency: "USD"Currency code for the cost amount. Currently always
"USD".default: USD
inference_geo: "global" or "us" or nullInference region of the usage or cost. Null unless
inference_geois ingroup_by[]; it can also be null on grouped rows where the region is not set (the rows thatinference_geos[]=not_availablematches)."global""us"
list_amount: stringList-price amount (pre-discount) in fractional cents.
model: string or nullModel that produced the usage or cost, as a model name in the form the
models[]filter accepts (for example,claude-opus-5). Null unlessmodelis ingroup_by[]; it can also be null on grouped rows whose usage or cost is not attributed to a specific model, such as code execution.product: string or nullProduct surface that produced the usage or cost. Null unless product is in
group_by[]; it can also be null on grouped rows whose usage cannot be attributed to a known surface. Values includechat,claude_code,cowork,office_agent,claude_in_chrome,claude_design, andclaude-tag.claude-tagis Claude Tag, the Claude product in Slack. Some unattributed usage is reported as "other".rbac_group_id: string or nullRBAC group (team) the usage is attributed to, in the public tagged
rbac_group_...spelling — the same spelling the activity resources use for this key, so the same team has one id across resources and it round-trips as anrbac_group_ids[]filter value. Populated only whenrbac_group_idis ingroup_by[]. Any-membership semantics: a user in several groups contributes their full usage to each of those groups' rows, so the named-group rows overlap and their sum can exceed the org total. A null value is the single unassigned row: users in no group on that (UTC) day. For the true org total, run the same query withoutgroup_by[].requests: number or nullNumber of API requests in this row's scope. Null when
group_byincludescost_typeortoken_type(the count has no per-component attribution; read it from the ungrouped response). For sandbox / code-execution events, this counts execution spans rather than HTTP requests (these rows surface withproduct: null).slack_channel_id: string or nullSlack channel the usage originated from. Populated only when
slack_channel_idis ingroup_by[]; null for usage outside Slack (and for rows recorded before channel attribution was enabled).speed: "fast" or "standard" or nullInference speed mode of the usage or cost:
fastorstandard. Null unlessspeedis ingroup_by[]."fast""standard"
token_type: "cache_creation.ephemeral_1h_input_tokens" or "cache_creation.ephemeral_5m_input_tokens" or "cache_read_input_tokens" or 2 more or nullToken type when
group_by[]=token_typeandcost_type=tokens; null otherwise."cache_creation.ephemeral_1h_input_tokens""cache_creation.ephemeral_5m_input_tokens""cache_read_input_tokens""output_tokens""uncached_input_tokens"
starting_at: stringStart of the time bucket (inclusive) in RFC 3339 format.
format: date-time
data_refreshed_at: string or nullRFC 3339 timestamp of the export this response was served from. Null when no export yet covers any part of the requested range, in which case every bucket's
resultslist is empty. Buckets beyond this watermark are incomplete; for stable results, setending_atto this value or earlier. Data is typically refreshed every 4 hours but not final until about 30 days after the usage date (late-arriving events, reconciliation adjustments).format: date-time
has_more: booleanWhether another page is available. When true, pass
next_pageas thepageparameter to fetch it.next_page: string or nullOpaque cursor for the next page, or null when
has_moreis false. Pass it as thepageparameter, keeping the other parameters unchanged. A cursor can expire after the underlying data refreshes; the request then returns HTTP 410 and pagination must restart from the first page.organization_id: stringID of the Organization.
Example
curl https://api.anthropic.com/v1/organizations/analytics/cost_report \
-H 'anthropic-version: 2023-06-01' \
-H "X-Api-Key: $ANTHROPIC_API_KEY"Response (200)
{
"data": [
{
"ending_at": "2019-12-27T18:11:19.117Z",
"results": [
{
"amount": "amount",
"claude_tag_category": "dm",
"claude_tag_user_id": "U0123ABCDEF",
"context_window": "0-200k",
"cost_type": "code_execution",
"currency": "USD",
"inference_geo": "global",
"list_amount": "list_amount",
"model": "claude-opus-5",
"product": "chat",
"rbac_group_id": "rbac_group_012rppKaSVsmTo6NqRDXQXNF",
"requests": 0,
"slack_channel_id": "C0123ABCDEF",
"speed": "fast",
"token_type": "cache_creation.ephemeral_1h_input_tokens"
}
],
"starting_at": "2019-12-27T18:11:19.117Z"
}
],
"data_refreshed_at": "2019-12-27T18:11:19.117Z",
"has_more": true,
"next_page": "next_page",
"organization_id": "org_013FP9SaFPBg7Kw7fetjn6cF"
}Get Per-User Cost
GET /v1/organizations/analytics/user_cost_report
Get per-user cost in USD across a date range.
Returns one row per user, ranked by spend. Use this to see which users account for the most cost. Only cost attributable to a seat user is included; for organization-wide totals including direct API-key and automation traffic, use the bucketed /v1/organizations/analytics/cost_report endpoint. Available to organizations on a Claude Enterprise plan. Requires an API key with the read:analytics scope.
Query parameters
starting_at: stringStart of range, inclusive. RFC 3339 tz-aware. Must be within the last 365 days and no earlier than 2026-01-01T00:00:00Z.
format: date-time
bucket_width: optional "1d" or "1h" or "1m"Time-bucket granularity. When set, each row's
starting_atandending_atare populated and one actor may span several rows (one per time bucket with usage). The time bucket counts towardlimit, so one page can return multiple rows for the same actor.ending_atis required whenbucket_widthis set, and withbucket_width="1m"the range may span at most 24 hours. When omitted, each row aggregates the full[starting_at, ending_at)range."1d""1h""1m"
claude_tag_categories: optional array of "dm" or "engaged" or "monitoring" or 2 moreFilter to Claude Tag (Claude in Slack) usage in specific spend categories. Usage with no category never matches.
dmusage is reported under the user's product rather thanclaude-tag, so combining this filter withproducts[]=claude-tagexcludes it. Usegroup_by[]=claude_tag_categoryto break out per-category values.maxItems: 100
"dm""engaged""monitoring""proactive""scheduled"
claude_tag_user_ids: optional array of stringFilter to Claude Tag (Claude in Slack) usage attributed to specific Slack users, by Slack user ID (for example
U0123ABCDEF), not claude.ai user ID. Usage that is not Claude Tag, and Claude Tag usage not attributed to a single user, never matches. Usegroup_by[]=claude_tag_user_idto break out per-user values.maxItems: 100
context_windows: optional array of "0-200k" or "200k-1M"Filter to specific context-window pricing tiers. Use
group_by[]=context_windowto break out per-tier values.maxItems: 100
"0-200k""200k-1M"
ending_at: optional stringEnd of range, exclusive. When omitted, defaults to the earlier of now and
starting_at+ 31 days. The range may span at most 31 days.format: date-time
exclude_deleted_users: optional booleanIf true, omit rows for users who are deleted (
deleted: true). A page may contain fewer thanlimitrows; usehas_moreandnext_pageto paginate as usual.default: false
group_by: optional array of "claude_tag_category" or "claude_tag_user_id" or "context_window" or 8 moreBreak each actor's row out by the given dimensions. Accepts the same values as the bucketed
/cost_reportendpoint. Theproduct,model,context_window,inference_geo, andspeeddimensions — and the time bucket, whenbucket_widthis set — count towardlimit.cost_typeandtoken_typedo not:cost_typereturns one row per cost component (tokens, web search, code execution);token_typereturns one row per token type, each withcost_type: "tokens"; combining both returns the per-token-type rows plus the web-search and code-execution rows. A page can therefore contain more rows thanlimitwhencost_typeortoken_typeis requested.maxItems: 100
"claude_tag_category""claude_tag_user_id""context_window""cost_type""inference_geo""model""product""rbac_group_id""slack_channel_id""speed""token_type"
inference_geos: optional array of "global" or "not_available" or "us"Filter to specific inference regions.
not_availablematches rows where the region is unset. Usegroup_by[]=inference_geoto break out per-region values.maxItems: 100
"global""not_available""us"
limit: optional numberNumber of rows per page (1-1000, default 20). One row per actor unless
group_by[]orbucket_widthsplits an actor across rows;cost_type/token_typefan-out rows (cost endpoint only) are the exception — they do not count toward this limit, sodatacan exceed it.default: 20, maximum: 1000, minimum: 1
models: optional array of stringModels to include. Defaults to all models. Use
group_by[]=modelto break out per-model values.maxItems: 100
order: optional "asc" or "desc"Sort direction. Defaults to
desc.default: desc
"asc""desc"
order_by: optional "amount" or "list_amount"Metric to rank actors by. Defaults to
amount.default: amount
"amount""list_amount"
page: optional stringOpaque cursor from a previous response's
next_pagefield.products: optional array of "chat" or "claude-tag" or "claude_code" or 4 moreProduct surfaces to include. Defaults to all products.
maxItems: 100
"chat""claude-tag""claude_code""claude_design""claude_in_chrome""cowork""office_agent"
rbac_group_ids: optional array of stringFilter to usage attributed to specific RBAC groups. Accepts tagged RBAC group IDs (
rbac_group_...) or bare group UUIDs. A row matches when the user belonged to any of the listed groups on the (UTC) day the usage occurred; usage with no group attribution never matches.maxItems: 100
slack_channel_ids: optional array of stringFilter to usage originating from specific Slack channels. Use
group_by[]=slack_channel_idto break out per-channel values.maxItems: 100
speeds: optional array of "fast" or "standard"Filter to fast or standard inference mode. Use
group_by[]=speedto break out per-mode values.maxItems: 100
"fast""standard"
user_ids: optional array of stringFilter to specific users by tagged user ID.
maxItems: 100
Returns
BetaUserCost objectdata: array of objectRows for this page, ranked by
order_byin theorderdirection. One row per user, or several per user whengroup_by[]orbucket_widthbreaks that user's usage or cost out across rows. Rows split out bycost_typeortoken_type(cost endpoint only) stay adjacent and are ranked as one unit.actor: BetaAnalyticsUserActorThe user this row's usage or cost is attributed to. Always a
user_actor.type: "user_actor"Actor type. Always
"user_actor".deleted: booleanTrue when the account has been deleted, or when the user is no longer a member of the organization or its associated organizations (for example, their membership was removed or they were deprovisioned via your identity provider).
emailstays populated for removed users and is null when the account has been deleted.namefollows the rules described on that field. Theuser_idis still populated for reconciliation.email: string or nullThe user's email address, including for users who are no longer members of the organization or its associated organizations. Null when the account has been deleted (check
deleted) and for system-minted service accounts, which have no person's mailbox behind them (checkname).name: string or nullThe user's full name. Null when the user has not set a name. Returns
"Deleted User"when the account itself has been deleted, or when the user is no longer a member of the organization or its associated organizations and the organization has chosen to hide the names of removed users. Otherwise, the name stays populated for removed users. Rows for system-minted service accounts render the service name (for example,"Claude Security"for usage by Anthropic's security-patching service) or null.user_id: stringTagged user ID.
amount: stringAmount (post-discount, pre-credit) in fractional cents (minor units).
claude_tag_category: "dm" or "engaged" or "monitoring" or 2 more or nullClaude Tag (Claude in Slack) spend category:
engaged(a person addressed Claude in a channel or thread),proactive(Claude responded without being addressed),scheduled(a scheduled routine ran),monitoring(Claude watching a channel it was asked to monitor), ordm(direct messages with Claude). Populated only whenclaude_tag_categoryis ingroup_by[]; null for usage that is not Claude Tag. Direct-message usage is billed to the individual user and is reported under that user's product, not underclaude-tag. New categories may be added over time."dm""engaged""monitoring""proactive""scheduled"
claude_tag_user_id: string or nullSlack user ID (for example
U0123ABCDEF) of the member the Claude Tag (Claude in Slack) usage is attributed to, not a claude.ai user ID. Populated only whenclaude_tag_user_idis ingroup_by[]; null for usage that is not Claude Tag and for Claude Tag usage that is not attributed to a single user (for examplemonitoring, andproactiveusage Claude initiated), so per-user rows can sum to less than the Claude Tag total. Cannot be combined withgroup_by[]=rbac_group_idor therbac_group_ids[]filter.context_window: "0-200k" or "200k-1M" or nullContext-window pricing tier of the usage or cost. Null unless
context_windowis ingroup_by[]; it can also be null on grouped rows with no context-window tier, such as code execution."0-200k""200k-1M"
cost_type: "code_execution" or "tokens" or "web_search" or nullCost component breakdown; null when returning the combined total.
"code_execution""tokens""web_search"
currency: "USD"Currency code for the cost amount. Currently always
"USD".default: USD
ending_at: string or nullEnd of the row's UTC time bucket (exclusive), as an RFC 3339 timestamp; equal to
starting_atplus onebucket_width. Null unlessbucket_widthis set.format: date-time
inference_geo: "global" or "us" or nullInference region of the usage or cost. Null unless
inference_geois ingroup_by[]; it can also be null on grouped rows where the region is not set (the rows thatinference_geos[]=not_availablematches)."global""us"
list_amount: stringList-price amount (pre-discount) in fractional cents.
model: string or nullModel that produced the usage or cost, as a model name in the form the
models[]filter accepts (for example,claude-opus-5). Null unlessmodelis ingroup_by[]; it can also be null on grouped rows whose usage or cost is not attributed to a specific model, such as code execution.product: string or nullProduct surface that produced the usage or cost. Null unless product is in
group_by[]; it can also be null on grouped rows whose usage cannot be attributed to a known surface. Values includechat,claude_code,cowork,office_agent,claude_in_chrome,claude_design, andclaude-tag.claude-tagis Claude Tag, the Claude product in Slack. Some unattributed usage is reported as "other".rbac_group_id: string or nullRBAC group (team) the usage is attributed to, in the public tagged
rbac_group_...spelling — the same spelling the activity resources use for this key, so the same team has one id across resources and it round-trips as anrbac_group_ids[]filter value. Populated only whenrbac_group_idis ingroup_by[]. Any-membership semantics: a user in several groups contributes their full usage to each of those groups' rows, so the named-group rows overlap and their sum can exceed the org total. A null value is the single unassigned row: users in no group on that (UTC) day. For the true org total, run the same query withoutgroup_by[].requests: number or nullNumber of API requests in this row's scope. Null when
group_byincludescost_typeortoken_type(the count has no per-component attribution; read it from the ungrouped response). For sandbox / code-execution events, this counts execution spans rather than HTTP requests (these rows surface withproduct: null).slack_channel_id: string or nullSlack channel the usage originated from. Populated only when
slack_channel_idis ingroup_by[]; null for usage outside Slack (and for rows recorded before channel attribution was enabled).speed: "fast" or "standard" or nullInference speed mode of the usage or cost:
fastorstandard. Null unlessspeedis ingroup_by[]."fast""standard"
starting_at: string or nullStart of the row's UTC time bucket (inclusive), as an RFC 3339 timestamp. Null unless
bucket_widthis set; withoutbucket_width, each row aggregates the full requested range.format: date-time
token_type: "cache_creation.ephemeral_1h_input_tokens" or "cache_creation.ephemeral_5m_input_tokens" or "cache_read_input_tokens" or 2 more or nullToken type when
cost_typeistokens; null otherwise."cache_creation.ephemeral_1h_input_tokens""cache_creation.ephemeral_5m_input_tokens""cache_read_input_tokens""output_tokens""uncached_input_tokens"
data_refreshed_at: string or nullRFC 3339 timestamp of the export this response was served from. Null when no export yet covers any part of the requested range, in which case
datais empty. Data beyond this watermark is incomplete; for stable results, setending_atto this value or earlier. Data is typically refreshed every 4 hours but not final until about 30 days after the usage date (late-arriving events, reconciliation adjustments).format: date-time
has_more: booleanWhether another page is available. When true, pass
next_pageas thepageparameter to fetch it.next_page: string or nullOpaque cursor for the next page, or null when
has_moreis false. Pass it as thepageparameter, keeping the other parameters unchanged. A cursor can expire after the underlying data refreshes; the request then returns HTTP 410 and pagination must restart from the first page.organization_id: stringID of the Organization.
Example
curl https://api.anthropic.com/v1/organizations/analytics/user_cost_report \
-H 'anthropic-version: 2023-06-01' \
-H "X-Api-Key: $ANTHROPIC_API_KEY"Response (200)
{
"data": [
{
"actor": {
"deleted": true,
"email": "jane@example.com",
"name": "Jane Smith",
"type": "user_actor",
"user_id": "user_01AbCdEfGhIjKlMnOpQrSt"
},
"amount": "41280.000000",
"claude_tag_category": "dm",
"claude_tag_user_id": "U0123ABCDEF",
"context_window": "0-200k",
"cost_type": "code_execution",
"currency": "USD",
"ending_at": "2019-12-27T18:11:19.117Z",
"inference_geo": "global",
"list_amount": "51600.000000",
"model": "claude-opus-5",
"product": "chat",
"rbac_group_id": "rbac_group_012rppKaSVsmTo6NqRDXQXNF",
"requests": 128,
"slack_channel_id": "C0123ABCDEF",
"speed": "fast",
"starting_at": "2019-12-27T18:11:19.117Z",
"token_type": "cache_creation.ephemeral_1h_input_tokens"
}
],
"data_refreshed_at": "2019-12-27T18:11:19.117Z",
"has_more": true,
"next_page": "next_page",
"organization_id": "org_013FP9SaFPBg7Kw7fetjn6cF"
}