tokenstat
tokenstat
Reading your usage

Where model prices come from

György
Reviewed by
György
Updated Oct 19, 2026 6 min

Every page in the model catalog puts one model's API prices from up to four sources side by side. This guide covers where each number comes from, how the sources are joined into one row, which price leads the page and why, and what to do when a number is wrong.

The four sources

Source What it contributes Read
LiteLLM The open model_prices_and_context_window.json file in the LiteLLM repository: list rates per model id. It is also the price list the CLI downloads. Hourly
OpenRouter OpenRouter's public models API: the rate OpenRouter charges for each model it routes, context length, and for some models Artificial Analysis scores. Twice a day
models.dev The models.dev catalog: one entry per provider and model, with rates, context, release date, knowledge cutoff and capabilities. Twice a day
tokenstat seed A short file I maintain by hand. Each entry is a list rate copied from the lab's own pricing page or launch post, plus models no feed carries yet. When a lab changes a price or ships a model

All rates are USD per million tokens. The catalog is rebuilt from whatever copies are on hand every hour, and again whenever a feed refreshes.

No feed is taken on trust:

  • A refresh that fails, times out, or comes back larger than a size cap leaves the last good copy in place.
  • A refresh that moves an existing model's input or output rate by more than half is rejected. A broken feed is far more common than a real price halving overnight.
  • Two exceptions keep the catalog from freezing. Any move is accepted once the current copy is more than a day old. For OpenRouter and models.dev, a handful of moves on a large catalog is also accepted as genuine price changes.

What the date on a model page means

"Rates as of" is the UTC day the catalog was last rebuilt. It is not the day the lab set the price. If a feed has not refreshed in two days, the models index says which one and since when.

How rows merge

Each source names models its own way: anthropic/claude-opus-5, claude-opus-5, amazon-bedrock/anthropic.claude-opus-5. The merge turns every id and alias into a join key (lowercase, with dots and underscores turned into hyphens) and joins on that.

  • Order. models.dev goes first, then OpenRouter, then LiteLLM, then the seed. OpenRouter joins only on full ids and its canonical slugs, because a bare model name collides across providers.
  • First writer wins. Once a key points at a row it never moves to another one, so a later source cannot pull an id onto the wrong model.
  • One listing per source. Each source's price becomes its own listing on the row. When two feeds report the same host at the same input and output rate, that collapses to one listing, and the row keeps a record of both feeds.
  • Gateway copies fold in. A reseller that republishes a lab's model under its own prefix becomes a listing on one row for that model, normally under the lab's own id, not a near-duplicate page.
  • Specs. Context length takes the largest value any source reports. Capabilities (tools, vision, reasoning) are the union of what the sources say.
  • Names. A seed name wins over feed names, which are sometimes the host's label rather than the model's.

What a first-party pin is

A pin is a seed entry with input and output rates I copied from the lab's own pricing page or launch post. It becomes a listing with the source tokenstat, and three rules follow from that:

  • It is never folded into another host's listing, even at the same rate, so the reference price always shows under its own name.
  • It is listed first in the Sources table.
  • It leads the page. The List input and List output figures at the top, the page title and the search snippet all use it.

When the pin's source is on the lab's own domain, the model page links it next to the date ("list price from anthropic.com"). A pin whose only source is a news report shows no link until the lab publishes the rate itself.

A page without a pin leads with its cheapest listing instead, labeled with the source it came from.

Why batch and reseller rows do not lead

The cheapest listing for a model is rarely the price the lab charges. Usually it is one of these:

  • A batch route. Labs discount asynchronous batch requests, often by half, and some feeds list the batch route as its own model (:batch). Those routes fold into the base model's row rather than getting a page of their own.
  • A reseller or gateway with its own markup or discount, a promotional rate, or a regional price.
  • A free listing. $0 listings are hidden by default. The Sources table says how many were hidden and links to show them.

All of these stay in the table, because the spread is worth seeing, and the lowest one keeps its "cheapest" badge. They do not get to stand in for the list price at the top of the page.

Where benchmark scores come from

Scores are sparse on purpose. Each one is one of three kinds, and the "i" next to a score on a model page names which:

  • Arena. Community-vote Elo from the Arena AI text, code, vision and agent leaderboards, read from open daily snapshots twice a day.
  • Artificial Analysis. Index scores, only where OpenRouter's model feed embeds them. I do not scrape Artificial Analysis directly.
  • Curated. Figures I enter by hand from launch tables, system cards and eval write-ups, mostly the lab's own, for models no feed scores yet. A figure goes under an existing column only when it is the same eval at the same version. A different version gets its own column or stays out.

A measured feed never overwrites a curated value. One score row is attached to every listing of the same model across gateways, matched on the model's identity rather than on any one host's id. A refresh where an existing model's score moves by more than half is rejected, and the previous board stays. Full boards and credits are on benchmarks.

Report a wrong number

Every model page has a Report incorrect data button at the bottom. Pick what is wrong (wrong price, wrong specs, something missing, out of date, wrong page entirely, or something else) and, if you can, add the right value or the page where the lab publishes it. That last part is what lets me fix a pin quickly.

Reports are anonymous. Nothing about you is stored, only the page, the reason and your note, and they come straight to me. A wrong pin is mine to fix. A wrong feed listing is corrected when the feed corrects it, and until then the pin, where there is one, still leads the page.

Check the data yourself

The whole merged catalog is public JSON at /api/v1/catalog/current. Each listing carries its source (litellm, openrouter, modelsdev or tokenstat) and, when it was collapsed, the other feeds that reported it. The sources block at the top gives each feed's model count and fetch time, and the date the pins were last reviewed.

For how the published prices turn into the cost figures in your own usage, see why your numbers disagree with a vendor's dashboard.

Human-led and verified · AI-assisted content · AI tools may help draft, edit, maintain, and improve grammar or clarity. Nothing is published automatically; every change is reviewed by the human maintainer.