Skip to main content

model-prices

LLM API prices, today's or as they were at any point in time. Pricing past usage at today's rates misstates it whenever a price changed: GPT-5.6 Sol cost $5/$30 per million input/output tokens until August 21, 2026, and $4/$20 for the three months after. This package answers "what did this request cost at API prices when it ran?"

Status: work in progress. Versions before 0.1 may change the data format and API without notice.

import model_prices

model_prices.cost(
    "gpt-5.6-sol",
    input_tokens=12_000,        # uncached input only
    cache_read_tokens=180_000,
    output_tokens=900,
    at="2026-08-20T14:00:00Z",
)

model_prices.rates("claude-opus-5-5")  # current rates, per million tokens
model-prices rate gpt-5.6-sol --at 2026-08-20
model-prices rate "Gemini 3.5 Flash (High)" --json

Install

Requires Python 3.11 or newer.

uv add model-prices

Where the prices come from

Prices come from the git history of models.dev, an open catalog of model metadata that records each model's price in one TOML file per provider. Every commit on its main branch that changed a tracked model's price becomes an entry effective from that commit's time. The tracked providers are the labs that sell their own models: Alibaba, Anthropic, DeepSeek, Google, Moonshot AI, OpenAI, xAI, and Z.ai.

models.dev sometimes records a change days after the provider made it, or lists a wrong price for a while. corrections.toml overrides those periods, and every correction cites its source. research_corrections.toml adds corrections generated from agent research into every recorded change, each verified against quotes from its sources (see research/README.md); hand corrections take precedence. A correction without an end date names the models.dev values it replaces and stops applying as soon as models.dev records anything else, so it cannot outlive a later fix or price change.

Rates.valid_from_basis says how a start date was found: models.dev commit dates usually lag the provider's real change by days, while documented dates come from a correction's cited source.

Usage from before a model's first recorded price is priced at that first price, because models.dev often adds a model after its launch. Rates.valid_from is then later than the requested time, which a caller can check to reject implausible times, such as a zero timestamp. Usage after data_as_of(), the date of the models.dev commit the data was built from, assumes no price changed since.

Pass the time the provider billed the request as at. Providers do not document whether a request that spans a peak boundary bills at its start or its end; agent harnesses usually report completion times, which is a reasonable choice.

Each entry keeps input, output, cache read, and cache write rates, long-context tiers, and alternate modes such as fast mode. A tier applies when one request's whole prompt, meaning uncached input plus cache reads and writes, exceeds the tier size. A missing cache price falls back to the input price.

Time-of-day pricing

Some providers price by time of day. schedules.toml records each version of a provider's rules with the dates it applied: either peak windows that multiply the recorded rate, or off-peak windows that discount it for listed models. Rates.period says which applied: "peak" or "off_peak", "standard" outside a discount window, or None when no time-of-day rule applies.

Holiday calendars record the last date they cover, and model-prices check fails 45 days before that date so the next year's holidays are added in time. DeepSeek is the one provider with such pricing so far. From 16:30 UTC on February 26, 2025 until 16:00 UTC on September 5, 2025, it took 50% off DeepSeek-V3 (deepseek-chat) and 75% off DeepSeek-R1 (deepseek-reasoner) from 16:30 to 00:30 UTC daily. Since 16:00 UTC on August 16, 2026, its peak hours have been 01:00-04:00 and 06:00-10:00 UTC on weekdays other than Chinese public holidays, at twice the off-peak rate. The pricing page added the weekday and holiday exceptions in late August and mid-September without an announcement; model-prices applies the current rule from the start of peak pricing. DeepSeek pricing history records the evidence for each 2026 date. DeepSeek decides the period by when a request completes, so pass the completion time as at where it is known.

Official price checks

model-prices check fetches each supported provider's official pricing page, reads it with a parser written for that page's table layout, and compares every price with the rate model-prices uses today. It covers Anthropic, DeepSeek, Google, OpenAI, xAI, and Z.ai. Each price is reported as:

  • ok: models.dev and the official page agree.
  • corrected: models.dev differs, but a correction in corrections.toml or research_corrections.toml supplies the official price.
  • mismatch: model-prices differs from the official page. The command exits with status 1.
  • untracked: the page lists a model that models.dev does not price.

Page model names must match models.dev ids exactly, with no suffix removal, so a dated model is never compared with a different undated one. For DeepSeek, peak and off-peak prices are checked at the next hours the schedule classifies as each, and the peak-hour rule on both the English and Chinese pricing pages must match the wording recorded in schedules.toml, so a change to the hours, multiplier, or exceptions fails the check. Google's dated future prices are read for the check date. A page that yields no prices fails the check, because its format has changed.

model-prices check --genai-prices also scores Pydantic's genai-prices against the same official prices, reading its data.json from GitHub, or from a file or checkout given as --genai-prices PATH. It lists each price genai-prices gets wrong and ends with how many official prices each source lists correctly, wrongly, or not at all. Its disagreements never change the exit status. genai-prices is read by exact model id only: it also matches names by prefix, which would give a model it lacks, such as Claude Opus 5.5, an older model's prices. Z.ai is not compared, because genai-prices' Zhipu entry is the mainland China API. On 2026-10-01, models.dev listed 342 official prices correctly and 7 wrongly; genai-prices listed 173 correctly and 40 wrongly, almost all from missing price cuts such as GPT-5.6's.

Not modeled

model-prices prices standard synchronous requests. It does not model batch, flex, or priority service tiers; Anthropic's separate 1-hour cache-write price, which it treats as the 5-minute price; regional or data-residency surcharges; storage charges for cached context; or tool fees such as web search. Modes listed by models.dev, such as fast mode, are available through mode. While a correction applies, a mode's price is the corrected price scaled by the mode's ratio to models.dev's standard price at that time, since corrections record standard prices only.

Where a model has no cache-write price, cache writes are priced as input. That matches providers whose caching is automatic and bills the first, cache-filling request as normal input, such as Google's implicit caching, DeepSeek, xAI, and Z.ai. Providers that charge more for writing a cache list a cache-write price in models.dev.

Long-context tiers apply when a request's prompt exceeds the tier size. Providers word the boundary differently, such as Google's "> 200k" and xAI's "≥ 200k", so a prompt of exactly the tier size may price one tier off.

Rates.breakdown() returns a request's cost by token type and the tier it reached, for callers that report either.

Model names

resolve() maps the names that logs and agent harnesses use to models.dev ids. It lowercases the name and normalizes display names such as Gemini 3.5 Flash (High) and dotted Claude versions such as claude-sonnet-4.5. It reads a provider/ prefix or the provider argument as a hint, and when the full name is unknown it removes context markers such as [1m], the -build suffix that xAI's subscription endpoint adds to Grok versions such as grok-4.6-build, effort suffixes such as -high, and date suffixes such as -20251001 or -2026-04-23. Rates.removed_suffix records any text removed this way, and resolve_details() returns it, so a caller can tell when a price belongs to a related name: -max is both an effort level and part of some model names, such as qwen3.8-max. A model is looked up at its own lab before other labs that also serve it. A lab model name resolves to the first-party API id that serves it, using models.dev's base_model links and preferring ids that are not deprecated: DeepSeek serves deepseek-v4.1-flash as deepseek-flash, so that name gets deepseek-flash's price. aliases.toml holds the few names that need an explicit mapping. Unknown models return None rather than a guessed price.

Current prices for past requests

rates() and cost() take prices_at to price a request from a different date's price list. The time-of-day rule in force at at, the time the request ran, still applies: a request made in a 2025 DeepSeek discount hour keeps its discount on today's prices. Pricing every past request with prices_at set to today compares usage across weeks without price changes appearing as usage changes.

Prices over a span

rates_between(model, start, end) returns each distinct rate in effect over a span with the time it begins. Use it for usage known only to fall within a span, such as a run with a start and finish but no per-request times: a single entry means one price covered the whole span. It finds changes from price history, corrections, and time-of-day schedules exactly, including peak windows and holidays. Rates.price_key() compares prices without provenance, so a correction and the models.dev entry that later records the same prices compare equal.

Subscription plans

plan(provider, plan_id, at=None) returns a subscription plan's monthly price from plans.toml, keyed by the plan name each lab's usage tools report, such as max_20x for Claude or lite for the GLM Coding Plan. A plan sold in several price tiers gets one entry per tier, with the price in its id and name, such as ultra_200 for Google AI Ultra $200 or pro_500 for ChatGPT Pro $500. When a usage tool reports only the untiered name, that name has no entry, except that ChatGPT's pro keeps its original $200 price.

Recording what was used

pricing_basis() returns an identifier such as model-prices-0.0.1+models.dev@e2bf2e470a1b+synced@2026-09-30+data@3f1c09a2b7de, naming the package version, the models.dev commit its data came from and that commit's date, and a hash of all its data files, so any change to prices, corrections, schedules, or aliases changes it. Store it next to computed costs.

Updating prices

A daily workflow clones models.dev, rebuilds src/model_prices/data/prices.json with model-prices update, and opens a pull request when a tracked price changed. It then runs model-prices check and fails when an official price disagrees; fix that with a correction, or with a models.dev pull request when models.dev is wrong. Before merging, check each changed model's effective date against the provider's announcement and add a correction when models.dev recorded the change late.

To rebuild locally:

git clone https://github.com/sst/models.dev.git /tmp/models.dev
uv run --locked model-prices update /tmp/models.dev

Development

uv run --locked python -m unittest discover -s tests

License

The code and the corrections are MIT licensed. src/model_prices/data/prices.json is derived from models.dev, whose MIT license is in src/model_prices/data/LICENSE.models.dev. The test fixture tests/fixtures/genai-prices.json is an excerpt of genai-prices, whose MIT license is in tests/fixtures/LICENSE.genai-prices.

Metadata

Release files for model-prices 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for model-prices 0.0.1
File Size Uploaded
model_prices-0.0.1.tar.gz 60.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for model-prices 0.0.1
File Interpreter ABI Platform
model_prices-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 112.0 kB

Release files / model_prices-0.0.1.tar.gz

Download URL model_prices-0.0.1.tar.gz
Size 60.0 kB
Tags Source
SHA-256 checksum
How to use checksums
9fe173a05b2d0aca1ef2a6eb0b23328a492901ce4e0a5eb6eebb2560505975b5
BLAKE2b-256 checksum
How to use checksums
af3a94d407acaad8501ea7b719591b1e9b0cb03e8d379b8a96b7f91c40265f4f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / model_prices-0.0.1-py3-none-any.whl

Download URL model_prices-0.0.1-py3-none-any.whl
Size 52.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ca01abd995f80cb004e760bb09423a196ce967e3e9fa0dded22f139d63951ad3
BLAKE2b-256 checksum
How to use checksums
bde0dca85d588773471ce59c01bcfc01e7dbe6758f8ba88af490ca2ea61a1f36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page