Every Gateway call comes back with a receipt
Cost used to be recomputed at read time from today's price list. It is now priced when the request is served and frozen on the ledger row.
Until 7 September, token_usage stored token counts and nothing else. Every dollar figure in the Console was recomputed at read time from the live registry, which has three consequences worth stating plainly.
Editing a price silently rewrote all historical cost. Managed traffic — our key, real cost of goods, billable — was indistinguishable from BYOK traffic the customer had already paid for. And routing was never persisted, so "the router saves you money" had no data behind it at all.
Price at write time, and freeze it
A row in the ledger now carries the price that was applied at request time: cost_usd, the per-million list rates in force, the rate multiplier, the provider, the mode, the model asked for, the model served, whether it was routed, and what the baseline would have charged. The row reproduces its own arithmetic.
One row per inference round, including rounds that failed with zero tokens, so an error rate stays computable from the ledger alone.
What comes back on the response
On a buffered response the arithmetic is in the headers.
x-lobstack-cost-usd— what you owe for these tokens.x-lobstack-savings-usd— the baseline cost minus that.x-lobstack-baseline-modelandx-lobstack-baseline-reason— which model the saving was measured against, and why that model is the comparison.x-lobstack-baseline-usd— what the baseline would have charged for these exact token counts.x-lobstack-priced— false when the served model is not in the registry, so cost is null rather than zero.x-lobstack-metered— false when the ledger write failed. You still got your answer; the row is missing.
Alongside them, the routing headers say what actually served the request, the tier it landed in, the complexity score, and whether our key or yours paid for the tokens. On a streamed response the cost fields arrive on the last frame instead, because headers flush before the provider has counted a token.
Where the honest answer is null, the header is empty
Not zero. An unpriced model produces an empty x-lobstack-cost-usd, and a client that renders that as $0.00 has written off a real charge. The same rule runs through the ledger and the stream frame.
A saving is a subtraction, so both operands are shown
baseline_reason is named when you asked for a specific model, and plan_ceiling when you sent auto and the comparison is the most expensive model your plan may reach. Both are real subtractions between two real prices, and they are not the same claim — plan_ceiling compares against a model you never mentioned, chosen because it is the most flattering number available to us.
Render baseline_reason next to the figure, or do not render the figure.
What stays on our side
There are two costs on every request: what the provider charged us, and what you owe. Only the second is on the receipt. The provider figure is written to the ledger as provider_cost_usd and appears in no header, no stream frame and no API response.
Every field, every meter and the full ledger schema are in Metering & cost.
All posts


