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.
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.