Every AI cost dashboard starts the same way: take the token counts the provider returned, multiply by a price, add them up. The token counts are the provider's own and are usually right. The price is where estimates go wrong, because "the price" of a model is not one number. It depends on who you are, how the request ran, where it ran and when.
This guide lists the sources of drift between a list-price estimate and what your provider bills, and how to close each one.
List price is a default, not your price
The vendor's list rate is the right starting point: it is public, dated and the same for everyone. It is also, for many organizations, not the rate they pay. Anthropic says volume pricing is available to high-volume users and are negotiated case by case, alongside custom enterprise terms1. Committed-spend agreements trade a spend commitment for a lower effective rate. Neither appears on a public price page, so no estimate built from public data can know about them.
An estimate that ignores a negotiated rate is not slightly wrong in a random direction. It is wrong by the same factor every day, which is exactly what makes it detectable: a steady ratio between reported cost and estimate. See reconciling estimated spend with provider invoices for the mechanics.
One model, many published rates
Even at list price, a single model has several rates, chosen per request by options the request sets or the account defaults to. Anthropic's page for Claude Opus 5.5 alone publishes:
- $4 per 1M input tokens standard, $20 output1;
- $2 input and $10 output through the Batch API, half of standard;
- $5 for a five-minute cache write and $8 for a one-hour write, $0.20 for a cache read;
- $8 input and $40 output in fast mode, a research preview on the Claude API only;
- a 1.1x multiplier on every token category for US-only inference via
inference_geo1.
On Bedrock and Google Cloud, regional and multi-region endpoints carry a 10% premium over global endpoints for Claude Sonnet 4.5, Haiku 4.5, Opus 4.5 and later models1. These multipliers stack: a cache read inside a batch request, or a US-only fast-mode request, is a product of several factors.
USD per 1M input tokens
- Cache read$0.20
- Batch$2.00
- Standard (list)$4.00
- US-only inference1.1x multiplier$4.40
- 5-minute cache write$5.00
- Fast mode$8.00
- 1-hour cache write$8.00
OpenAI's pricing page is shaped the same way. Each GPT-6 model has Standard, Batch, Flex and Fast mode rows, and each row has a short-context and a long-context column: GPT-6 Sol is $2.00 input and $10.00 output standard at short context, $4.00 and $15.00 at long context, $1.00 and $5.00 on Batch or Flex, and $4.00 and $20.00 in fast mode2.
Prices that depend on the prompt or the clock
Some rates change with the request itself:
- Long-context tiers. Gemini 3.1 Pro bills $2.00 input and $12.00 output per 1M tokens for prompts up to 200k tokens, and $4.00 and $18.00 above3. OpenAI publishes a separate long-context column, with higher input and output rates, for each GPT-6 model2. An estimate carrying one pair of rates reads low on every long prompt.
- Time of day. DeepSeek bills off-peak hours at half the peak rate; peak is 01:00–04:00 and 06:00–10:00 UTC on weekdays, excluding Chinese public holidays4. An estimate at the peak rate reads high for off-peak traffic, which is the safer direction to be wrong.
- Scheduled changes. Gemini 3.8 Flash is $0.75 input and $3.75 output per 1M tokens through 2026-12-31, and $1.50 and $7.50 from 2027-01-013. That change is already published; an estimate that does not carry an effective date will be wrong on New Year's Day. Changes also go the other way: Claude Sonnet 5's $2 and $10 introductory rate became its standard price, and a scheduled increase did not happen1.
A related trap is not a rate at all. Anthropic notes that Claude 4.7 and later models use a tokenizer that produces roughly 30% more tokens for the same text1. Per-request estimates use the provider's reported token counts, so they stay right; forecasts that convert characters or words into tokens with an old ratio do not.
| Source of drift | Moves the estimate | Visible per request? | Fix |
|---|---|---|---|
| Negotiated or committed rate | Estimate reads high | ○No | Enter the contract rate |
| Vendor list price change | Either way | ○No | Update the rate table with its date |
| Long-context tier | Estimate reads low | ◐Prompt length is | Model the tier, or flag long prompts |
| Batch, flex, priority, fast mode | Either way | ◐Only if the tier is recorded | Price by tier, or keep off the gateway path |
| Regional or residency premium | Estimate reads low | ◐Endpoint choice is | Enter the regional rate |
| Peak and off-peak pricing | Estimate reads high off-peak | ●Time of request | Accept a conservative estimate, or price by hour |
Record which rate priced each request
The single most useful field in a cost record is not the cost; it is where the rate came from. With it, a finance analyst can split a variance into "requests priced at list" and "requests priced at our contract" and see immediately which half is off. Without it, every discrepancy is an investigation.
A practical record carries, per request: the model and provider account that served it, the token counts by class (uncached input, cached input, cache write, output), the rate applied to each class, the source of the rate (contract, list, provider-reported) and the rate's effective date.
Inferring an effective rate
When you do not know your contract rate, or suspect the one on file is stale, derive it from the provider's own reported cost.
from decimal import Decimal
def effective_rate_per_mtok(reported_usd: Decimal, tokens: int) -> Decimal:
"""What the provider actually charged per 1M tokens of one class, over a window."""
if tokens <= 0:
raise ValueError("no tokens in window")
return reported_usd / Decimal(tokens) * Decimal(1_000_000)
def factor_vs_list(effective: Decimal, list_rate: Decimal) -> Decimal:
return (effective / list_rate).quantize(Decimal("0.001"))Do this per model and per token class, not for a provider's total. Anthropic's cost report can be grouped by description, which itemises each line by model, token_type, service_tier and context_window5; exclude batch and long-context lines before inferring a standard rate, or you will blend two prices into one that matches neither.
Three rules for applying an inferred rate:
- Scope it to the provider that billed it. The same model on another provider or cloud is a different contract.
- Apply it forward. Re-pricing recorded requests rewrites reports people have already used.
- Keep the evidence. The window, the token counts, the reported cost and who applied it.
Keep a rate history, not a rate
A rate table that stores only the current price for each model cannot explain last quarter. When finance asks why March's estimate was off, the answer depends on which rate was in force in March, and on whether the request records were priced with it.
Treat rates as dated records: model, provider, token class, rate, effective from, effective until, and the evidence for it (a contract clause, a vendor price page and its date, or an inferred rate with its window). Price each request with the rate in force when it ran, and store that rate on the request rather than looking it up later. Then a rate correction is a new record with a new effective date, and every report that already went out stays reproducible.
The same discipline applies to published list prices. Vendors change them in both directions, sometimes on a schedule announced months ahead, sometimes with little notice. A dated list-price record with its source URL is what lets you tell "the vendor changed the price on the 14th" from "our estimate has been wrong since the 14th".
A drift checklist
- Contract rates recorded per model, provider and token class, with effective dates and the clause they come from.
- Every request records the rate that priced it and where that rate came from.
- Batch, flex, fast and priority traffic priced at its own tier, or kept on a separate account so it can be excluded.
- Long-context and regional pricing modelled, or those requests flagged as estimated at a lower bound.
- Scheduled vendor price changes entered before their effective date.
- Estimates compared with reported cost weekly, and inferred rates applied forward only.
Negotiated rates in INFRO
INFRO estimates what your provider will bill you; it does not bill model usage and takes no part of it. Each request is priced at the first rate available in this order, and the response's usage.price_source says which: provider when the provider returned its own cost, custom_provider for a rate you entered for that model on that provider kind, custom for a rate you entered for the model on any provider, and list for the vendor's published rate. With none of these the request is unpriced, never $0. See chat completions.
1 · provider
Provider-reported cost
The provider returned its own cost in the response; no rate is applied.
2 · custom_provider
Your rate for this provider
A contract rate you entered for this model on this provider kind.
3 · custom
Your rate for the model
A rate you entered for the model on any provider.
4 · list
Vendor list rate
The model vendor's published rate. Without one, the request is unpriced, never $0.
Negotiated rates are entered in the console, per model and optionally per provider, from the Team plan. An override replaces the list rate field by field: set input and output and leave cached input empty, and cached input keeps the list rate. On the Business plan, reconciliation compares estimates against OpenAI's and Anthropic's reported cost and suggests a rate when the ratio holds within 5% over at least 10 days; applying it writes a rate for that model and provider kind, recorded in the audit log, and prices only future requests. If your contract includes a spend commitment, commitments track it against reported cost and forecast where it will end, without moving traffic on their own.
