Claude Sonnet 5 and GPT-6 Sol have the same price sheet, to the cent: $2.00 per million input tokens, $0.20 for a cache read, $2.50 for a cache write, $10.00 for output. Send each of them the same agent turn — 150,000 tokens of context, 140,000 of them already in the cache, 8,000 newly written, 3,000 tokens out — and each bills $0.082.
Now take the four-line cost function you wrote against one vendor’s SDK and point it at the other vendor’s response. The same turn costs $0.378. Point it the other way and it costs −$0.214.
Nothing in either response is wrong. Both usage objects are accurate and documented. The two vendors simply use the same field name, input_tokens, for two different numbers, and a cost function only ever knows one of them.
This is the reference we wanted and could not find in one place: every field that decides the bill at OpenAI, Anthropic and Google, what each one includes, what it quietly leaves out, the organization-level Usage and Costs APIs, and a function that prices a response correctly. We tested the function against every worked number in this article before publishing it.
input_tokens is three different numbers
Here is what each API puts in its input and output fields. The column that matters is the second one.
| API | Input field | Includes cache reads? | Includes cache writes? | Output field | Includes reasoning? |
|---|---|---|---|---|---|
| Anthropic Messages | input_tokens | No | No | output_tokens | Yes |
| OpenAI Responses | input_tokens | Yes | Yes | output_tokens | Yes |
| OpenAI Chat Completions | prompt_tokens | Yes | Yes | completion_tokens | Yes |
| Google Interactions | total_input_tokens | Yes | — | total_output_tokens | No |
| Google generateContent | promptTokenCount | Yes | — | candidatesTokenCount | No |
The vendors say so, each in its own place. Anthropic’s API reference: “Total input tokens in a request is the summation of input_tokens, cache_creation_input_tokens, and cache_read_input_tokens.” OpenAI’s organization Usage API defines its input_tokens as the number “including cached and cache-write tokens”, and OpenAI’s own sample cost code starts by subtracting them: ordinary_input_tokens = input_tokens - cached_tokens - cache_write_tokens. Google defines promptTokenCount as the total prompt size that “includes the number of tokens in the cached content.” The dashes in the Google rows are not an omission: the Interactions API supports only implicit caching, which carries no separate write charge.
So the same turn arrives in two shapes:
| Field | Anthropic reports | OpenAI reports |
|---|---|---|
input_tokens | 2,000 | 150,000 |
| Cache read | 140,000 | 140,000 |
| Cache write | 8,000 | 8,000 |
| Output | 3,000 | 3,000 |
| Bill, with the right function | $0.082 | $0.082 |
| Bill, with the other vendor’s function | −$0.214 | $0.378 |
The negative number is the lucky failure: it shows up on a dashboard and someone asks about it. The $0.378 is the unlucky one. It is 4.6x the real figure, it is positive, and it is plausible for a long-context agent turn, so it will sit in a spend report until somebody reconciles against an invoice. If you have ever moved a cost tracker from one provider to another, or written one “unified” helper for both, check which convention it assumes.
One smaller consequence of OpenAI’s convention: the input count includes hidden system tokens that the cached count excludes — OpenAI’s caching guide says cached-token reporting is “excluding hidden tokens” on GPT-5.6 and later. A hit rate computed as cached divided by input stays below 100% even when everything eligible was cached, and the gap is not a cache miss.
Reasoning is inside output_tokens at two vendors and outside it at the third
All three vendors bill reasoning as output. They disagree about where to count it.
Anthropic is explicit that output_tokens “remains the inclusive, authoritative total used for billing”, and that the thinking_tokens breakdown is “a read-only decomposition for observability” — computed by re-tokenizing, so it can differ from the real count by a few tokens. OpenAI’s reasoning guide says reasoning tokens “are billed as output tokens” and reports them in output_tokens_details.reasoning_tokens, also inside the total. Google puts them outside: total_output_tokens is only the visible response, total_thought_tokens is separate, and the pricing page spells out that “response pricing is the sum of output tokens and thinking tokens.”
That gives you two opposite mistakes:
- Forgetting to add thoughts at Google. Take the same turn on Gemini 3.8 Flash ($0.75 input, $0.075 cached, $3.75 output), with 2,400 of the 3,000 output tokens spent thinking. The correct bill is $0.02925. A function that reads
total_output_tokensas the whole output bills $0.02025 — 30.8% short. Run an Anthropic-shaped function on it and you make both mistakes at once: $0.12525, 4.3x over. - Adding reasoning on top at OpenAI or Anthropic. On the GPT-6 Sol turn above,
output_tokensplusreasoning_tokensbills 5,400 output tokens instead of 3,000: $0.106 instead of $0.082, 29.3% over.
The breakdown fields are for observability. Price the inclusive field where there is one, and add the thought count only where the vendor tells you it is separate.
The top-level numbers are not always the whole request
Anthropic has two features that change the shape of the usage object, and both do it in the direction that makes your costs look lower than they are.
Compaction summarizes a long conversation in an extra sampling pass, and the docs are blunt about the accounting: “The top-level input_tokens and output_tokens do not include compaction iteration usage.” In the docs’ own example, the top level reports 23,000 input and 1,000 output tokens, while a compaction entry in usage.iterations records a pass that read 180,000 and wrote 3,500. Priced on Claude Sonnet 5, the top level says $0.056; the request actually cost $0.451. A dashboard reading the top-level fields sees 12.4% of it — and it sees costs fall at exactly the moment they rise. On-demand compaction is starker still: the top-level fields are zero and the whole charge lives in the iteration. We covered what compaction does to context and the fix to our earlier cost function when the feature was new; the rule has not changed.
Server-side fallback is newer, in beta, and changes something more basic: which model you pay for. Claude Fable 5.1, Fable 5, Opus 5.5 and Opus 5 carry safety classifiers that can decline a request. With fallbacks set, the API retries the declined request on another model inside the same call and returns one response. The billing section is precise: “The top-level usage counts describe only the attempt that produced the returned message. Tokens from different models are never summed into one field.”
The docs’ example is a request to Claude Fable 5 that declines and is answered by Claude Opus 4.8. Two entries sit in usage.iterations, each with its own model:
| Attempt | Model | Input | Output | Cost at its own rates |
|---|---|---|---|---|
| Declined | claude-fable-5 | 535 | 0 | $0.00535, if billed |
| Served | claude-opus-4-8 | 412 | 264 | $0.00866 |
Price the top-level counts at the model you asked for and you get $0.01732 — double the real cost of the answer, while leaving out the declined attempt entirely. Price the iterations, each at its own model’s rate, and you get the right answer: $0.00866 plus the declined attempt when it was billed, which makes it 38% of the request.
Whether the declined attempt was billed depends on the refusal category. A refusal that arrives before any output is billed only for bio, frontier_llm and reasoning_extraction, and the documented fallback block carries only from and to, not the category. From the response alone you cannot tell whether that $0.00535 was charged. Our function below counts it, which errs high; the cost endpoint settles it.
The same rule makes plain refusals over-report. Anthropic says a refusal before any output in an unbilled category is not billed, but “either way, content is empty and token counts appear in usage.” A tracker that sums usage objects bills you for requests the vendor did not.
The rate is often not in usage at all
A usage object counts tokens. The multiplier on those tokens usually lives somewhere else in the response, or nowhere in it.
| Modifier | Effect | Where to read it |
|---|---|---|
| OpenAI Fast mode | 2x on the GPT-6 and GPT-5.6 families | service_tier on the response: fast or priority |
| OpenAI Flex | 0.5x | service_tier: "flex" |
| OpenAI Batch | 0.5x | You know; you submitted it |
| OpenAI long context | 2x input and cache, 1.5x output, for the whole request | input_tokens over 272K on GPT-6 and GPT-5.6 |
| OpenAI regional processing | +10% for models released on or after 5 March 2026 | Your endpoint |
| Anthropic fast mode | 2x on Opus 5.5, Opus 5 and Opus 4.8 | usage.speed, with the fast-mode beta |
| Anthropic US-only inference | 1.1x on every token category | usage.inference_geo |
| Anthropic Batch | 0.5x | usage.service_tier: "batch" |
| Google Flex / Priority | 0.5x / 1.8x on Gemini 3.8 Flash | service_tier |
| Gemini 3.8 Flash schedule | $0.75 / $3.75 through 31 December 2026, then $1.50 / $7.50 | The calendar |
Two of these deserve a sentence each, because the obvious implementation gets them wrong.
Read the tier the request ran on, not the tier you asked for. OpenAI’s Fast mode guide: “If your traffic ramps too fast, the system may downgrade some Fast mode requests to standard speeds and charge standard rates. When this happens, the response contains service_tier: "default".” A function that prices from your request parameter over-bills those requests by 2x. There is a second wrinkle: for GPT-5.6 and earlier, the response says priority even when you sent fast, so match both.
The long-context rate is per request, and it is a cliff. OpenAI’s model pages for GPT-6 Sol and GPT-6 Astra: “Prompts with more than 272K input tokens are priced at 2x input and cache rates and 1.5x output for the full request.” A GPT-6 Sol call with 300,000 input tokens, 280,000 of them cached, and 2,000 out costs $0.222. A function that only knows the short-context rates says $0.116, about half. The threshold counts input tokens, and OpenAI’s input count includes the cached part — the pricing table carries a separate long-context cached-input rate for exactly that case — so a good cache hit rate does not keep a long conversation under the line.
The Gemini row is the quiet one. Google publishes the price change in advance, so a rate table without an end date is wrong on a known morning: the Gemini turn above goes from $0.02925 to $0.0585 on 1 January 2027 with no change to your code or your traffic. Store rates with the date they stop being true.
Streaming: price the last count, never the first
Streaming moves the usage object around, and both big vendors do it differently.
At Anthropic, message_start carries a usage block, and each message_delta carries another — and the docs warn that “the token counts shown in the usage field of the message_delta event are cumulative.” Adding the two double-counts. Taking the first one under-counts, and not by a rounding error. In Anthropic’s own web-search streaming example on Claude Opus 5.5, message_start reports 2,679 input and 3 output tokens; the final message_delta reports 10,682 input, 510 output and one web search. The search results were added to the input mid-turn. Priced, that is $0.0108 at the first count against $0.0629 at the last — 5.8x.
At OpenAI’s Chat Completions, streamed responses carry no usage unless you ask: set stream_options: {"include_usage": true} and one extra chunk arrives before [DONE] with the totals, while every other chunk carries usage: null. The reference adds the caveat that matters for accounting: “If the stream is interrupted, you may not receive the final usage chunk which contains the total token usage for the request.” An interrupted stream is still billed for what it generated. It just never tells your logger.
What usage never contains
Some charges are not tokens, so no token field can carry them.
| Charge | Rate | In per-response usage? |
|---|---|---|
| Anthropic web search | $10 per 1,000 searches | Yes: server_tool_use |
| Anthropic web fetch | Tokens only | Counted, not priced |
| Anthropic code execution | $0.05 per container-hour | No — cost endpoint only |
| Anthropic Managed Agents | $0.08 per session-hour | No |
| OpenAI web search | $10 per 1,000 calls | No — count web_search_call |
| OpenAI containers | From $0.03 per 20-minute session | No |
| OpenAI file search | $2.50 per 1,000 calls | No |
| Google Search grounding | $14 per 1,000 after a free allowance | Counted, not priced |
| Gemini explicit cache storage | $0.50 per million tokens per hour | No |
The fine print matters for the ones you do use. Anthropic’s code execution comes with 1,550 free container-hours a month and a five-minute minimum, and is free altogether when web_search_20260209 or web_fetch_20260209 is in the same request; Managed Agents runtime accrues only while a session is running. OpenAI’s web search adds the retrieved content as tokens on top of the per-call fee, its container price is for 1 GB, and file search adds storage at $0.10 per GB per day after the first GB. Google’s grounding allowance is 5,000 requests a month shared across Gemini 3.x models, counted per response in grounding_tool_count, so a per-response price is wrong until you have passed it; the storage rate is Gemini 3.8 Flash’s through 2026.
We wrote a longer tour of the charges that sit beside the sticker price earlier; the table above is the subset that decides whether a usage-based tracker can be complete. It cannot, for any of the three vendors, without the cost endpoint.
One charge sits in the other direction: it is in usage, but not in anything you sent. Server-side conversation state — OpenAI’s previous_response_id, Google’s previous_interaction_id — lets you stop re-sending history, and it is easy to assume you stopped paying for it. OpenAI: “Even when using previous_response_id, all previous input tokens for responses in the chain are billed as input tokens.” Google’s example notes that the second turn’s usage “includes tokens from both turns.” You cannot estimate those requests from your payload size. Only the usage object knows, and only a cache hit makes that history cheap — which is the job of getting prompt-cache hits, not of the state API.
The organization-level APIs: what OpenAI’s Usage API and Costs API return
Per-response usage is for attribution: which feature, which user, which prompt version spent the money. For the total, both OpenAI and Anthropic expose organization-level endpoints behind an admin credential. They look alike and differ in the details that break integrations.
OpenAI splits it in two. GET /v1/organization/usage/completions returns token counts in buckets one minute, one hour or one day wide — at most 1,440, 168 and 31 buckets per page, so a page covers a day, a week or a month. You can group by project_id, user_id, api_key_id, model, batch and service_tier. It needs an Admin API key, and “Admin API keys cannot be used for non-administration endpoints” — so this is a separate credential in a separate secret, not your application key. The fields follow the per-response convention: input_tokens includes cached and cache-write tokens, with input_cached_tokens, input_cache_write_tokens and input_uncached_tokens (“excluding cache-write tokens”) alongside.
What it cannot do is reprice your traffic. There is no context-length dimension, so the 272K cliff — a per-request rule — cannot be reconstructed from bucketed totals. For money, use GET /v1/organization/costs: daily buckets only, up to 180 per page, groupable by project_id, line_item and api_key_id, with amount.value in dollars.
Anthropic has the same pair. /v1/organizations/usage_report/messages renames the per-response field to what it always meant — uncached_input_tokens — splits cache writes by TTL, and can group by model, workspace, API key, service tier, context window, inference_geo and, with the beta header, speed. Two gaps are documented: “Code execution is not included in the usage endpoint”, and its server-tool counter reports web searches only. Data “typically appears within 5 minutes.” The Admin API is not available on individual accounts. /v1/organizations/cost_report is daily-only, groups by workspace and description, and excludes Priority Tier costs.
A cost function that survives all of the above
This prices one response from each vendor, using only fields the vendor documents. It is deliberately explicit rather than clever: each rule in this article is one line you can find. Rates are from each vendor’s pricing page as of 27 September 2026 — replace them with yours, and see the live rates on our model pages before you trust ours.
from datetime import date
# $ per 1M tokens, standard lane. Verified 2026-09-27 on each vendor's pricing page.
# Keyed by the model the API RETURNS, which is not always the one you asked for.
RATES = {
"claude-sonnet-5": {"in": 2.00, "read": 0.20, "w5m": 2.50, "w1h": 4.00, "out": 10.00},
"claude-opus-4-8": {"in": 5.00, "read": 0.50, "w5m": 6.25, "w1h": 10.00, "out": 25.00},
"claude-fable-5": {"in": 10.00, "read": 1.00, "w5m": 12.50, "w1h": 20.00, "out": 50.00},
"gpt-6-sol": {"in": 2.00, "read": 0.20, "write": 2.50, "out": 10.00, "long": 272_000},
"gemini-3.8-flash": {"in": 0.75, "read": 0.075, "out": 3.75,
"until": date(2026, 12, 31)}, # doubles on 2027-01-01
}
BILLED_REFUSALS = {"bio", "frontier_llm", "reasoning_extraction"} # Anthropic, Sept 2026
def rates_for(model, on=None):
matches = [k for k in RATES if model.startswith(k)] # tolerate dated snapshot names
if not matches:
raise KeyError(f"no rates for {model}") # never price an unknown model at zero
r = RATES[max(matches, key=len)]
if "until" in r and (on or date.today()) > r["until"]:
raise ValueError(f"{model}: rate table expired after {r['until']}")
return r
def anthropic_cost(resp, batch=False):
u = resp["usage"]
if (resp.get("stop_reason") == "refusal" and u.get("output_tokens", 0) == 0
and (resp.get("stop_details") or {}).get("category") not in BILLED_REFUSALS):
return 0.0 # tokens are reported, but this refusal is not billed
total = 0.0
# compaction and server-side fallback: top-level counts cover only part of the request
for it in u.get("iterations") or [u]:
r = rates_for(it.get("model") or resp["model"])
w1h = (it.get("cache_creation") or {}).get("ephemeral_1h_input_tokens", 0)
w5m = it.get("cache_creation_input_tokens", 0) - w1h
total += (it.get("input_tokens", 0) * r["in"] # EXCLUDES cache reads and writes
+ it.get("cache_read_input_tokens", 0) * r["read"]
+ w5m * r["w5m"] + w1h * r["w1h"]
+ it.get("output_tokens", 0) * r["out"]) / 1e6 # includes thinking
if u.get("speed") == "fast":
total *= 2 # Opus 5.5 / 5 / 4.8; the field needs the fast-mode beta
if u.get("inference_geo") == "us":
total *= 1.1
if batch or u.get("service_tier") == "batch":
total *= 0.5
searches = (u.get("server_tool_use") or {}).get("web_search_requests", 0)
return total + searches * 0.01
def openai_cost(resp, batch=False):
u = resp["usage"]
r = rates_for(resp["model"])
inp = u.get("input_tokens", u.get("prompt_tokens", 0)) # Responses / Chat names
d = u.get("input_tokens_details") or u.get("prompt_tokens_details") or {}
read, write = d.get("cached_tokens", 0), d.get("cache_write_tokens", 0)
out = u.get("output_tokens", u.get("completion_tokens", 0)) # includes reasoning
ordinary = inp - read - write # input INCLUDES reads and writes
k_in, k_out = (2.0, 1.5) if inp > r.get("long", float("inf")) else (1.0, 1.0)
total = (k_in * (ordinary * r["in"] + read * r["read"] + write * r["write"])
+ k_out * out * r["out"]) / 1e6
# the tier that RAN the request; a throttled Fast request comes back as "default"
total *= {"flex": 0.5, "priority": 2.0, "fast": 2.0}.get(resp.get("service_tier"), 1.0)
if batch:
total *= 0.5
searches = sum(1 for i in resp.get("output", []) if i.get("type") == "web_search_call")
return total + searches * 0.01
def gemini_cost(resp, batch=False, on=None):
u = resp["usage"] # Interactions API
r = rates_for(resp["model"], on)
inp, read = u.get("total_input_tokens", 0), u.get("total_cached_tokens", 0)
out = u.get("total_output_tokens", 0) + u.get("total_thought_tokens", 0) # thoughts NOT in output
total = ((inp - read) * r["in"] + read * r["read"] + out * r["out"]) / 1e6
total *= {"flex": 0.5, "priority": 1.8}.get(resp.get("service_tier"), 1.0)
if batch:
total *= 0.5
return total
Every number in this article is one of its test cases: $0.082 for the shared turn on both Sonnet 5 and GPT-6 Sol, $0.02925 on Gemini 3.8 Flash, $0.451 for the compaction example, $0.01401 for the fallback example, $0.222 for the long-context call, zero for an unbilled refusal, and a raised error for the Gemini rates on 1 January 2027.
What it deliberately leaves out, so you know where it will disagree with the invoice:
- Declined fallback attempts in unbilled categories. It counts them, because the response does not say whether they were billed. It errs high.
- Charges with no token field: container hours, session runtime, file-search calls, cache storage, and grounding past the monthly allowance. It errs low.
- Google’s
total_tool_use_tokens. Google defines them as tokens “present in tool-use prompt(s)”, and in its own function-calling example they are not included intotal_tokens. The pricing page does not say how they are billed, so we leave them out and flag them for reconciliation rather than guess. - OpenAI’s regional uplift and Scale Tier, which the response does not report. If you use them, you know it — apply them outside.
Reconcile daily, and alert on the drift
A per-response tracker and the vendor’s cost endpoint will never agree exactly, and that is fine as long as you know why and in which direction.
| Cause | Direction of your tracker |
|---|---|
| Unbilled refusals still report tokens | Too high |
| Declined fallback attempts in unbilled categories | Too high |
| Interrupted streams that lose the final usage chunk | Too low |
| Code execution, containers, storage, grounding | Too low |
| A rate table past its end date | Either |
So the workable pattern is two layers. Price every response with a function like the one above and store the result next to the request — that gives you cost per feature, per customer and per prompt version, which no vendor endpoint can. Then, once a day, compare the sum with the vendor’s cost endpoint for the same window and alert when the gap moves outside the band you have learned to expect. A sudden jump is almost always one of the five rows in that table: a new server tool, a feature that turned on compaction, a model that started refusing, a rate that changed.
That is also why token savings are not dollar savings until you have weighted them by class — and why you cannot weight them by class until you know which class each field is counting. If you would rather start from rates than from code, our calculator prices a workload with cache and batch built in, and our methodology explains how each rate on this site is verified.
The short version fits on a sticky note. Know which vendor’s input_tokens you are holding. Price the model and tier the response names. Sum iterations when they exist. Add thoughts at Google and nowhere else. Take the last streaming count. Date your rates. And let the cost endpoint, not your tracker, have the final word.
| Model | Input /M | Cached input /M | Output /M |
|---|---|---|---|
| Claude Sonnet 5 Anthropic | $2 | $0.2 | $10 |
| GPT-6 Sol OpenAI | $2 | $0.2 | $10 |
| Gemini 3.8 Flash Google | $0.75 | $0.075 | $3.75 |
| Claude Opus 4.8 Anthropic | $5 | $0.5 | $25 |
Sources, each read for this article on 27 September 2026: Anthropic Messages API reference (usage object), pricing, prompt caching, streaming, compaction, refusals and fallback, fast mode, Usage and Cost API, usage report and cost report references; OpenAI pricing, prompt caching, reasoning, Fast mode, GPT-6 Sol model page, Chat and Responses references, usage completions and costs references, and the Admin APIs guide; Google Gemini pricing, tokens, thinking, caching, and the generateContent and Interactions API references. Model rates cross-checked against our snapshot on the same day. Beta fields and billing rules change often — see our methodology for how we re-verify, and corrections for what we have got wrong.
Frequently asked questions
What is the OpenAI Usage API?
It is a set of organization-level endpoints that return your token consumption in time buckets, the main one being GET /v1/organization/usage/completions. It needs an Admin API key - an ordinary project key will not work, and an Admin key cannot call the normal model endpoints either. Buckets are one minute, one hour or one day wide, up to 1,440, 168 and 31 buckets per page respectively, and you can group by project_id, user_id, api_key_id, model, batch and service_tier. Its companion, GET /v1/organization/costs, returns daily dollar amounts that you can group by project, API key and line item. Use the first for attribution and alerting, and the second when you need a figure in money.
Does input_tokens include cached tokens?
It depends on the vendor, and that is the whole problem. At OpenAI, yes: input_tokens includes both cached tokens and cache-write tokens, and OpenAI's own sample code subtracts them to get the ordinary remainder. At Anthropic, no: input_tokens is only the uncached part, and the docs state that total input is the sum of input_tokens, cache_creation_input_tokens and cache_read_input_tokens. At Google, promptTokenCount and total_input_tokens include the cached tokens. A cost function written for one convention mis-bills the others, in one case by 4.6x.
Are reasoning or thinking tokens billed, and where do I find them?
They are billed as output at all three vendors, but they are counted in different places. OpenAI and Anthropic include them inside output_tokens and show a breakdown alongside (output_tokens_details.reasoning_tokens and output_tokens_details.thinking_tokens), so you must not add the breakdown on top. Google counts them outside the output field - total_thought_tokens in the Interactions API, thoughtsTokenCount in generateContent - so you must add them. You are billed for the full reasoning even when the API returns only a summary of it.
Why does the sum of my usage objects not match my invoice?
Because several documented things push the two apart, in both directions. Refusals that Anthropic does not bill still report tokens in usage, which makes your sum too high. Interrupted streams can lose the final usage chunk, which makes it too low - OpenAI warns that you may not receive the final usage chunk if the stream is interrupted. Container hours, cache storage, search grounding past a free allowance and similar charges never appear in per-response usage at all. And a rate table that has quietly expired mis-prices everything after its date. Price responses yourself for attribution, then reconcile daily against the vendor's cost endpoint.
How do I get token usage when streaming?
At OpenAI's Chat Completions, set stream_options: {"include_usage": true}; usage then arrives in one extra chunk before [DONE], and every other chunk carries usage: null. At Anthropic, message_start carries a first usage block and each message_delta carries cumulative counts - price the last one only, and never add them together. The first count is not a floor you can trust: in Anthropic's own web-search example the input grows from 2,679 tokens at message_start to 10,682 at the final delta, because search results are added mid-turn.
Is the Anthropic Cost API amount in dollars?
No. Anthropic's cost_report returns amount as a decimal string in the lowest currency unit, and the reference gives the example that "123.45" in USD represents $1.23. OpenAI's /v1/organization/costs returns amount.value as a number in dollars. A spend dashboard that pulls both and adds them without converting overstates Anthropic by exactly 100x.
Does previous_response_id or server-side conversation state save money?
It saves bandwidth, not tokens. OpenAI states that even when using previous_response_id, all previous input tokens in the chain are billed as input tokens, and Google's own example for previous_interaction_id notes that the second turn's usage includes tokens from both turns. The history you stopped sending is still re-processed and billed each turn. What does lower the bill for that history is a cache hit, which is why the cached-token field is the one to watch.
Which model should I price a response at?
The one the response says ran it, not the one you requested. With Anthropic's server-side fallback, a refused request can be answered by another model inside the same call, and each attempt is billed at the rates of the model that ran it; usage.iterations lists every attempt with its model. Sticky routing then sends later turns of that conversation straight to the fallback model for roughly an hour, with no fallback block in the response - the top-level model field is the only sign. Pricing those turns at the requested Claude Fable 5 instead of the serving Claude Opus 4.8 doubles every line.
Nothing yet. Mention this post on any platform — Mastodon, Bluesky, LinkedIn, a blog — and the citation surfaces here.