Usage: the shape of your spending
Usage reads one window at a time. The ranges are 24 hours, 7 days, 30 days, 90 days and 1 year, and it shows:- Totals for the window: requests, how many were served, how many were not, token counts including reasoning and cache reads and writes, and the cost summed from the per request charges.
- The same window immediately before it, so a total can be read as a change rather than as a number on its own.
- A series bucketed by hour on the 24 hour window and by day on the longer ones. A bucket with no requests carries a zero rather than being missing, so a gap in the chart never has to be interpreted.
- Breakdowns by model, by provider, by key and by member.
- Your balance, read from the one component allowed to compute it, beside the summed cost rather than derived from it.
Breakdowns by key and by member are scoped to what you may see. An owner or admin
sees every line. Everybody else sees the keys they are accountable for or named on,
plus their own row. Totals, buckets, models and providers are whole for every
member.
Activity: one row per request
Activity lists requests newest first, 25 to a page unless you choose 50 or 100, with the request id linking to the single request lookup. Each row carries when it ran, which door it came through (api or playground), the model, which provider answered, the outcome, the token
counts, what it cost as dollars and how long it took.
Paging is stable: rows are ordered by time with the request id as the tiebreak, so a
row cannot swap sides of a page boundary between two reads and appear twice or not at
all.
Filters
The filter panel narrows by model, by outcome and by date range, and the controls compose: all of them narrow the same list. It is a plain form, so a filtered view is an address you can bookmark or send to a colleague, and shortcuts for the last day, week and month write the date fields for you. The model list offered by the panel is the models this workspace has actually called, not a catalogue, and a model that has been renamed appears once: choosing it still matches the rows recorded under the name it used to have. Outcome narrows to one of four choices rather than to a code: any outcome, served, provider error, refused.Three ways to see no rows
They mean different things and the screen says which:- Nothing has ever run here. The workspace is new.
- The filter matched nothing. Rows exist and this narrowing excluded them. The table keeps its shape and offers a control to clear the filter.
- The range reaches past what we keep. It was never going to answer, so the screen names the retention window instead of inviting a narrower filter.
Reading a row
unknown is not zero. On the outcomes where a charge exists and final token
counts never arrived, the count reads unknown. A real charge printed beside two
zeros is the reading that files a billing bug, so a count nobody measured is never
rendered as a measurement.
A refusal shows a cost of zero. That is the point: turned away, charged nothing.
No prompt, no reply. Neither is stored anywhere, so neither is on the row and
neither can be recovered later. The single request view says so in as many words.
Look up one request
Every response carriesx-uniblock-request-id, and every error envelope carries the
same value as request_id. Paste it into the request id field in Activity, or open
the row from the list, to get the single request view: the same fields as the row,
plus the note that nothing else about the request was ever stored.
One answer covers both ways to miss: a request id from another workspace and a
request id that never existed both simply find nothing. That is by construction
rather than by policy, so the lookup cannot be used to learn whether an id exists
somewhere else.
A request that has passed the 90 day retention window is answered by naming the
window rather than by an empty row. The money movement for that request is still on
your statement.
Reconcile a statement line with a request
Ausage line on your statement carries our request id as its cause. That is the
join:
1
Take the request id from the statement line
Every charge line names one.
2
Look it up in Activity
The single request view shows the model, the outcome, the token counts and the
cost for that exact request.
3
Compare the figures
The charge on the usage record and the amount on the ledger line are the same
money, matched by request id with no tolerance for a difference. If they do not
agree, that is a defect on our side rather than something for you to reconcile.
Quote the request id.
- A charge with an explanation. Some lines carry a sentence saying the counts were not confirmed, that the provider reported none, or that the hold had already expired when the charge settled.
- A served request with no cost figure. Where token counts never reached us, the request is settled against its hold and the usage row cannot yet say for how much. The totals name how many such requests fall in the window, so the cost totals read as incomplete rather than as complete. Your statement carries the real movement.
Next
View activity
A closer walkthrough of the Activity list: paging, filtering and looking up
one request.
Usage and metering
The full field set, the outcome vocabulary and the retention rules.
Credits and billing
Statement lines, purchase annotations and the running ledger total.
Every response carries the same id on two headers:
x-uniblock-request-id,
which is ours, and x-request-id, which is the one the official OpenAI SDKs
surface on their error objects. Every error envelope repeats it as
request_id. Quote it when you ask us about a request. Without it we are
guessing at which of your requests you mean.