OpenAI's GPT-5.6 ships reasoning across the entire production family. Sol, Terra, Luna — all of them reason before responding.
That's a capability upgrade. It's also a billing problem most teams haven't hit yet — but will.
The invisible tokens eating your budget
Reasoning tokens are billed as output tokens. They just never appear in the response.
So the model returns a short answer while consuming substantially more billed tokens internally. Your estimator sees the visible output. The invoice sees everything.
Concrete example — a Sol request returning 200 visible tokens with 600 reasoning tokens underneath:
Visible output: 200 tokens
Reasoning: 600 tokens
Billed output: 800 tokens
At $30 per million output tokens:
Estimated (visible only): 200 / 1M × $30 = $0.006
Actual: 800 / 1M × $30 = $0.024
4× off. Not because the math was wrong. Because the estimator measured the wrong thing.
Why a point estimate breaks here
Most pre-call cost guards look like this:
const estimatedCost =
(inputTokens / 1_000_000) * inputPrice +
(expectedOutputTokens / 1_000_000) * outputPrice;
That's fine when visible output length is a reasonable proxy for billed output. For reasoning models, it isn't.
A simple formatting task and a complex architectural problem can return similarly-sized responses while generating completely different reasoning-token counts internally. Same output length, wildly different cost.
The guard needs to account for that uncertainty — not pretend it doesn't exist.
Use a range, not a number
Instead of estimating a single cost figure, estimate a range:
interface ModelPricing {
inputPerM: number;
outputPerM: number;
thinkingMultiplierRange?: [number, number];
}
Shift the question from:
"What will this call cost?"
to:
"What's the plausible cost ceiling — and can the session afford it?"
If the worst-case estimate exceeds the remaining budget, block the call before it leaves your process. That's the only point where you still have control.
Reconcile after execution
Once the provider responds, replace the reservation with reality:
Before call:
estimate range
reserve against ceiling
block if ceiling is unaffordable
After call:
read actual token usage
release reservation
record actual spend
This is a standard reservation pattern. The key property is unchanged: the budget decision happens before the request goes out. Actual usage just closes the loop.
Let your own workload calibrate the range
A generic multiplier is a starting point, not an answer.
Once you have production data, track the ratio of reasoning tokens to visible output tokens per model per workload type. Over time, your registry moves from:
"reasoning might add 0.5–4×"
to:
"for this workload, observed range is 1.2–1.8×"
The guard gets sharper without pretending reasoning cost is predictable before execution.
Caching creates the opposite failure
Reasoning inflates actual cost above estimate. Caching deflates it.
A simplistic guard fails in both directions:
- Reasoning: actual cost > estimate → you underreserved, overspent
- Caching: actual cost < estimate → you overreserved, blocked calls unnecessarily
The fix is the same either way: model the provider's actual billing mechanics, not just input × price + output × price.
The bigger shift
As models get more sophisticated, token count alone stops being a sufficient cost model.
A production cost guard needs to account for:
- Model-specific pricing tiers
- Cached input discounts
- Reasoning output ranges
- Retries and partial failures
- Session-level budgets across multiple agents
Some of those variables are only fully known after execution. That's not a limitation to work around — it's the architecture to design for.
Estimate and reserve before the call. Reconcile against actual usage afterward.
The estimate isn't wrong. It's just not the whole bill anymore.
Top comments (0)