prices_checked is set by a human. A maintainer confirms a rate against the provider’s own pricing page and writes that date into the provider YAML. The freshness bot never writes it, not on a drift fix and not on a match. At build time the date is copied into provenance.last_verified, which is the input every signal below is derived from.
Status
verification_status is derived at load time, not stored in the data:
imported and seed are never reported as stale: stale implies the price was verified at some point.
The provider tables on this site show three of the four (verified, imported, seed) next to the date a human last confirmed the rate. They deliberately never show stale. Staleness depends on today’s date, and those pages are files committed to the repository, so a stale badge baked into one would start lying the day after it was written. Read the date and judge, or compute the live answer with model_freshness from the Python package.
Confidence
confidence is a coarse high / medium / low label. It is not a probability and not a score. A calibrated score was deferred until there is observed bot-accuracy data to calibrate against. The rule is exactly:
high: status isverified.medium: status isstale, or status isimportedand the verifier agents were unanimous (agent_votes.total > 0andapprove == total).low: everything else, meaningseed, andimportedwithout a unanimous agent vote.
verified price drops to stale (and high to medium) once it passes the threshold, with nobody editing the data. staleness_threshold_days is set per provider and defaults to 60.
Estimated rates
Status answers is this rate current. It does not answer is this rate the meter, and those are different questions. A rate can be verified this morning against the vendor’s own page and still not be what they charge you. Some vendors publish two numbers for one model in two units, and bill on only one of them. OpenAI pricesgpt-4o-transcribe per token, and also prints $0.006 / minute in a column it heads Estimated cost, derived from an assumed speech density it does not publish. Both numbers are on the page. Only the token rate is on the invoice.
Where the catalog carries such a number, provenance.estimated_fields names the fields it applies to, and the provider tables mark the row estimated:
The flag is per field, not per model, because the split is per field: on
gpt-4o-transcribe the token rates are billed and only input_audio_kseconds is estimated.
Worth seeing side by side on the OpenAI STT page: whisper-1 and gpt-4o-transcribe both read $0.006 per minute. For whisper-1 that is the meter and the conversion is exact. For gpt-4o-transcribe it is an estimate of a per-token bill. Same number, different standing, and the marker is the only thing that says so.
Calling a model with usage it has no rate for is a third case again, and the library reports it: PriceCalculation.unpriced_usage names any Usage field that found no meter, so a total_price of zero can be told apart from a free call.
How LLM rates are checked
LLM rates are cross-checked against four external aggregators: Helicone, OpenRouter, LiteLLM, and Simon Willison’s llm-prices. That pipeline is a local tool a maintainer runs (make get-update-price-discrepancies); each discrepancy is then resolved by hand.
LLM models do not carry a per-model verification status for this reason. They are covered by aggregator cross-check rather than per-model verification, so a status on an LLM row would misread as low confidence. Every other category carries one: STT, TTS, S2S, and VAD.
How voice rates are checked
Those aggregators do not carry TTS and STT models, so voice rates have no cross-check to fall back on. Instead, a maintainer-triggered GitHub Action re-verifies each voice rate against that model’s ownpricing_source_url: a headless browser renders the page and an LLM extracts the current rate. Deterministic guards (quote must be a literal substring of the page, number must match the quote, right row, USD, right unit class, no implausible magnitude jump) run before anything is proposed.
When a rate has drifted, the job opens or refreshes a single rolling PR on the bot/pricing-freshness branch. It is manual only: workflow_dispatch, no schedule, so it costs nothing until someone runs it. It is never auto-merged. Every proposed change is reviewed by a human, and that human sets prices_checked when merging, which is what resets the staleness clock. A run where every rate matches produces no diff and no PR.
Staying current
The price data ships inside the installed package, so it ages with your pinned version. The Python package can refresh it at runtime withUpdatePrices, which is explicitly opt-in: it downloads prices/data.json from GitHub once on start and then hourly.
UpdatePrices is process-wide, which matters in tests
UpdatePrices installs the downloaded snapshot into module-level state that every later calc_price in the process reads, and it does so from a background daemon thread. That is the point of the feature, but it has a consequence worth knowing before you debug it the hard way: once it has run, a call somewhere else in your test suite can see downloaded prices rather than the ones bundled with your pinned version, and the value can change between two calls that look identical.
Use it as a context manager and it cleans up after itself. stop() clears the snapshot after joining the thread, so an in-flight download cannot reinstall one behind you: