The two endpoints and the admin key
Both endpoints live at the organization level and reject normal project keys. Create an Admin API key in the OpenAI platform under organization settings, then:
# token usage, grouped by model, daily buckets
curl "https://api.openai.com/v1/organization/usage/completions?\
start_time=1754006400&bucket_width=1d&group_by=model" \
-H "Authorization: Bearer $OPENAI_ADMIN_KEY"
# billed dollars per day
curl "https://api.openai.com/v1/organization/costs?\
start_time=1754006400&bucket_width=1d" \
-H "Authorization: Bearer $OPENAI_ADMIN_KEY"Usage buckets go down to the minute and group by project, API key, model, and the optional user field. Costs currently buckets by day only. Full parameters are in OpenAI’s Usage API cookbook. Timestamps are Unix seconds.
Every parameter, and the endpoint that does not exist
Both endpoints take start_time as required Unix seconds. Everything else is optional, and the defaults are the reason most first attempts come back looking empty or useless:
bucket_width:1m,1hor1don usage, default1d. The costs endpoint supports1donly, which is why you cannot chart billed dollars by hour.group_by: on usage, the same dimensions you can filter by, somodel,project_id,user_id,api_key_idandbatch. On costs, the useful pair isline_itemandproject_id. Technically optional, practically mandatory: leave it off and the grouped fields come back null, which is the single most common reason a first call looks broken.- Filters, all lists:
project_ids,user_ids,api_key_ids,models, plus the booleanbatchto separate batch from interactive traffic. limitcaps the number of buckets returned andpagetakes the cursor from the previous response. A month of hourly buckets is over 700 rows, so paginate rather than raising the limit and hoping.end_timeis optional. Omit it and you get everything up to now, which makes month-boundary reports quietly wrong if you are diffing two runs.
One thing worth stating plainly, because it is the most searched request that has no answer: there is no supported endpoint that returns your remaining credit balance. People look for GET /v1/organization/billing/balance; it is not part of the Admin API, and an admin key against it returns an error rather than a number. The old /v1/dashboard/billing/credit_grants path is undocumented, unsupported and tied to the legacy dashboard, so treat anything built on it as temporary. What exists today is spend, not balance: the costs endpoint tells you what you have burned, and you track the rest against your own ceiling. See the standing request for balance access and OpenAI’s Admin API guide for the current surface.
What these endpoints answer well
- Which model the money goes to, per day: the model mix question that explains most bill surprises.
- Which project or key spent what, if you split keys per service or environment.
- Token counts per user field value, if you already pass a user id on every request.
- Invoice reconciliation: the costs endpoint is what finance closes the month against.
A useful monthly ritual: multiply the usage endpoint’s token counts by current prices from the LLM pricing JSON feed and compare against the costs endpoint. A persistent gap means unattributed traffic or a stale price table, and both are worth finding.
The gap: tokens per user is not margin per user
Even with the userfield on every call, the Usage API hands you token counts per user, not dollars, and never margin. Turning that into “is this customer profitable” requires three things the endpoints do not have: current per model prices applied per request, your feature context, and what each user pays you. The moment you want the question answered continuously, with per user spending caps enforced before the call rather than reported after the day closes, you are building the request time layer described in OpenAI cost per user.
That layer is what Weckr ships as two lines around your existing client: every call logged with user, feature, recomputed cost, and margin against the user’s plan, with caps that block or downgrade runaways in real time. The Usage API then becomes your monthly cross check instead of your only view.
FAQ
How do I get OpenAI usage and cost data programmatically?
Use the organization endpoints: /v1/organization/usage/completions returns token usage over time, and /v1/organization/costs returns daily spend in USD. Both require an Admin API key created at platform.openai.com under organization settings, a regular sk- project key is not enough. Usage can be bucketed by minute, hour, or day; the costs endpoint currently buckets by day only.
Can the OpenAI Usage API break down cost by end user?
Only partially, and only in tokens. The usage endpoint can group by project, API key, model, and the optional user field you pass on requests, so if you send a user id on every call you can see token counts per user. The costs endpoint does not go to that grain, and neither endpoint knows what a user pays you, so per user dollar cost and margin still have to be computed in your own stack.
What is the difference between the OpenAI Usage API and the Costs API?
Usage counts tokens and requests with flexible grouping and time buckets down to the minute. Costs reports billed dollars per day, the number that reconciles with your invoice. Token counts times your own price table should approximate the costs endpoint, and a persistent gap usually means unattributed traffic or a stale price table.
Is there an OpenAI API endpoint for my remaining credit balance?
No. There is no supported balance endpoint in the Admin API. GET /v1/organization/billing/balance is frequently searched for but is not part of the API, and an admin key against it returns an error rather than a balance. The legacy /v1/dashboard/billing/credit_grants path is undocumented and unsupported. What you can get today is spend: /v1/organization/costs returns billed dollars per day, and you compare that against a ceiling you define yourself.
Why does group_by return null values in the OpenAI usage response?
Because group_by is optional and defaults to nothing. Without it the response still returns buckets, but the grouped fields such as model and project_id come back null, which makes the first call look broken. Pass group_by explicitly, for example group_by=model or group_by=project_id, on essentially every real query. On the costs endpoint the useful values are line_item and project_id.
How fresh is the OpenAI cost data?
It is reporting data, not a live meter. Daily cost buckets settle after the day closes, which is fine for finance and useless for catching a runaway user mid burst. Real time control, per user caps, loop detection, blocking before the call, has to happen at request time in your own request path.
Should I build my dashboard on the Usage API or track per request?
Both, for different jobs. The Usage and Costs APIs are the authoritative record of what OpenAI bills your organization, ideal for monthly reconciliation. Per request tracking in your app is the only place user identity, feature, and plan price exist together, which is what answers whether a customer is profitable. Weckr does the per request half in two lines and you can cross check it monthly against the costs endpoint.
Keep reading
Reporting tells you what happened. Weckr tells you who.
Wire the two line integration, keep the Usage API as your auditor, and the unprofitable accounts stop hiding in daily buckets. See the per user view on the live demo, free for 50,000 requests a month, or start with the AI cost and margin guide.
Two follow ons if you are wiring this up today: OpenAI budget alerts for the account level warning the API will not send you, and streaming LLM cost gotchas if any of your calls stream, because that is where token counts most often go missing.
