Pricing
Usertoken costs per model across all four tiers, estimation functions, and the fallback rate.
All costs in the usertrust SDK are denominated in usertokens (UT).
1 UT = $0.0001 (one basis point of a dollar — a hundredth of a cent).
A budget of 100_000 UT equals $10.00. A budget of 1_000_000 UT equals $100.00.
Pricing Table
The SDK includes a 56-model pricing table in ledger/pricing.ts, current as of
PRICING_TABLE_VERSION = "2026-11-02" (see PRICING_TABLE_VERSION).
Rates are in usertokens per 1,000 LLM tokens, across four tiers: input (fresh prompt tokens),
output, cache-read (cache-hit prompt tokens), and cache-write (cache-creation prompt tokens). A
— means the provider publishes no rate for that tier — it is not free; see
Cache tiers and the fallback invariant below.
Anthropic
| Model | Input | Output | Cache Read | Cache Write (5m) | Cache Write (1h) |
|---|---|---|---|---|---|
claude-fable-5-1 | 100 | 500 | 2.5 | 125 | 200 |
claude-fable-5 | 100 | 500 | 10 | 125 | 200 |
claude-mythos-5-1 (limited availability) | 100 | 500 | 2.5 | 125 | 200 |
claude-mythos-5 (limited availability) | 100 | 500 | 10 | 125 | 200 |
claude-opus-5-5 | 40 | 200 | 2 | 50 | 80 |
claude-opus-5 | 50 | 250 | 5 | 62.5 | 100 |
claude-opus-4-8 | 50 | 250 | 5 | 62.5 | 100 |
claude-opus-4-7 | 50 | 250 | 5 | 62.5 | 100 |
claude-opus-4-6 | 50 | 250 | 5 | 62.5 | 100 |
claude-opus-4-5 | 50 | 250 | 5 | 62.5 | 100 |
claude-mythos-preview (deprecated; Project Glasswing) | 250 | 1250 | 25 | 312.5 | 500 |
claude-opus-4-1 (retired) | 150 | 750 | 15 | 187.5 | 300 |
claude-opus-4 (retired) | 150 | 750 | 15 | 187.5 | 300 |
claude-sonnet-5-5 | 20 | 100 | 1 | 25 | 40 |
claude-sonnet-5 | 20 | 100 | 2 | 25 | 40 |
claude-sonnet-4-6 | 30 | 150 | 3 | 37.5 | 60 |
claude-sonnet-4-5 | 30 | 150 | 3 | 37.5 | 60 |
claude-sonnet-4 (retired) | 30 | 150 | 3 | 37.5 | 60 |
claude-haiku-5-5 (prompt ≤ 100,000 tokens) | 1 | 5 | 0.1 | 1.25 | 2 |
claude-haiku-5-5 (prompt > 100,000 tokens) | 5 | 25 | 0.5 | 6.25 | 10 |
claude-haiku-4-5 | 10 | 50 | 1 | 12.5 | 20 |
claude-3-5-haiku (retired) | 8 | 40 | 0.8 | 10 | 16 |
Rates re-verified against Anthropic's published pricing page
(platform.claude.com/docs/en/about-claude/pricing) on 2026-10-07; the 1-hour write column was re-read
raw on 2026-10-08, and every row again on 2026-10-11.
Anthropic publishes cache-read at 0.1x base input and 5-minute cache-write at 1.25x, with three
published exceptions on cache reads: 0.05x on claude-opus-5-5 and claude-sonnet-5-5, and
0.025x on claude-fable-5-1 and claude-mythos-5-1. claude-sonnet-5 is $2 / $10 per MTok:
the introductory price became the standard price and the announced increase to $3 / $15 did not
happen. The 1-hour cache write (2x base input, the last column) is its own tier:
cacheWriteTokens stays the TOTAL written and a call that reports a 1-hour share
(cache_creation.ephemeral_1h_input_tokens) prices that share at cacheWrite1hPer1k and the
remainder at the 5-minute rate; see 1-hour cache writes.
A customRates entry is honoured only when the config's pricing field is "custom" (it is ignored
under the default "recommended"), and it replaces the table row rather than merging with it.
Restate cacheReadPer1k, cacheWritePer1k and cacheWrite1hPer1k in the entry: an omitted read or
5-minute write tier prices at inputPer1k, and an omitted 1-hour write rate at the dearer of the
5-minute write rate and 2× inputPer1k. The SDK prints a one-time warning when a custom entry
drops cache tiers the table publishes for that model.
Per-request prompt tiers (Claude Haiku 5.5)
claude-haiku-5-5 is priced per request by prompt length. A request whose prompt is over
100,000 tokens pays the higher row for every category, output included; a prompt of exactly
100,000 tokens pays the lower row. The prompt length counts all of the request's input tokens:
fresh input, cache reads and cache writes (a 1-hour write is part of the cache writes, so it is
counted once). Output does not count toward it. Each request is priced on its own.
In the table this is ModelRates.longPrompt: the row's own rates are the lower tier, and
longPrompt is { thresholdTokens: 100_000, rates }. costFromRates selects the tier from the
counts it prices, so every estimate, settle and stream applies the same rule, and a receipt's
pricing.appliedRates are the rates of the tier the call was settled at: the recompute below
still reproduces its cost. Only built-in table rows carry a tier; customRates are flat, and a
longPrompt on a custom row (for example one built by spreading a table row) is ignored.
The xAI rows use the same mechanism with thresholdTokens: 199_999: xAI applies its doubled long-context rates once a
prompt reaches 200,000 tokens, so a prompt of 200,000 tokens or more pays the higher row and 199,999 or fewer pays the lower one (see xAI).
One settle is one request. A settle prices the counts it is given as a single request. A caller that settles several requests' usage together, such as the Claude Code plugin's transcript windows, is priced at the tier of their combined prompt. Before rounding, that is never below what the requests cost one by one, and never above the higher tier for all of them. The charge itself can be lower, because a settle is rounded up to a whole UT once, with a 1 UT floor: two requests that each cost 0.4 UT are charged 1 UT together and 2 UT apart. To be priced exactly, settle each request on its own.
Holds. trust() and createGovernor().authorize() size a hold from an estimated prompt,
which cannot tell which side of the threshold the request will land on. They hold the higher
tier; the settle posts the actual tier and the two-phase post releases the difference at once. A
short Haiku 5.5 call therefore reserves about 5× what it settles at. The @usertrust/openshell gate
sizes from an upper bound on the prompt, so it holds the lower tier whenever that bound is at or
under 100,000 tokens.
1-hour cache writes
ModelRates.cacheWrite1hPer1k is the 1-hour write rate. Every Anthropic row carries it
explicitly (the page's "1h cache writes" column). cacheWriteTokens is the TOTAL cache-write
count, and the 1-hour tokens are a subset of it (never added to it): the 5-minute term is
cacheWriteTokens - cacheWrite1hTokens. A 1-hour count above the total is clamped to it, and a
1-hour count with no write total prices nothing at the 1-hour rate; sent alone to a headless
settle() it is not reported usage, so the settle meters at the pre-call estimate. A reported 1-hour share for a model whose built-in row publishes no 1-hour rate (Mistral, Gemini,
OpenAI) is ignored: it has no such tier, so the whole write total prices at its single write rate. A custom row that omits cacheWrite1hPer1k
resolves, in one place (effectiveCacheWrite1hRate), to the dearer of its 5-minute write rate and
2x inputPer1k: a silent row is never billed below 2x input.
Where the split comes from: the Anthropic usage.cache_creation breakdown, on both stream
surfaces and the non-stream path; headless settle() takes cacheWrite1hTokens; usertrust-server
accepts it on POST /v1/settle and lists cache-write-1h in /v1/health capabilities (an older
server strips the key, so a client sends it only when the capability is listed). A payload that
carries only the flat cache_creation_input_tokens total, and a host with no TTL split (the
OpenClaw plugin's usage), prices at the 5-minute rate.
On the receipt, when the call wrote 1-hour cache: a ROOT field
cacheWrite1h: { tokens, ratePer1k }, never inside usage or pricing.appliedRates (the v2 schema
closes both). It is absent otherwise, so every other receipt is unchanged. An auditor's recompute
splits the write term: (usage.cacheWriteTokens - cacheWrite1h.tokens) x appliedRates.cacheWritePer1k + cacheWrite1h.tokens x cacheWrite1h.ratePer1k.
OpenAI
| Model | Input | Output | Cache Read | Cache Write |
|---|---|---|---|---|
gpt-4o | 25 | 100 | 12.5 | — |
gpt-4o-2024-05-13 (snapshot priced above its alias) | 50 | 150 | — | — |
gpt-4o-mini | 1.5 | 6 | 0.75 | — |
gpt-5.4 | 25 | 150 | 2.5 | — |
o3 | 20 | 80 | 5 | — |
o4-mini | 11 | 44 | 2.75 | — |
gpt-5.6-sol (promotional price, "at least through November 21, 2026") | 40 | 200 | 4 | 50 |
The cached-input discount varies within the OpenAI family — gpt-5.4 reads at 0.1x, o3/
o4-mini at 0.25x — so there is no single family-level multiplier. OpenAI publishes no separate
cache-write rate for the models above; writes bill at the standard input price, which is exactly
what the fallback invariant reproduces by leaving cacheWritePer1k unset. gpt-5.6-sol is the
exception and carries an explicit rate: from gpt-5.6 onward OpenAI bills cache writes at 1.25x the
uncached input price, so leaving it unset would misprice them.
Moonshot AI
| Model | Input | Output | Cache Read | Cache Write |
|---|---|---|---|---|
kimi-k3 | 30 | 150 | 3 | — |
Moonshot's price list has a cache-hit and a cache-miss input column and no cache-creation column at
all, so cacheWritePer1k is unset and writes price at the input rate through the fallback
invariant. Kimi speaks the OpenAI wire protocol, so detectClientKind reports openai for a Kimi
client — that is the client SHAPE, and it does not change which rates apply.
Google Gemini
| Model | Input | Output | Cache Read | Cache Write |
|---|---|---|---|---|
gemini-2.5-flash | 3 | 25 | 0.3 | — |
gemini-2.5-pro | 12.5 | 100 | 1.25 | — |
gemini-3.1-pro-preview | 20 | 120 | 2 | — |
Context-cache reads are 0.1x base input. Cache creation bills as ordinary input plus an hourly
storage charge this per-token model doesn't carry, so cacheWritePer1k is omitted rather than
guessed — see Documented approximations.
xAI
Rates are xAI's published model pricing, retrieved 2026-11-02. xAI publishes a cached-input price
and no cache-write price, so the cache-write column is — (writes price at the input rate). Every
model below also has a 200,000-token long-context tier at exactly double each rate, cached input
included: xAI applies it once the prompt reaches 200,000 tokens, so a prompt of 200,000 tokens or more
pays the doubled rates for every category, and a prompt of 199,999 tokens or fewer pays the rates shown.
The table cannot see a request's endpoint: xAI bills calls to its US regional endpoint at 1.1x these
rates, which the estimate does not include.
| Model | Input | Output | Cache read | Cache write |
|---|---|---|---|---|
grok-4.7 | 20 | 60 | 5 | — |
grok-4.6 | 20 | 60 | 5 | — |
grok-4.5 | 20 | 60 | 3 | — |
grok-4.3 | 12.5 | 25 | 2 | — |
grok-4.20-0309-reasoning | 12.5 | 25 | 2 | — |
grok-4.20-0309-non-reasoning | 12.5 | 25 | 2 | — |
grok-4.20-multi-agent-0309 | 12.5 | 25 | 2 | — |
grok-build-0.1 | 10 | 20 | 2 | — |
grok-3 | 12.5 | 25 | 2 | — |
grok-4-0709 | 12.5 | 25 | 2 | — |
grok-4-1-fast-reasoning | 12.5 | 25 | 2 | — |
grok-4-1-fast-non-reasoning | 12.5 | 25 | 2 | — |
grok-4-fast-reasoning | 12.5 | 25 | 2 | — |
grok-4-fast-non-reasoning | 12.5 | 25 | 2 | — |
grok-code-fast-1 | 12.5 | 25 | 2 | — |
The last seven rows are xAI's retired slugs. xAI's "Grok Model Retirement on May 15, 2026" notice says
requests to a deprecated slug are billed at grok-4.3 pricing, so each carries that row and its
long-context tier. That includes grok-code-fast-1, which the notice routes to grok-build-0.1: routing is
not billing, and where the notice's pricing paragraph and its routing note differ the higher price is
metered. grok-3-mini and bare grok-4 are not on that notice and have no row.
Other Providers
No cache-tier pricing is currently published for these models; both cache columns fall back to the input rate.
| Model | Provider | Input | Output |
|---|---|---|---|
mistral-large | Mistral | 5 | 15 |
mistral-large-latest (alias) | Mistral | 5 | 15 |
deepseek-chat | DeepSeek | 2.8 | 4.2 |
deepseek-reasoner | DeepSeek | 2.8 | 4.2 |
llama-4-maverick | Meta (Bedrock) | 2.4 | 9.7 |
command-a | Cohere | 25 | 100 |
sonar-pro | Perplexity | 30 | 150 |
qwen-72b | Alibaba | 2.9 | 3.9 |
nova-pro | Amazon | 8 | 32 |
CANONICAL SOURCE
Rates reflect the SDK's built-in table. Check packages/core/src/ledger/pricing.ts for the canonical source, or run usertrust pricing (--json for machine output) to print the table as resolved against your usertrust.config.json — input, output, cache-read and cache-write, the 1-hour write rate, and for claude-haiku-5-5 its higher per-request tier, with absent cache rates shown at inputPer1k, in $/MTok. It lists the models of the providers named in your config, or every table model when none are named.
Cache tiers and the fallback invariant
ModelRates carries optional fields beyond inputPer1k/outputPer1k:
interface ModelRates {
inputPer1k: number;
outputPer1k: number;
cacheReadPer1k?: number | undefined; // absent or undefined ⇒ prices at inputPer1k, never 0
cacheWritePer1k?: number | undefined; // absent or undefined ⇒ prices at inputPer1k, never 0
cacheWrite1hPer1k?: number | undefined; // 1-hour writes; absent ⇒ the dearer of cacheWritePer1k and 2 × inputPer1k
longPrompt?: LongPromptTier | undefined; // per-request prompt tier (built-in rows only)
}Absent means "no published rate," not "free." costFromRates resolves an absent (or
non-finite/negative) cache rate to the model's inputPer1k — this is the one and only rate
resolution site in the SDK. A model that omits cacheWritePer1k still bills cache-write tokens,
at the same rate as fresh input.
This is deliberately fail-safe: understating a bill is the dangerous direction (a budget that looks fuller than the real invoice), so an unmodeled cache tier defaults to the conservative price, never to zero. Never treat an absent field as a discount.
Fallback Rate
Models not in the pricing table are priced at the highest rate the table publishes ("fail dearest"). An unknown id over-counts visibly instead of under-counting silently:
| Direction | Rate (per 1K tokens) |
|---|---|
| Input | 250 UT |
| Output | 1250 UT |
| Cache write | 312.5 UT (5m) / 500 UT (1h) |
| Cache read | 250 UT (the input rate; no cache discount is assumed) |
These are the maxima over the table (today claude-mythos-preview, $25 / $125); a test recomputes them,
so a dearer row cannot be added without raising the fallback. A fallback-priced record carries
rateSource: "fallback" and unknown: true. An unrecognized model isn't known to be
Anthropic-shaped, so no cache-read discount is attached. Set unknownModelPolicy: "deny" to refuse
an unknown model instead of metering it. The fallback is the dearest rate the table KNOWS; it cannot bound a model the table does not list that costs more than every row in it (claude-mythos-preview was exactly that case before it got its own row). For a hard budget, unknownModelPolicy: "deny" is the guarantee.
Whether an unknown model is allowed to meter at this rate is governed by the unknownModelPolicy
config field ("fallback" | "warn" | "deny", default "warn"). "fallback" meters silently;
"warn" meters at the same rate and prints a once-per-process stderr warning per model; either way
the receipt carries meter.rateSource: "fallback". "deny" throws PolicyDeniedError
(unknown_model: <model> not in pricing table) before any PENDING hold is placed. Only cloud-scope
calls can be unknown: a model on a local endpoint never reaches the fallback rate — it resolves
through local.models (exact key, then longest trailing-* glob) and otherwise local.defaultRate
(default { inputPer1k: 0, outputPer1k: 0 }, which the 1-UT floor settles at exactly 1 nominal usertoken).
Model Matching
getModelRates() resolves a model id in this order:
- an exact row;
- the id with exactly one trailing date suffix stripped —
-YYYYMMDD(claude-haiku-4-5-20251001) or-YYYY-MM-DD(gpt-4o-2024-08-06) — then exact; - the fallback rate, flagged
rateSource: "fallback",unknown: true.
There is no prefix matching: claude-sonnet-5-5 is a different, separately priced model from
claude-sonnet-5, and a longer id that merely begins with a table key used to be billed at that
key's row while the receipt claimed an exact table match. The exact row is tried first because a
dated snapshot can cost more than its alias: gpt-4o-2024-05-13 is $5 / $15 per MTok against
gpt-4o's $2.50 / $10, so it has its own row and is never reduced to the alias. A dated snapshot
with no row of its own is metered at its base row, which assumes it is priced like its alias.
Residue (priced at the fallback, flagged): Gemini …-preview-MM-DD ids, a seven-digit or
non-numeric suffix, -fast, and Bedrock anthropic.…:0 / Vertex …@… ids. isModelPriced() is
stricter on purpose: it checks for an exact key (or custom rate) only, so a dated snapshot meters
at its base row but is not "priced" for a caller that must refuse what it cannot price exactly.
For an endpoint classified as cloud, an id written the way a gateway or cloud platform writes it (Bedrock, Vertex, OpenRouter, a -latest alias without a row of its own, or another case such as GPT-4o) is priced at the fallback rate, so its hold is larger too and a small budget can refuse the call. To refuse such a call instead, set unknownModelPolicy to "deny". To price one, set pricing to "custom" and add the exact id to customRates; a local endpoint ignores customRates and uses local.models and local.defaultRate. See LIMITATIONS.md section 16.
getModelRates("claude-fable-5") // exact match → { 100, 500 }
getModelRates("claude-fable-5-20260301") // dated snapshot → claude-fable-5 → { 100, 500 }
getModelRates("gpt-4o-2024-08-06") // dated snapshot → gpt-4o → { 25, 100 }
getModelRates("gpt-4o-2024-05-13") // exact row, priced above its alias → { 50, 150 }
getModelRates("claude-fable-5-1") // its own row → { 100, 500, cache read 2.5 }
getModelRates("claude-opus-5-fast") // unknown → fallback → { 250, 1250 }Functions
getModelRates, isModelPriced, costFromRates, estimateCost, estimateInputTokens,
PRICING_TABLE_VERSION, resolveAppliedRates, resolveRates and the ModelRates type are exported
from the package root (import { ... } from "usertrust"). PRICING_TABLE, FALLBACK_RATE,
effectiveCacheWriteRate and effectiveCacheWrite1hRate are not on the root — import them from the
usertrust/pricing subpath.
getModelRates()
function getModelRates(model: string, customRates?: Record<string, ModelRates>): ModelRatesLook up the four-tier rates for a model. An exact key in the optional customRates map wins first; then an exact table row, then the id with one date suffix stripped, then the fallback rate (never a prefix match).
costFromRates()
function costFromRates(
rates: ModelRates,
inputTokens: number,
outputTokens: number,
cacheReadTokens?: number, // default 0
cacheWriteTokens?: number, // default 0; the TOTAL written (5m + 1h)
cacheWrite1hTokens?: number, // default 0; the 1-hour SUBSET of cacheWriteTokens
): numberCompute usertoken cost across all four tiers from an explicit ModelRates. The four counts are
expected to be disjoint — cached tokens must already be separated out of inputTokens before
this is called, or they are double-counted. Absent cache rates resolve to inputPer1k (see Cache
tiers and the fallback invariant); the result is floored
at 1 usertoken, same as estimateCost().
// 1,000 fresh input + 500 output + 2,000 cache-read tokens on claude-fable-5
costFromRates(getModelRates("claude-fable-5"), 1000, 500, 2000, 0)
// → Math.max(1, Math.ceil((1000 * 100)/1000 + (500 * 500)/1000 + (2000 * 10)/1000))
// → Math.max(1, Math.ceil(100 + 250 + 20))
// → 370 UTEach tier is computed as (tokens × ratePer1k) / 1000 — multiply before dividing. This is the
same order the receipt schema publishes as
ceil(sum(counts × rates / 1000)), and it is load-bearing rather than stylistic: in IEEE-754 the
divide-first form (tokens / 1000) × ratePer1k can land a ulp above an integer (560 cache-write
tokens at 12.5/1k give 7.000000000000001), which Math.ceil then rounds to a whole extra
usertoken. Reconciling against a receipt with the published formula reproduces the charged cost
exactly, on every input.
estimateCost()
function estimateCost(
model: string,
inputTokens: number,
outputTokens: number,
customRates?: Record<string, ModelRates>,
): numberTwo-tier convenience wrapper around costFromRates() for callers that don't have a cache split —
cacheReadTokens/cacheWriteTokens default to 0. The result is always at least 1 (floor to
prevent zero-amount transfers in TigerBeetle).
// 1,000 input tokens + 500 output tokens on claude-fable-5
estimateCost("claude-fable-5", 1000, 500)
// → Math.max(1, Math.ceil((1000 * 100)/1000 + (500 * 500)/1000))
// → Math.max(1, Math.ceil(100 + 250))
// → 350 UTestimateInputTokens()
function estimateInputTokens(messages: unknown[]): numberEstimate the input token count from a messages array before the LLM call. Uses a heuristic of approximately 4 characters per token with a 1.5x safety margin so the PENDING hold exceeds actual cost in the majority of cases.
This function handles:
- String content and multi-part content blocks
- Nested arrays (tool result payloads)
- Per-message overhead (role, structure)
- Tool-call overhead
Returns at least 1. This estimate never models cache state — see Documented approximations.
ModelRates
interface ModelRates {
inputPer1k: number; // usertokens per 1,000 fresh input tokens
outputPer1k: number; // usertokens per 1,000 output tokens
cacheReadPer1k?: number | undefined; // usertokens per 1,000 cache-hit tokens; absent or undefined ⇒ inputPer1k
cacheWritePer1k?: number | undefined; // usertokens per 1,000 cache-creation tokens; absent or undefined ⇒ inputPer1k
cacheWrite1hPer1k?: number | undefined; // 1-hour cache writes; absent ⇒ max(cacheWritePer1k, 2 × inputPer1k)
longPrompt?: LongPromptTier | undefined; // a per-request prompt tier (built-in rows only)
}
interface LongPromptTier {
thresholdTokens: number; // a prompt OVER this many tokens pays `rates` for every category
rates: Omit<ModelRates, "longPrompt">;
}PRICING_TABLE_VERSION
const PRICING_TABLE_VERSION: string // e.g. "2026-11-02"Date-stamped version of the built-in PRICING_TABLE, bumped whenever any entry's rates change.
Recorded on every settled LLM receipt (receipt.pricing.tableVersion; governed non-LLM action receipts meter no tokens and omit the pricing block) alongside the resolved
rates (receipt.pricing.appliedRates) so a metered cost can be reproduced exactly against the table
version that priced it, independent of the SDK version currently installed.
Hold sizing and the cache-write premium
The PENDING hold reserves the input leg at the dearest write rate the call can produce, not
inputPer1k alone. A cache write can price above plain input — Anthropic's 5-minute write is
1.25x, the 1-hour write 2x — so sizing the hold off inputPer1k alone understates the reserve for
any call that turns out to write to cache. The hold covers the worst case this request can
produce:
- the governed
trust()path reads the request: it reserves the 1-hour rate only when the request declares a 1-hour TTL (acache_controlblock withttl: "1h"anywhere in it), and otherwise holds atmax(inputPer1k, effectiveCacheWriteRate(rates))exactly as before; - the headless
authorize()path runs before the call and cannot see the TTLs, so it reserves the dearest write rate (the 1-hour one) for the input leg and for any statedestimatedCacheWriteTokens. Only a row that publishes a 1-hour rate reserves it, so a model with no 1-hour tier holds as before; operator-owned rates (customRates, local rates, the fallback) with nocacheWrite1hPer1kreserve the derived 2x input, as their 1-hour tokens are metered at that rate.
Consequence: holds on cache-writing workloads run roughly 25% fatter than an input-only hold
would size them, and headless holds on Anthropic models run about 60% fatter on the input leg
(2x input against 1.25x), so a 402 near the budget comes sooner. The trust() path pays the extra only
for a request that declares a 1-hour TTL. Warm (cache-hit-heavy) calls settle well below the hold and release the
difference — this is conservative, not wasted budget. A caller supplying an exact
estimatedInputTokens for a call that turns out cache-cold can still see the settle capped at the
hold (settlement_shortfall, see AGENTS.md's Money invariants) if the actual write premium
exceeds even the widened reserve.
Documented approximations
Reconciliation against a provider's own invoice is approximate, not exact — a receipt's cost
exactly reproduces usertrust's own configured metered cost (counts × appliedRates, per-call
ceil, 1-UT floor), but not necessarily the provider's bill line-for-line, because:
1-hour cache writes are priced at the 1-hour rate only when the provider reports the 5m/1h split
(a flat write total, or a host with no TTL split, bills at the 5-minute rate); long-context, service-tier, regional, modality, and cache-STORAGE charges (Gemini
hourly storage, prompt-size-dependent rates; gpt-5.6-sol's >272k long-context uplift, 2× in / 1.5× out) not modeled — fixed
per-model rates by design, except claude-haiku-5-5 and the xAI rows, which are priced per request by prompt length
(see "Per-request prompt tiers" at /docs/api/pricing); fast mode is not priced (Opus 5.5 fast is $8 / $40, Opus 5 and
Opus 4.8 fast $10 / $50; speed is a usage field, not a model id); per-call ceil + 1-UT floor
differs from provider-side aggregation. Estimates never model cache state.
Cost Estimation Flow
During the two-phase spend lifecycle, costs are estimated twice:
-
Before the call (PENDING):
estimateInputTokens()produces a conservative input estimate. Combined with the output cap the request names for the output estimate —trust()readsmax_tokenson Anthropic;max_output_tokenson OpenAI Responses;max_completion_tokens, elsemax_tokens, timesnon OpenAI chat;config.maxOutputTokenstimescandidateCounton Google (with no Google cap, 4096 and never less than the thinking budget); any other call with no cap holds 4096; the headless controller usesmaxOutputTokens ?? 4096— and the cache-write premium guard above, the SDK calculates the hold amount. The 1.5x safety margin (plus the write-premium guard) means the hold usually exceeds actual cost. -
After the call (POST): Actual token counts from the provider response (or accumulated from stream chunks), split into all four tiers, produce the real cost via
costFromRates(). The difference between the hold and the actual cost is released back to the available budget.