
The position
We read the provider's settled cost for the call it actually served and bill exactly that. We do not compute a cost, and when a cost is genuinely unknowable we report it as unpriced — never as
$0, because a confident zero is the most expensive lie a gateway can tell.
Every number a customer sees on nRouter traces back to one value: what a request cost. Your budget, your attribution split, your per-customer margin and your invoice are all arithmetic on that single figure. It is the most important number in the product and the easiest one to quietly get wrong in our own favour.
So we made a principle of it and wrote it down, because a principle nobody published is a preference. This post is what the principle is, what it costs you, and how to check that we are keeping it.
What we were asked for instead
The request we keep declining, stated at its strongest: fill every cell. Give us a cost column with a number in every row. A blank breaks the pivot table, a blank breaks the chargeback report, and a blank is the one thing an internal finance system cannot consume. Estimate it if you must — an approximate number beats a hole.
We understand why this is asked, and the case for it is genuinely strong:
| Their argument | Why it holds up |
|---|---|
| A blank breaks downstream systems | A chargeback pipeline that must handle nulls is a pipeline with a bug waiting in it |
| An estimate is better than nothing | For capacity planning, ±5% is usually decision-equivalent to exact |
| Dashboards with holes lose trust | Users read a gap as a broken product, not as an honest one |
| Everyone else shows a number | A competitor's fully-populated column looks more complete in a bake-off |
The last row is the one that stings, because it is true and it costs us evaluations. A gateway that computes cost has a prettier dashboard than one that admits an unknown. We still will not do it, and the next section is why.
What that would cost you
A computed cost is plausible. That is exactly what makes it dangerous — you cannot tell a computed estimate from a settled charge by looking at it, so the incentive to shade it is enormous and the chance of detection is near zero. Three corruptions follow, and none of them requires anyone to act in bad faith:
- Stale prices. A price table is a copy of somebody else's data with no invalidation signal. Providers change per-model rates, split rates by cache tier, and ship new model families with different billing units. Stale-low undercharges you today and produces a shocking correction later; stale-high overcharges you quietly forever.
- Convenient rounding. Rounding policy sounds like a detail until every rounding decision goes the same direction. A half-cent per call, always up, is a margin nobody agreed to and nobody can see.
- Embedded markup. A markup baked into a computed rate is invisible by construction. You cannot decompose a single number into "provider rate" and "our cut" without being told the split, so the only defence is not to compute the number at all.
Work the arithmetic on the first one. This is an illustration, not a measurement of anything we have done:
| Scenario (illustrative) | Monthly provider spend | Price-table drift | Cost of the drift |
|---|---|---|---|
| Table 3% stale-high | $20,000 | +3% | $600/mo overstated, $7,200/yr |
| Table 3% stale-low | $20,000 | −3% | $600/mo understated, corrected later as a surprise |
| Unknown cost billed as $0 | any | −100% on those calls | Budgets never advance; the ceiling silently stops existing |
The third row is the serious one. A missing price rendered as $0 does not just misreport — it disables the controls built on top of the number. A budget that sums zeros never trips. A rate ceiling keyed on spend never bites. The failure is silent, and silence is worse than a loud error, because nothing pages anybody.
What we do instead
The provider serves the call and reports what it settled at. We read that value and bill it. There is no price table to go stale, because we are not the ones pricing the call.
request → provider serves it → provider reports the settled cost
│
we read that authoritative value ← the only number we trust
│
settle credits against THAT, exactly
│
write one ledger entry, sum reconcilable to the balanceBecause that value is not always available, a cost has exactly three states, and we expose all three rather than collapsing them into one column:
| State | Header behaviour | What it means | What you should do |
|---|---|---|---|
exact | x-nr-request-cost present, x-nr-cost-status: exact | The provider reported a settled cost; this is what you were billed | Use it for attribution and chargeback directly |
unpriced | x-nr-request-cost absent, x-nr-cost-status: unpriced | The call succeeded but its cost is not knowable from what the provider returned | Count the call, do not invent a figure; reconcile at the ledger |
| In flight | Neither final | A hold is placed before the call and settled after it | Read the ledger, not the header, for the final figure |
The reservation half of that is not an implementation detail either. A hold is taken before the request leaves, and every exit path either settles it or releases it — the mechanism is reserve-and-settle, and it is why a balance cannot go negative under concurrent load. One deliberately counter-intuitive rule falls out of the honesty principle: an unpriced call settles at the reserved amount rather than releasing, because releasing it would make the request free, and free requests are how a gateway leaks money while every dashboard reads green.
Why an absent header beats a zero
The header contract is the smallest place this principle becomes observable, so it is worth being precise about it. When the cost is unknown, x-nr-request-cost is absent — not 0, not null, not an empty string. x-nr-cost-status carries unpriced alongside it.
resp = client.chat.completions.with_raw_response.create(
model="claude-sonnet-4-5-20250929",
messages=[{"role": "user", "content": prompt}],
)
cost = resp.headers.get("x-nr-request-cost") # None when unpriced
status = resp.headers.get("x-nr-cost-status") # "exact" | "unpriced"
if cost is None:
metrics.increment("llm.cost.unpriced") # count it, never zero-fill it
else:
metrics.observe("llm.cost.usd", float(cost))An absent field forces the consumer to make a decision. A zero makes the decision silently and wrongly, and the decision it makes is "this call was free." Every downstream aggregate then inherits that claim: the team's spend total, the customer's margin, the model's cost-per-request ranking in cost vs usage analytics. One zero-filled column is a whole quarter of quietly wrong economics.
The same logic runs through the non-text modalities, where per-unit pricing is least standardised across providers. That is what multimodal cost floors are for: a missing price reads as a conservative charge, deliberately, rather than as a dishonest free call.
What honest cost makes possible
Cost honesty is not one feature. It is the precondition for four others, each of which is only worth what the underlying number is worth:
- Hard spend limits cap real spend, so a cap means what it says. Sum estimates instead and your ceiling is an estimate too.
- Attribution by team, customer and feature reconciles to the invoice, which is the only test that matters. Estimates sum to a number that is close to the bill and never equal to it — and "close" is exactly what an argument between two teams is made of.
- Markup-free credits are only credible if the per-call cost carries no hidden cut. It cannot carry one, because we do not set it. Our revenue is the platform fee, charged visibly on top — the reasoning is in Every Feature on Every Plan: We Charge a Fee, Not a Gate.
- Per-customer billing for AI apps only works if your cost of goods is real. Reselling on top of an estimate means your margin is an estimate, which you will discover at the worst possible time.
Pull the honest number out and every one of those becomes something you take on faith. Keep it, and they are all just arithmetic on a value you can verify. The cross-provider mechanics of getting that value in the first place are in the cost tracking guide.
The same refusal, everywhere
Cost is where this stance matters most, because cost is where the incentive to fudge is strongest. But it is one instance of a broader refusal to build a convenient fiction next to the truth:
- No mocks, no demo mode. There is no environment where the system pretends. The argument is in why we ban mocks and demo mode, and it is the same argument as this one, pointed at behaviour instead of at money.
- Real tenants, real isolation. Separation is enforced beneath the application rather than asserted by it, so "isolated" is a property that can be tested rather than a claim in a doc.
- The ledger is the record. Every credit movement is an entry, and the entries sum to the balance. There is no second place where a balance is stored more conveniently.
- Compliance stated at its actual stage. SOC 2 Type II is in progress. Not certified, not compliant — in progress, on the trust page, until the day it is not.
The trade we are making
This costs you things, and they are not hypothetical.
Your dashboard will sometimes have a hole. Where a competitor shows a confident figure, we show unpriced and a count. If your finance pipeline cannot consume a null, that is real integration work we are pushing onto you, and we know it.
We lose bake-offs on completeness. A fully-populated cost column looks better in a side-by-side grid than an honest one with gaps. We have watched this happen and we are not going to fix it by inventing numbers.
You cannot ask us to price a model we cannot price. There is no override that makes a number appear. If a provider does not report enough to settle a call, the answer stays unpriced until the provider changes what it reports.
Reconciliation is on you, if you want it. We publish the ledger and the header. Verifying that they agree is a job we make possible and do not do for you.
Who this is wrong for
- Teams that require a fully populated cost column, unconditionally. If a chargeback system cannot represent "unknown" and cannot be changed, our honest answer is an integration problem you will fight every month. Pick a vendor that estimates, and know that is what you picked.
- Anyone who wants a blended internal rate. Some organisations deliberately want one flat internal price per token, decoupled from provider reality, to keep budgeting simple. That is a legitimate model. It is the opposite of this one.
- Buyers optimising a capability grid. If completeness of the cost column is a scored row, we score badly on it by design.
- Teams that need cost known before the call, exactly. Pre-flight is a reservation, not a settlement. If you need an exact figure before egress, no gateway can honestly give you one.
How you can hold us to it
Not one of these requires talking to us.
- Read the header on a live call. Confirm
x-nr-request-costis absent — not0— on any call whose status isunpriced. If you ever see a zero paired withunpriced, that is a defect and we want the request id. - Reconcile the ledger. Sum a day of ledger entries and compare against the balance change. Reading a spend ledger walks through it; the billing guide says where to find it.
- Cross-check one call against the provider's own rate card. Take an
exactcost, look up the model on the vendor's public pricing page from the Sources list, and do the multiplication yourself. - Compare the dashboard to the raw numbers. The analytics guide shows the aggregates; they should equal the sum of what you collected from the headers.
- Test the ceiling. Set a small budget and prove the 402 arrives before the provider call, not after. Handling 429 and 402 is the client-side half.
- Check what we charge on top. The pricing page states the platform fee. If our revenue ever appears anywhere other than that visible line, this post is false.
Try it
Point one existing service at https://api.nrouter.ai/v1 with NROUTER_API_KEY, log both cost headers for a day, and reconcile your total against the ledger. Then deliberately call something unusual — a model or modality at the edge of your catalog — and watch what happens when the cost is not knowable. The absent header is the whole argument of this post, and it takes about ten minutes to see. Start at signup; the current catalog is on the models page.
See also
- Reserve-and-settle: never overspend a credit balance — the mechanism behind the hold, and why an unpriced call settles rather than releases.
- Markup-Free LLM Credits: The Fee Is On Top, Never In The Rate — the commercial claim this principle makes checkable.
- Multimodal Cost Safety: An Unpriced Image Call Is Never $0 — where a missing price is most likely and how a floor beats a zero.
- How to read your LLM credit ledger — the reconciliation procedure referenced in "how you can hold us to it".
- One Authoritative Cost Per LLM Request, Across Providers — the cross-provider mechanics of getting a settled cost at all.
- Why we ban mocks and demo mode — the same refusal, applied to behaviour instead of money.
- Pricing — the platform fee, stated as the one place our revenue appears.
Sources
Verified 2026-08-23. Provider rate cards change; if any link below has moved or changed, email hello@nrouter.ai and we will correct this post.
- nRouter plans and fees: nrouter.ai/pricing — the visible platform fee that is our only cut.
- OpenAI API pricing: openai.com/api/pricing — the rate card to cross-check an
exactcost against for OpenAI models. - Anthropic pricing: anthropic.com/pricing — the same, for the Claude family.
- AWS Bedrock pricing: aws.amazon.com/bedrock/pricing — Bedrock is live on nRouter and AWS publishes per-model rates.
- OpenAI API reference: platform.openai.com/docs/api-reference — the usage object a settled cost is derived from upstream.
- Anthropic Messages API: docs.anthropic.com/en/api/messages — the equivalent usage reporting for Claude.
OpenAI, Anthropic and AWS are trademarks of their respective owners. nRouter is not affiliated with or endorsed by them. All claims above are sourced from their public pricing or documentation on the date shown.


