An OpenAI bill hides its cost in four specific places.
This is the OpenAI-specific half of a cost audit. The generic advice — use a cheaper model, cache more — is worth roughly nothing until you know which of these four is actually driving your invoice.
1. Attribution stops at the project boundary
OpenAI's attribution unit is the project. Keys belong to projects, and the Costs and Usage endpoints under the organization admin API bucket spend by project and by model. That is the whole granularity you get from the platform.
If your teams share one project, or one key, the invoice is a single number and no amount of dashboard work will split it. The fix is boring and it is the first thing we do: one project per workload or per owning team, keys reissued accordingly, then the Costs API pulled on a schedule into whatever your finance team already reads. Anything finer than the project boundary — per customer, per feature, per endpoint — has to come from your own logging, because the platform does not carry it.
2. Cached input is either 50-90% off or nothing
Prompt caching applies automatically above a minimum prefix length and discounts the cached portion sharply, but only when the prefix is byte-identical and reused inside the cache window. Two habits destroy it: putting a timestamp, session id or retrieved chunk near the top of the prompt, and rotating system prompt variants per request.
Cached input tokens are reported separately, which makes the audit test trivial: pull the ratio of cached to uncached input tokens per workload. A high-volume workload with a stable system prompt and a near-zero cache ratio is usually the single largest recoverable line on an OpenAI bill, and the fix is prompt reordering rather than a migration.
3. Reasoning tokens bill as output and never appear in the response
On the reasoning models, tokens spent thinking are billed at the output rate and are not in the text you received. A team measuring cost per response length will read the invoice as inexplicable, because the expensive part is invisible by design.
The audit checks the reasoning token count per workload against the reasoning effort setting, because most workloads are running a higher effort than the task needs. Classification, extraction and routing rarely justify extended reasoning, and dropping the effort level on those is usually a same-day change with a measurable before and after.
4. The Batch tier is unused on work that is already asynchronous
Batch runs at roughly half price with a 24-hour completion window. The audit looks for workloads already tolerating minutes or hours of latency — nightly enrichment, backfills, evaluation runs, document processing queues — and still being sent through the synchronous endpoint because that is what the first prototype used.
This one is pure arithmetic. Either the workload has a documented latency requirement or it does not, and if it does not, half the cost is available for a queue change.
What the audit needs from you
- Organization-level read access, or an export from the Costs endpoint for the last 90 days.
- The list of projects and roughly what each one serves.
- For your top two or three workloads: a representative request, including the system prompt.
- Your latency requirements, if they are written down anywhere.
It takes about a week and ends in a written document with a ranked savings list and an effort cost against each item. It is free, it is not a slide deck, and you can implement all of it without us.