> For the complete documentation index, see [llms.txt](https://docs.otari.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.otari.ai/otari/for-integrators/api-reference/organization-usage.md).

# Organization usage

## List Organization Usage

> List the caller's organization's usage logs, most recent first.\
> \
> The tenant-scoped counterpart of \`\`GET /api/v1/usage\`\`: same filters, same bare\
> JSON array, same separate \`\`/count\`\` for a paginator's total, confined to\
> what the caller's membership lets them see. Scope is never a parameter here.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"UsageEntry":{"description":"A single usage log entry.","properties":{"api_key_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key Id"},"api_key_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key Name"},"attempt_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Attempt Count"},"attempt_position":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Attempt Position"},"billing_meters":{"anyOf":[{"$ref":"#/components/schemas/BillingMeters"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Billing Meters"},"bulk_editable":{"title":"Bulk Editable","type":"boolean"},"cache_read_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cache Read Tokens"},"cache_write_1h_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cache Write 1H Tokens"},"cache_write_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cache Write Tokens"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Completion Tokens"},"cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost"},"counts_toward_budget":{"title":"Counts Toward Budget","type":"boolean"},"endpoint":{"title":"Endpoint","type":"string"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"id":{"title":"Id","type":"string"},"latency_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latency Ms"},"model":{"title":"Model","type":"string"},"policy_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Policy Name"},"pricing_breakdown":{"anyOf":[{"items":{"anyOf":[{"$ref":"#/components/schemas/ToolChargeLine"},{"$ref":"#/components/schemas/TokenChargeLine"},{"$ref":"#/components/schemas/UnitChargeLine"},{"additionalProperties":true,"type":"object"}]},"type":"array"},{"type":"null"}],"title":"Pricing Breakdown"},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Prompt Tokens"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"},"provider_latency_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Provider Latency Ms"},"reasoning_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reasoning Tokens"},"request_group_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Group Id"},"selection_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selection Reason"},"source":{"title":"Source","type":"string"},"source_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Label"},"status":{"title":"Status","type":"string"},"status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status Code"},"tags":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Tags"},"timestamp":{"title":"Timestamp","type":"string"},"total_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Tokens"},"user_alias":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Alias"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"}},"required":["id","user_id","api_key_id","timestamp","model","provider","endpoint","prompt_tokens","completion_tokens","total_tokens","cache_read_tokens","cache_write_tokens","cache_write_1h_tokens","billing_meters","pricing_breakdown","cost","status","error_message","status_code","latency_ms","provider_latency_ms","source","source_label","counts_toward_budget","bulk_editable"],"title":"UsageEntry","type":"object"},"BillingMeters":{"additionalProperties":true,"description":"The meters a request was billed on.\n\nToken meters sit flat (``{\"input\": 1200}``), which is why extra keys are\nallowed: the names come from the provider and the endpoint, so the map is\ngenuinely open. Gateway-run tool counts are the one reserved key, nested\nunder ``tools`` because an MCP server can advertise a tool named after a\ntoken meter and a flat collision would corrupt the billed-token aggregates\nfor the whole window (see ``gateway.services.tool_usage``).\n\nA TypedDict for the reason above, and for one that cost a round trip to\nlearn: a model that suppressed its defaults with a ``model_serializer``\npublished an *empty* schema, because that serializer replaces the\nserialization JSON schema and that is the one FastAPI puts in the spec. The\nproperties below are the whole point, so they have to survive into\ndocs/public/openapi.json; ``tests/unit/test_billing_schemas.py`` asserts they\ndo.","properties":{"tools":{"additionalProperties":{"$ref":"#/components/schemas/ToolMeter"},"title":"Tools","type":"object"}},"title":"BillingMeters","type":"object"},"ToolMeter":{"additionalProperties":true,"description":"One gateway-run tool's call counts on a request.\n\nA TypedDict rather than a model, and every key optional, so a stored entry\nserializes back as it was written: a model with defaults would put\n``\"unit_rate\": null`` on every tool that has never been priced.","properties":{"billed":{"title":"Billed","type":"integer"},"errors":{"title":"Errors","type":"integer"},"unit_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Unit Rate"}},"title":"ToolMeter","type":"object"},"ToolChargeLine":{"additionalProperties":true,"description":"A gateway-run tool's charge line, one per tool, label and payer.\n\nA subclass with ``label`` required, rather than a defaulted field on\n:class:`UnitChargeLine`, so the per-request, rerank and image lines, and a\nstored tool line without a label, serialize back without a\n``\"label\": null`` they never had.\n\nA line written since tools are charged by whose account ran them also\ncarries ``deployment_paid``: true where the deployment's account ran the\ncalls, which charges the organization's funds where the deployment bills\nthem, and false where the organization's own key did. It is kept as an extra\nkey rather than declared, so an older line serializes back without it.","properties":{"cost":{"description":"USD charged for this line.","title":"Cost","type":"number"},"label":{"description":"What served the calls: '<provider>:<instance>' for a search or fetch instance, 'builtin:builtin_fetch' for the built-in fetcher, 'org:<provider>' for an organization's own key, or 'otari:<tool>' for any other gateway-run tool.","title":"Label","type":"string"},"meter":{"description":"What was metered, e.g. 'request' or 'web_search_calls'.","title":"Meter","type":"string"},"unit_rate":{"description":"USD per call.","title":"Unit Rate","type":"number"},"units":{"anyOf":[{"type":"integer"},{"type":"number"}],"description":"Calls billed on this meter.","title":"Units"}},"required":["meter","units","unit_rate","cost","label"],"title":"ToolChargeLine","type":"object"},"TokenChargeLine":{"additionalProperties":true,"description":"A charge line billed per million tokens.\n\n``rate_per_million`` is the discriminator: its presence (rather than\n``unit_rate``) is what tells a reader, and a renderer, which unit convention\napplies. See ``gateway.services.pricing_service``.","properties":{"cost":{"description":"USD charged for this line.","title":"Cost","type":"number"},"meter":{"description":"What was metered, e.g. 'input' or 'cache_read'.","title":"Meter","type":"string"},"rate_per_million":{"description":"USD per million units.","title":"Rate Per Million","type":"number"},"units":{"anyOf":[{"type":"integer"},{"type":"number"}],"description":"Tokens billed on this meter.","title":"Units"}},"required":["meter","units","rate_per_million","cost"],"title":"TokenChargeLine","type":"object"},"UnitChargeLine":{"additionalProperties":true,"description":"A charge line billed per call, for gateway-run tools and per-request routes.\n\n``unit_rate`` is the discriminator, in the same sense as\n:class:`TokenChargeLine`'s ``rate_per_million``.","properties":{"cost":{"description":"USD charged for this line.","title":"Cost","type":"number"},"meter":{"description":"What was metered, e.g. 'request' or 'web_search_calls'.","title":"Meter","type":"string"},"unit_rate":{"description":"USD per call.","title":"Unit Rate","type":"number"},"units":{"anyOf":[{"type":"integer"},{"type":"number"}],"description":"Calls billed on this meter.","title":"Units"}},"required":["meter","units","unit_rate","cost"],"title":"UnitChargeLine","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/organizations/me/usage":{"get":{"description":"List the caller's organization's usage logs, most recent first.\n\nThe tenant-scoped counterpart of ``GET /api/v1/usage``: same filters, same bare\nJSON array, same separate ``/count`` for a paginator's total, confined to\nwhat the caller's membership lets them see. Scope is never a parameter here.","operationId":"organization-usage-list_organization_usage","parameters":[{"description":"Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)","in":"query","name":"start_date","required":false,"schema":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)","title":"Start Date"}},{"description":"Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)","in":"query","name":"end_date","required":false,"schema":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)","title":"End Date"}},{"description":"Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.","in":"query","name":"user_id","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.","title":"User Id"}},{"description":"Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)","in":"query","name":"status","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)","title":"Status"}},{"description":"Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly","in":"query","name":"status_code","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly","title":"Status Code"}},{"description":"Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.","in":"query","name":"model","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.","title":"Model"}},{"description":"Filter to a single endpoint (e.g. '/v1/chat/completions')","in":"query","name":"endpoint","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single endpoint (e.g. '/v1/chat/completions')","title":"Endpoint"}},{"description":"Filter to a single provider (e.g. 'openai')","in":"query","name":"provider","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single provider (e.g. 'openai')","title":"Provider"}},{"description":"Filter to a single provenance source (e.g. 'gateway' or 'claude_code')","in":"query","name":"source","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single provenance source (e.g. 'gateway' or 'claude_code')","title":"Source"}},{"description":"Filter to a single session (source_label): the session's trace id on a gateway request that named one, or the session/project label imported usage carried","in":"query","name":"source_label","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single session (source_label): the session's trace id on a gateway request that named one, or the session/project label imported usage carried","title":"Source Label"}},{"description":"Filter by a request tag (what a request sent in its `metadata`), as `key:value`. Repeatable: values for the same key match any of them, and different keys must all match. At most 50 per call.","in":"query","name":"tag","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter by a request tag (what a request sent in its `metadata`), as `key:value`. Repeatable: values for the same key match any of them, and different keys must all match. At most 50 per call.","title":"Tag"}},{"description":"Filter to one or more API key ids; repeatable (api_key_id=a&api_key_id=b). Several values match any of them. At most 50 per call.","in":"query","name":"api_key_id","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more API key ids; repeatable (api_key_id=a&api_key_id=b). Several values match any of them. At most 50 per call.","title":"Api Key Id"}},{"description":"Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.","in":"query","name":"priced","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.","title":"Priced"}},{"description":"Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, web_fetch, code_execution) matches that tool specifically.","in":"query","name":"tool","required":false,"schema":{"anyOf":[{"enum":["any","web_search","web_fetch","code_execution"],"type":"string"},{"type":"null"}],"description":"Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, web_fetch, code_execution) matches that tool specifically.","title":"Tool"}},{"description":"Filter by budget participation, which is not the same question as provenance: true = only enforced gateway rows, false = every row that never touches a budget, meaning imported usage and also gateway traffic on a budget-exempt key","in":"query","name":"counts_toward_budget","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by budget participation, which is not the same question as provenance: true = only enforced gateway rows, false = every row that never touches a budget, meaning imported usage and also gateway traffic on a budget-exempt key","title":"Counts Toward Budget"}},{"description":"Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call.","in":"query","name":"request_group_id","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":1000,"type":"array"},{"type":"null"}],"description":"Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call.","title":"Request Group Id"}},{"description":"Only usage recorded in this workspace.","in":"query","name":"workspace_id","required":false,"schema":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Only usage recorded in this workspace.","title":"Workspace Id"}},{"in":"query","name":"skip","required":false,"schema":{"default":0,"minimum":0,"title":"Skip","type":"integer"}},{"in":"query","name":"limit","required":false,"schema":{"default":100,"maximum":1000,"minimum":1,"title":"Limit","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/UsageEntry"},"title":"Response Organization-Usage-List Organization Usage","type":"array"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"List Organization Usage","tags":["organization-usage"]}}}}
```

## Count Organization Usage

> Total rows matching these filters, within the caller's scope.\
> \
> Serves the paginator's "N of M" beside the list above, and is scoped the\
> same way, so the total can never describe more rows than the list will show.\
> \
> Unlike the operator's \`\`GET /api/v1/usage/count\`\`, \`\`counts\_toward\_budget=false\`\`\
> is not narrowed to imported rows here: that narrowing sizes the bulk mutations, and\
> this surface has none. So this total keeps matching the list beside it.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"UsageCount":{"description":"Total number of usage logs matching a set of filters.","properties":{"total":{"title":"Total","type":"integer"}},"required":["total"],"title":"UsageCount","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/organizations/me/usage/count":{"get":{"description":"Total rows matching these filters, within the caller's scope.\n\nServes the paginator's \"N of M\" beside the list above, and is scoped the\nsame way, so the total can never describe more rows than the list will show.\n\nUnlike the operator's ``GET /api/v1/usage/count``, ``counts_toward_budget=false``\nis not narrowed to imported rows here: that narrowing sizes the bulk mutations, and\nthis surface has none. So this total keeps matching the list beside it.","operationId":"organization-usage-count_organization_usage","parameters":[{"description":"Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)","in":"query","name":"start_date","required":false,"schema":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)","title":"Start Date"}},{"description":"Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)","in":"query","name":"end_date","required":false,"schema":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)","title":"End Date"}},{"description":"Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.","in":"query","name":"user_id","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.","title":"User Id"}},{"description":"Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)","in":"query","name":"status","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)","title":"Status"}},{"description":"Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly","in":"query","name":"status_code","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly","title":"Status Code"}},{"description":"Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.","in":"query","name":"model","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.","title":"Model"}},{"description":"Filter to a single endpoint (e.g. '/v1/chat/completions')","in":"query","name":"endpoint","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single endpoint (e.g. '/v1/chat/completions')","title":"Endpoint"}},{"description":"Filter to a single provider (e.g. 'openai')","in":"query","name":"provider","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single provider (e.g. 'openai')","title":"Provider"}},{"description":"Filter to a single provenance source (e.g. 'gateway' or 'claude_code')","in":"query","name":"source","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single provenance source (e.g. 'gateway' or 'claude_code')","title":"Source"}},{"description":"Filter to a single session (source_label): the session's trace id on a gateway request that named one, or the session/project label imported usage carried","in":"query","name":"source_label","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single session (source_label): the session's trace id on a gateway request that named one, or the session/project label imported usage carried","title":"Source Label"}},{"description":"Filter by a request tag (what a request sent in its `metadata`), as `key:value`. Repeatable: values for the same key match any of them, and different keys must all match. At most 50 per call.","in":"query","name":"tag","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter by a request tag (what a request sent in its `metadata`), as `key:value`. Repeatable: values for the same key match any of them, and different keys must all match. At most 50 per call.","title":"Tag"}},{"description":"Filter to one or more API key ids; repeatable (api_key_id=a&api_key_id=b). Several values match any of them. At most 50 per call.","in":"query","name":"api_key_id","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more API key ids; repeatable (api_key_id=a&api_key_id=b). Several values match any of them. At most 50 per call.","title":"Api Key Id"}},{"description":"Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.","in":"query","name":"priced","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.","title":"Priced"}},{"description":"Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, web_fetch, code_execution) matches that tool specifically.","in":"query","name":"tool","required":false,"schema":{"anyOf":[{"enum":["any","web_search","web_fetch","code_execution"],"type":"string"},{"type":"null"}],"description":"Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, web_fetch, code_execution) matches that tool specifically.","title":"Tool"}},{"description":"Filter by budget participation, which is not the same question as provenance: true = only enforced gateway rows, false = every row that never touches a budget, meaning imported usage and also gateway traffic on a budget-exempt key","in":"query","name":"counts_toward_budget","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by budget participation, which is not the same question as provenance: true = only enforced gateway rows, false = every row that never touches a budget, meaning imported usage and also gateway traffic on a budget-exempt key","title":"Counts Toward Budget"}},{"description":"Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call.","in":"query","name":"request_group_id","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":1000,"type":"array"},{"type":"null"}],"description":"Filter to the rows of one or more request groups; repeatable (request_group_id=a&request_group_id=b). A routed request writes one row per attempt, all sharing a request_group_id, so this returns a request's whole plan: its absorbed attempts and the attempt that served it. Ignore ordering by timestamp and read attempt_position to reconstruct the plan. At most 1000 ids per call.","title":"Request Group Id"}},{"description":"Only usage recorded in this workspace.","in":"query","name":"workspace_id","required":false,"schema":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Only usage recorded in this workspace.","title":"Workspace Id"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageCount"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Count Organization Usage","tags":["organization-usage"]}}}}
```

## Organization Usage Series

> Time series split by one dimension, for the caller's organization.\
> \
> The tenant-scoped counterpart of \`\`GET /api/v1/usage/series\`\`, and kept in\
> lockstep with the summary above for the reason that endpoint gives: the\
> dashboard serializes one filter object for both, so a filter one of them\
> ignored would make the stacked chart disagree with the tiles beside it.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"UsageGroupedSeries":{"description":"A per-group time series for the dashboard's stacked charts.\n\n``groups`` ranks the window's top groups by spend (plus the reconciling\n``other`` fold), in the order a chart should stack and color them; ``points``\nis sparse (only populated cells), keyed by canonical UTC ``bucket_start``.","properties":{"bucket":{"enum":["hour","day"],"title":"Bucket","type":"string"},"end_date":{"title":"End Date","type":"string"},"group_by":{"enum":["model","user_id","api_key_id","source"],"title":"Group By","type":"string"},"groups":{"items":{"$ref":"#/components/schemas/UsageGroupRow"},"title":"Groups","type":"array"},"points":{"items":{"$ref":"#/components/schemas/UsageGroupedSeriesPoint"},"title":"Points","type":"array"},"start_date":{"title":"Start Date","type":"string"}},"required":["start_date","end_date","bucket","group_by","groups","points"],"title":"UsageGroupedSeries","type":"object"},"UsageGroupRow":{"description":"One breakdown row (a model, a user, an API key, a session, ...).\n\n``key`` is None both for the synthesized fold row (``is_other=True``) and for a\nreal group whose column was NULL (e.g. usage from a since-deleted user, with\n``is_other=False``). ``is_other`` disambiguates the two so the UI does not\nmislabel deleted-user usage as the fold.","properties":{"cost":{"title":"Cost","type":"number"},"is_other":{"default":false,"title":"Is Other","type":"boolean"},"key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"requests":{"title":"Requests","type":"integer"},"tokens":{"title":"Tokens","type":"integer"}},"required":["key","cost","tokens","requests"],"title":"UsageGroupRow","type":"object"},"UsageGroupedSeriesPoint":{"description":"One (time bucket, group) cell of a grouped series.\n\n``key``/``is_other`` follow the ``UsageGroupRow`` convention: ``key=None``\nwith ``is_other=True`` is the fold of groups outside the top N, ``key=None``\nwith ``is_other=False`` is a real NULL group (e.g. a deleted user).\n``tokens`` is the *billed* total (input including cache, plus output), the\nsame quantity the ungrouped series' composition fields sum to.","properties":{"bucket_start":{"title":"Bucket Start","type":"string"},"cost":{"title":"Cost","type":"number"},"is_other":{"default":false,"title":"Is Other","type":"boolean"},"key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key"},"requests":{"title":"Requests","type":"integer"},"tokens":{"title":"Tokens","type":"integer"}},"required":["bucket_start","key","cost","tokens","requests"],"title":"UsageGroupedSeriesPoint","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/organizations/me/usage/series":{"get":{"description":"Time series split by one dimension, for the caller's organization.\n\nThe tenant-scoped counterpart of ``GET /api/v1/usage/series``, and kept in\nlockstep with the summary above for the reason that endpoint gives: the\ndashboard serializes one filter object for both, so a filter one of them\nignored would make the stacked chart disagree with the tiles beside it.","operationId":"organization-usage-organization_usage_series","parameters":[{"description":"Dimension to split the series by","in":"query","name":"group_by","required":true,"schema":{"description":"Dimension to split the series by","enum":["model","user_id","api_key_id","source"],"title":"Group By","type":"string"}},{"description":"Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)","in":"query","name":"start_date","required":false,"schema":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)","title":"Start Date"}},{"description":"Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)","in":"query","name":"end_date","required":false,"schema":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)","title":"End Date"}},{"description":"Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.","in":"query","name":"user_id","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.","title":"User Id"}},{"description":"Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)","in":"query","name":"status","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)","title":"Status"}},{"description":"Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly","in":"query","name":"status_code","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly","title":"Status Code"}},{"description":"Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.","in":"query","name":"model","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.","title":"Model"}},{"description":"Filter to a single endpoint (e.g. '/v1/chat/completions')","in":"query","name":"endpoint","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single endpoint (e.g. '/v1/chat/completions')","title":"Endpoint"}},{"description":"Filter to a single provider (e.g. 'openai')","in":"query","name":"provider","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single provider (e.g. 'openai')","title":"Provider"}},{"description":"Filter to a single provenance source (e.g. 'gateway' or 'claude_code')","in":"query","name":"source","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single provenance source (e.g. 'gateway' or 'claude_code')","title":"Source"}},{"description":"Filter to a single session (source_label): the session's trace id on a gateway request that named one, or the session/project label imported usage carried","in":"query","name":"source_label","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single session (source_label): the session's trace id on a gateway request that named one, or the session/project label imported usage carried","title":"Source Label"}},{"description":"Filter by a request tag (what a request sent in its `metadata`), as `key:value`. Repeatable: values for the same key match any of them, and different keys must all match. At most 50 per call.","in":"query","name":"tag","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter by a request tag (what a request sent in its `metadata`), as `key:value`. Repeatable: values for the same key match any of them, and different keys must all match. At most 50 per call.","title":"Tag"}},{"description":"Filter to one or more API key ids; repeatable (api_key_id=a&api_key_id=b). Several values match any of them. At most 50 per call.","in":"query","name":"api_key_id","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more API key ids; repeatable (api_key_id=a&api_key_id=b). Several values match any of them. At most 50 per call.","title":"Api Key Id"}},{"description":"Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.","in":"query","name":"priced","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.","title":"Priced"}},{"description":"Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, web_fetch, code_execution) matches that tool specifically.","in":"query","name":"tool","required":false,"schema":{"anyOf":[{"enum":["any","web_search","web_fetch","code_execution"],"type":"string"},{"type":"null"}],"description":"Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, web_fetch, code_execution) matches that tool specifically.","title":"Tool"}},{"description":"Filter by budget participation, which is not the same question as provenance: true = only enforced gateway rows, false = every row that never touches a budget, meaning imported usage and also gateway traffic on a budget-exempt key","in":"query","name":"counts_toward_budget","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by budget participation, which is not the same question as provenance: true = only enforced gateway rows, false = every row that never touches a budget, meaning imported usage and also gateway traffic on a budget-exempt key","title":"Counts Toward Budget"}},{"description":"Only usage recorded in this workspace.","in":"query","name":"workspace_id","required":false,"schema":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Only usage recorded in this workspace.","title":"Workspace Id"}},{"description":"Time-series granularity: 'hour' or 'day'","in":"query","name":"bucket","required":false,"schema":{"default":"day","description":"Time-series granularity: 'hour' or 'day'","enum":["hour","day"],"title":"Bucket","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageGroupedSeries"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Organization Usage Series","tags":["organization-usage"]}}}}
```

## Organization Usage Summary

> Aggregate spend, tokens and request volume for the caller's organization.\
> \
> The tenant-scoped counterpart of \`\`GET /api/v1/usage/summary\`\`, running the same\
> aggregation over a narrower row set: the same bounded window, the same\
> breakdowns, the same \`\`dimensions\`\` selector for paying only for the passes a\
> caller reads. The breakdown by user names the people inside the caller's own\
> scope, which is the roster they can already read.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"UsageSummary":{"description":"Aggregate spend/volume for the Usage & analytics page.\n\nEvery breakdown field is always present. One the caller excluded through\n``dimensions`` comes back as an empty list, the same shape a window with no\nmatching rows produces, so narrowing the selector never changes the schema.","properties":{"bucket":{"enum":["hour","day"],"title":"Bucket","type":"string"},"by_api_key":{"items":{"$ref":"#/components/schemas/UsageGroupRow"},"title":"By Api Key","type":"array"},"by_endpoint":{"items":{"$ref":"#/components/schemas/UsageGroupRow"},"title":"By Endpoint","type":"array"},"by_model":{"items":{"$ref":"#/components/schemas/UsageGroupRow"},"title":"By Model","type":"array"},"by_provider":{"items":{"$ref":"#/components/schemas/UsageGroupRow"},"title":"By Provider","type":"array"},"by_source":{"items":{"$ref":"#/components/schemas/UsageGroupRow"},"title":"By Source","type":"array"},"by_source_label":{"items":{"$ref":"#/components/schemas/UsageGroupRow"},"title":"By Source Label","type":"array"},"by_tag":{"default":[],"items":{"$ref":"#/components/schemas/UsageGroupRow"},"title":"By Tag","type":"array"},"by_tool":{"default":[],"items":{"$ref":"#/components/schemas/UsageToolRow"},"title":"By Tool","type":"array"},"by_user":{"items":{"$ref":"#/components/schemas/UsageGroupRow"},"title":"By User","type":"array"},"end_date":{"title":"End Date","type":"string"},"errors_by_status_code":{"items":{"$ref":"#/components/schemas/UsageErrorCodeRow"},"title":"Errors By Status Code","type":"array"},"series":{"items":{"$ref":"#/components/schemas/UsageSeriesPoint"},"title":"Series","type":"array"},"start_date":{"title":"Start Date","type":"string"},"totals":{"$ref":"#/components/schemas/UsageTotals"}},"required":["start_date","end_date","bucket","totals","by_model","by_user","by_api_key","by_source","by_source_label","by_endpoint","by_provider","errors_by_status_code","series"],"title":"UsageSummary","type":"object"},"UsageGroupRow":{"description":"One breakdown row (a model, a user, an API key, a session, ...).\n\n``key`` is None both for the synthesized fold row (``is_other=True``) and for a\nreal group whose column was NULL (e.g. usage from a since-deleted user, with\n``is_other=False``). ``is_other`` disambiguates the two so the UI does not\nmislabel deleted-user usage as the fold.","properties":{"cost":{"title":"Cost","type":"number"},"is_other":{"default":false,"title":"Is Other","type":"boolean"},"key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"requests":{"title":"Requests","type":"integer"},"tokens":{"title":"Tokens","type":"integer"}},"required":["key","cost","tokens","requests"],"title":"UsageGroupRow","type":"object"},"UsageToolRow":{"description":"Spend and volume for one gateway-run tool inside the window.\n\n``calls`` counts billable calls, not requests: one request can run a tool\nseveral times, which is the whole reason a per-tool view exists. ``errors``\ncounts calls that failed and were therefore never billed. ``requests`` is how\nmany requests ran the tool at least once, so the number reconciles with the\nActivity list when the same filter is applied there.","properties":{"calls":{"title":"Calls","type":"integer"},"cost":{"title":"Cost","type":"number"},"errors":{"title":"Errors","type":"integer"},"requests":{"title":"Requests","type":"integer"},"tool":{"title":"Tool","type":"string"}},"required":["tool","calls","errors","requests","cost"],"title":"UsageToolRow","type":"object"},"UsageErrorCodeRow":{"description":"One error-taxonomy row: the failures in the window sharing a status code.\n\n``status_code`` is None for failures recorded without one (rows written\nbefore the column existed, and failures no HTTP status describes, e.g. a\nstream that finished without usage data under the ``fail`` policy).\n``error_class`` is the coarse display bucket derived from the code, so a UI\ncan group \"provider fault\" against \"my own misconfiguration\" without\nre-deriving a status ladder; the raw code stays alongside it for precision.","properties":{"error_class":{"enum":["pricing","rate_limit","auth","provider_error","client_error","unknown"],"title":"Error Class","type":"string"},"requests":{"title":"Requests","type":"integer"},"status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status Code"}},"required":["status_code","error_class","requests"],"title":"UsageErrorCodeRow","type":"object"},"UsageSeriesPoint":{"description":"One time bucket. ``bucket_start`` is canonical ISO-8601 UTC (``...Z``),\nidentical across SQLite and PostgreSQL for the same underlying instant.\n\n``tokens`` stays the raw provider-reported total (the field predates the\ncomposition split and external consumers may read it). The billed\ncomposition fields are normalized via billing meters (see ``_billed_expr``):\n``input_tokens`` includes both cache buckets, so a chart derives fresh input\nas ``max(0, input_tokens - cache_read_tokens - cache_write_tokens)`` and the\nbilled total as ``fresh + cache_read + cache_write + output``.","properties":{"bucket_start":{"title":"Bucket Start","type":"string"},"cache_read_tokens":{"default":0,"title":"Cache Read Tokens","type":"integer"},"cache_write_tokens":{"default":0,"title":"Cache Write Tokens","type":"integer"},"cost":{"title":"Cost","type":"number"},"errors":{"default":0,"title":"Errors","type":"integer"},"input_tokens":{"default":0,"title":"Input Tokens","type":"integer"},"output_tokens":{"default":0,"title":"Output Tokens","type":"integer"},"requests":{"title":"Requests","type":"integer"},"tokens":{"title":"Tokens","type":"integer"}},"required":["bucket_start","cost","tokens","requests"],"title":"UsageSeriesPoint","type":"object"},"UsageTotals":{"description":"Grand totals over the filtered window.","properties":{"avg_latency_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Avg Latency Ms"},"billed_input_tokens":{"default":0,"title":"Billed Input Tokens","type":"integer"},"billed_output_tokens":{"default":0,"title":"Billed Output Tokens","type":"integer"},"cache_read_tokens":{"title":"Cache Read Tokens","type":"integer"},"cache_write_1h_tokens":{"title":"Cache Write 1H Tokens","type":"integer"},"cache_write_tokens":{"title":"Cache Write Tokens","type":"integer"},"completion_tokens":{"title":"Completion Tokens","type":"integer"},"cost":{"title":"Cost","type":"number"},"error_count":{"title":"Error Count","type":"integer"},"prompt_tokens":{"title":"Prompt Tokens","type":"integer"},"reasoning_tokens":{"default":0,"title":"Reasoning Tokens","type":"integer"},"request_count":{"title":"Request Count","type":"integer"},"total_tokens":{"title":"Total Tokens","type":"integer"},"unpriced_requests":{"default":0,"title":"Unpriced Requests","type":"integer"}},"required":["cost","prompt_tokens","completion_tokens","total_tokens","cache_read_tokens","cache_write_tokens","cache_write_1h_tokens","request_count","error_count","avg_latency_ms"],"title":"UsageTotals","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/organizations/me/usage/summary":{"get":{"description":"Aggregate spend, tokens and request volume for the caller's organization.\n\nThe tenant-scoped counterpart of ``GET /api/v1/usage/summary``, running the same\naggregation over a narrower row set: the same bounded window, the same\nbreakdowns, the same ``dimensions`` selector for paying only for the passes a\ncaller reads. The breakdown by user names the people inside the caller's own\nscope, which is the roster they can already read.","operationId":"organization-usage-organization_usage_summary","parameters":[{"description":"Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)","in":"query","name":"start_date","required":false,"schema":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)","title":"Start Date"}},{"description":"Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)","in":"query","name":"end_date","required":false,"schema":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)","title":"End Date"}},{"description":"Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.","in":"query","name":"user_id","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more users; repeatable (user_id=a&user_id=b). Several values match any of them. At most 50 per call.","title":"User Id"}},{"description":"Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)","in":"query","name":"status","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single status: 'success', 'error', or 'absorbed' (an attempt a routing policy recovered from, excluded from error_count and request_count)","title":"Status"}},{"description":"Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly","in":"query","name":"status_code","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Filter to a single failure status code (e.g. 429 for provider rate limits, 402 for missing-pricing rejections). Only error rows carry one, so this filter also restricts to status='error' unless 'status' is given explicitly","title":"Status Code"}},{"description":"Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.","in":"query","name":"model","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more models; repeatable (model=a&model=b). Several values match any of them. At most 50 per call.","title":"Model"}},{"description":"Filter to a single endpoint (e.g. '/v1/chat/completions')","in":"query","name":"endpoint","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single endpoint (e.g. '/v1/chat/completions')","title":"Endpoint"}},{"description":"Filter to a single provider (e.g. 'openai')","in":"query","name":"provider","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single provider (e.g. 'openai')","title":"Provider"}},{"description":"Filter to a single provenance source (e.g. 'gateway' or 'claude_code')","in":"query","name":"source","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single provenance source (e.g. 'gateway' or 'claude_code')","title":"Source"}},{"description":"Filter to a single session (source_label): the session's trace id on a gateway request that named one, or the session/project label imported usage carried","in":"query","name":"source_label","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single session (source_label): the session's trace id on a gateway request that named one, or the session/project label imported usage carried","title":"Source Label"}},{"description":"Filter by a request tag (what a request sent in its `metadata`), as `key:value`. Repeatable: values for the same key match any of them, and different keys must all match. At most 50 per call.","in":"query","name":"tag","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter by a request tag (what a request sent in its `metadata`), as `key:value`. Repeatable: values for the same key match any of them, and different keys must all match. At most 50 per call.","title":"Tag"}},{"description":"Filter to one or more API key ids; repeatable (api_key_id=a&api_key_id=b). Several values match any of them. At most 50 per call.","in":"query","name":"api_key_id","required":false,"schema":{"anyOf":[{"items":{"type":"string"},"maxItems":50,"type":"array"},{"type":"null"}],"description":"Filter to one or more API key ids; repeatable (api_key_id=a&api_key_id=b). Several values match any of them. At most 50 per call.","title":"Api Key Id"}},{"description":"Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.","in":"query","name":"priced","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by token-pricing state: true = only rows whose model tokens were priced, false = only rows that still need pricing (no cost at all, or tokens that were never metered because the model had no rate). A row charged only for gateway-run tool calls still counts as needing pricing.","title":"Priced"}},{"description":"Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, web_fetch, code_execution) matches that tool specifically.","in":"query","name":"tool","required":false,"schema":{"anyOf":[{"enum":["any","web_search","web_fetch","code_execution"],"type":"string"},{"type":"null"}],"description":"Filter to requests that ran a gateway-run tool. 'any' matches any tool; a tool name (web_search, web_fetch, code_execution) matches that tool specifically.","title":"Tool"}},{"description":"Filter by budget participation, which is not the same question as provenance: true = only enforced gateway rows, false = every row that never touches a budget, meaning imported usage and also gateway traffic on a budget-exempt key","in":"query","name":"counts_toward_budget","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by budget participation, which is not the same question as provenance: true = only enforced gateway rows, false = every row that never touches a budget, meaning imported usage and also gateway traffic on a budget-exempt key","title":"Counts Toward Budget"}},{"description":"Only usage recorded in this workspace.","in":"query","name":"workspace_id","required":false,"schema":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Only usage recorded in this workspace.","title":"Workspace Id"}},{"description":"Time-series granularity: 'hour' or 'day'","in":"query","name":"bucket","required":false,"schema":{"default":"day","description":"Time-series granularity: 'hour' or 'day'","enum":["hour","day"],"title":"Bucket","type":"string"}},{"description":"Which breakdowns to compute; repeatable (dimensions=model&dimensions=user). Each value names the 'by_<value>' response field it fills, except 'status_code', which fills the failure taxonomy in 'errors_by_status_code'. Omit for every breakdown (the default); pass 'none' for a totals-and-series-only response. Each dimension left out skips one GROUP BY scan, so a caller that reads only the tiles or the time series should say so. Fields that were not requested come back empty.","in":"query","name":"dimensions","required":false,"schema":{"anyOf":[{"items":{"enum":["model","user","api_key","source","source_label","endpoint","provider","status_code","tool","none"],"type":"string"},"type":"array"},{"type":"null"}],"description":"Which breakdowns to compute; repeatable (dimensions=model&dimensions=user). Each value names the 'by_<value>' response field it fills, except 'status_code', which fills the failure taxonomy in 'errors_by_status_code'. Omit for every breakdown (the default); pass 'none' for a totals-and-series-only response. Each dimension left out skips one GROUP BY scan, so a caller that reads only the tiles or the time series should say so. Fields that were not requested come back empty.","title":"Dimensions"}},{"description":"A tag key to break spend down by, returned as `by_tag`. Rows that do not carry the tag group under a null key.","in":"query","name":"group_by_tag","required":false,"schema":{"anyOf":[{"maxLength":64,"minLength":1,"type":"string"},{"type":"null"}],"description":"A tag key to break spend down by, returned as `by_tag`. Rows that do not carry the tag group under a null key.","title":"Group By Tag"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Organization Usage Summary","tags":["organization-usage"]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.otari.ai/otari/for-integrators/api-reference/organization-usage.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
