The OpenAI Usage API, with working examples
Last verified
Usage answers "how many tokens", Costs answers "how many dollars". If you're chasing a budget, use Costs. If you're chasing a bloated prompt, use Usage.
Both require an admin key.
export OPENAI_ADMIN_KEY="sk-admin-..."
START=$(python3 -c 'import time; print(int(time.time()) - 7*86400)')
curl -s "https://api.openai.com/v1/organization/usage/completions?start_time=$START&bucket_width=1d&limit=7" \
-H "Authorization: Bearer $OPENAI_ADMIN_KEY" | jq
What you can slice by
The useful part is the grouping. Usage can be broken down by:
- model — which model is consuming the tokens
- project_id — which project
- api_key_id — which key, and therefore which service
- user_id — which member, in a team
curl -s "https://api.openai.com/v1/organization/usage/completions?start_time=$START&bucket_width=1d&group_by=model&limit=7" \
-H "Authorization: Bearer $OPENAI_ADMIN_KEY" | jq
bucket_width accepts finer granularity than the Costs endpoint — minute, hour or day — which is what makes Usage the better tool for narrowing down _when_ something went wrong.
What it is good for
Finding the expensive model. Group by model, sort by total tokens, and compare against what you believe your app calls. Mismatches are either a bug or someone else using your key.
Splitting input from output. Output tokens typically cost several times more than input. A prompt that looks fine on token count can be dominated by generation cost, and the two are reported separately.
Catching the invisible tokens. Reasoning tokens are billed as output but never appear in the response body you read. If a bill is inexplicable relative to the text you got back, this is usually why.
Attribution without a proxy. Group by api_key_id, run one key per service, and you get per-service usage attribution with no code changes and nothing in your request path.
What it is not good for
- Real-time anything. Recent usage takes time to land. See why billing APIs are daily.
- Per-request detail. There is no request log. You get aggregates, not individual calls. If you need per-request cost, that requires a proxy — proxy vs billing API.
- Prompt content. Providers do not hand back what was sent.
A daily export script
The most common actually-useful thing to build with it:
#!/usr/bin/env bash
set -euo pipefail
START=$(python3 -c 'import time; print(int(time.time()) - 86400)')
curl -s "https://api.openai.com/v1/organization/usage/completions?start_time=$START&bucket_width=1d&group_by=model" \
-H "Authorization: Bearer $OPENAI_ADMIN_KEY" \
| jq -r '.data[].results[] | [.model, .input_tokens, .output_tokens] | @tsv'
Pipe it into a spreadsheet, a Slack message, or whatever your team reads. Verify the exact field names against a live response first — they have changed between API revisions, and any guide that tells you otherwise (including this one) can go stale.