Organization Usage & Costs API¶
Report what this deployment consumed and what it cost, in time buckets, through the OpenAI Administration Usage and Costs API.
At a glance¶
- Eleven endpoints — ten
/v1/organization/usage/*families reporting tokens, characters, seconds of audio, images and tool calls, plus/v1/organization/costsfor what AWS bills — see Endpoints. - Grouped by model, source, tenant API key or user — the keys that are served, and the ones refused with an explanation, are listed under Grouping.
-
1mbuckets for 15 days,1hand1dfor 455 — a query past the boundary is refused rather than answered at a coarser resolution, see Bucket width. - Off by default — the surface is served only when
usage_apiis enabled.
from openai import OpenAI
client = OpenAI(base_url="https://your-gateway/v1", api_key="...")
page = client.admin.organization.usage.completions.list(
start_time=1756000000, bucket_width="1d", limit=7, group_by=["model"]
)
for bucket in page.data:
for result in bucket.results:
print(bucket.start_time, result.model, result.input_tokens)
Administrator endpoints, disabled by default
These endpoints report the whole deployment, not the calling client, and every query is billed by Amazon CloudWatch. They are served only when usage_api is enabled, and only to administrator credentials — see Who may call it.
Endpoints¶
| Endpoint | Reports |
|---|---|
GET /v1/organization/usage/completions | Input, output and cached tokens of chat, responses, text completion, messages and realtime requests |
GET /v1/organization/usage/embeddings | Input tokens of embeddings requests |
GET /v1/organization/usage/moderations | Input tokens of moderation requests |
GET /v1/organization/usage/images | Images produced by generation, edit and variation requests |
GET /v1/organization/usage/audio_speeches | Characters synthesized |
GET /v1/organization/usage/audio_transcriptions | Seconds of audio transcribed or translated |
GET /v1/organization/usage/web_search_calls | Searches run by the built-in web search tool |
GET /v1/organization/usage/file_search_calls | Vector store searches run |
GET /v1/organization/usage/vector_stores | Nothing: vector store storage is not measured |
GET /v1/organization/usage/code_interpreter_sessions | Nothing: no code interpreter is served |
GET /v1/organization/costs | What AWS bills this deployment for serving the requests |
The two endpoints that report nothing answer a well-formed page of empty buckets rather than a 404: the endpoint exists, and no measurement was taken.
GET /v1/usage is not served
The retired top-level usage endpoint is absent from OpenAI's current API surface and from the openai package, so there is no shape to mirror. Use the /v1/organization/usage/* family above.
Enabling the surface¶
| Setting | Needed for |
|---|---|
cloudwatch_metrics | Publishing the usage the endpoints read back. Nothing is reported for the period before it was enabled. |
usage_api | Serving the endpoints at all, and publishing usage per endpoint. |
cost_tracking | /v1/organization/costs only. |
With usage_api disabled every endpoint answers 503. Enabling usage_api without cloudwatch_metrics fails at startup instead, rather than serving endpoints that could never answer — the server log names the missing setting.
The server role needs cloudwatch:GetMetricData and cloudwatch:ListMetrics — see Usage API IAM permissions — and the queries are billed per metric read, which Usage API query cost puts a number on.
Query parameters¶
Every endpoint takes:
| Parameter | Default | Notes |
|---|---|---|
start_time | — | Required. Unix seconds, inclusive. |
end_time | now | Unix seconds, exclusive. |
bucket_width | 1d | 1m, 1h or 1d. /v1/organization/costs accepts 1d only. |
limit | 7 (1d), 24 (1h), 60 (1m) | Buckets per page. Maximum 31, 168 and 1440 respectively; 180 on /v1/organization/costs. |
page | — | Cursor from the next_page of a previous response. |
group_by | — | See Grouping. |
models | — | Report only these models. Not on /v1/organization/costs or file_search_calls. |
user_ids, api_key_ids | — | Report only these callers. Accepted only where that identity is recorded — see Grouping. |
Buckets are aligned to the UTC grid of the requested width, so start_time is rounded down to a bucket boundary and the reported start_time of the first bucket may be earlier than the one asked for.
/v1/organization/usage/images additionally takes sources (image.generation, image.edit, image.variation).
Grouping¶
group_by | Served |
|---|---|
model | On every model-backed endpoint. |
source | On images. |
api_key_id | When tenant API keys are issued. Otherwise refused: the deployment has one key, which identifies itself rather than a caller. |
user_id | When cloudwatch_metrics_user_dimension is enabled. Otherwise refused: consumption is not recorded per user by default, because that is one stored metric series per user. |
project_id | There are no projects here, so usage is never attributed to one. |
batch | Batch API usage is not reported by these endpoints at all — see Limits and behaviour to know. |
service_tier | The service tier a request ran under is not reported apart. |
size | The size of a generated image is not reported. |
context_level | The context size of a web search is not reported. |
vector_store_id | File searches are not reported per vector store. |
line_item | Costs are not reported per product line item. |
A refused key answers 400 naming the key and the reason. A refused key is never silently ignored: the grouping is the request.
api_key_id and user_id may each be combined with model, but not with each other: usage is reported per key or per user, never per pair of the two. The same holds for the api_key_ids and user_ids filters, and for one of them combined with a grouping by the other.
A key that was not grouped by is omitted from the JSON object rather than sent as an explicit null. The openai SDK reads it back as None either way, so only a client parsing the raw JSON sees the difference — read such a key with result.get("model"), never result["model"].
Bucket width and how far back¶
Narrow buckets are only kept for so long:
bucket_width | Reported for |
|---|---|
1m | The last 15 days |
1h | The last 455 days |
1d | The last 455 days |
A query past the boundary is refused with 400 naming the limit, rather than answered at a coarser resolution than it asked for — a usage report that silently changes resolution mid-range is a number that ends up in a spreadsheet. Ask for a later start_time, or a wider bucket_width.
The span between start_time and end_time is additionally bounded by usage_api_max_range_days, 92 days by default.
A model idle for two weeks stops being reported
The endpoints find the series to read through CloudWatch's metric index, which only carries what reported data in the last 14 days. A model, endpoint, tenant key or user that has served nothing for a fortnight is therefore missing from every bucket of the answer, however recent the range asked for — and so is its spend on /v1/organization/costs. Retire a model and its history stops being reported two weeks later; the same holds for a user or a tenant that went quiet.
This bounds the surface to reporting on what a deployment is currently serving. Where a permanent record is needed, keep the request logs, which are written per request and retained for as long as their log group is.
Costs¶
/v1/organization/costs reports the cost of the work in daily buckets, one result per currency:
{
"object": "bucket",
"start_time": 1756000000,
"end_time": 1756086400,
"results": [
{
"object": "organization.costs.result",
"amount": {"value": 1.42, "currency": "usd"}
}
]
}
This is the AWS bill, not an invoice to your clients
amount is what AWS charges this deployment's account for serving the requests. It is not what a reseller charges its own customers, and it carries no margin.
Amounts are never summed across currencies: a deployment spanning partitions reports one result per currency.
Who may call it¶
| Credential | Accepted |
|---|---|
| The deployment's own API key | It is the operator's own credential. |
| An Amazon Cognito token | Only when it carries every scope in usage_api_admin_scopes. With that list empty, no token is accepted. |
| A tenant API key | A per-customer credential is never an administrator credential. |
Anything else answers 403. Upstream gates the same endpoints on a separate administrator credential; this is the closest equivalent a deployment can express.
Limits and behaviour to know¶
Where this surface answers differently from the upstream Administration API:
- Only the grouping keys and filters in Grouping are served; the rest are refused with an explanation rather than ignored.
completionsreportsinput_tokens,output_tokens,input_cached_tokens,input_cache_write_tokens,input_uncached_tokensandnum_model_requests.input_tokenscovers the whole prompt, cached and cache-write tokens included, so it reconciles with theprompt_tokensthe same requests returned. The text/audio/image token breakdown upstream also publishes is not reported.num_model_requestscounts only the records carrying the endpoint's own measurement. A guardrail applied around the call, the built-in web search, a managed knowledge base retrieval and the translation behind an audio translation are each billed apart and recorded under the operation of the request they served, so they reach neither the count nor thegroup_by=modelrows of the endpoint that request went to.moderationsreportsnum_model_requestsfor every moderation, andinput_tokensonly for the ones a language model answered: a guardrail and Amazon Comprehend are moderating backends here rather than a filter around another call, so their records are counted — and a moderation answered by an Amazon Bedrock guardrail counts once per policy that guardrail applies.web_search_callsreportsnum_requestsandnum_model_requests;context_levelis never reported.num_model_requestscounts every request the model answered in the bucket, not only the ones that called the search tool, whenever the two shared the same model, operation and grouping in that bucket: the search count is recorded on the model's own usage record, so a bucket mixing searching and non-searching traffic to the same model cannot be told apart from the metrics alone.file_search_callscounts searches for the deployment as a whole;vector_store_idis never reported.- Batch API usage is absent from the usage endpoints. A batch's tokens are recorded against the route that collected its results, which carries no reported endpoint, so they reach neither
completionsnorembeddings— yet their spend is included in/v1/organization/costs. On a deployment running significant batch traffic, usage and costs therefore do not reconcile, by the whole batch workload. - Usage is reported from a single region — see
cloudwatch_metrics_region. A deployment publishing from more than one region reports the one it reads. next_pageis this server's own cursor and is only meaningful to it.
How far back a bucket width is answered, and the two-week metric index behind every answer, are covered in Bucket width and how far back.
Try it¶
Report the last seven days of token usage per model, with administrator credentials:
curl -G "https://your-gateway/v1/organization/usage/completions" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d start_time=1756000000 \
-d bucket_width=1d \
-d limit=7 \
-d group_by=model
Next steps¶
Next: Configuration · Cost Management · Logging & Monitoring · IAM Permissions