API

The whole catalogue as static JSON files: no key, no server, no rate limit beyond the host's. Files are rebuilt with each data refresh. Data generated 2026-10-20 03:37 UTC.

Free JSON feed

Stable URLs under /v1/, free to fetch with no key or sign-up. Poll them after each refresh (every 6 hours), or subscribe to the Atom feeds.

/api/v1/models.json
Every model with its cheapest headline price, price range and capabilities
/api/v1/models/<creator>/<model>.json
One model with every endpoint and price, e.g. anthropic/claude-sonnet-4
/api/v1/history/<creator>/<model>.json
Price history: the cheapest direct price at each refresh where it changed, e.g. deepseek/deepseek-v4-pro-0813. Index: /api/v1/history/index.json
/api/v1/plans.json
Flat-fee subscription plans, verified by hand
/feed.xml
Atom feed of every catalogue change. Per model and per plan: /feeds/models/<creator>/<model>.xml, /feeds/plans/<provider>/<plan>.xml (linked from each page that has changes)

Licence. The data merges third-party sources, each under its own terms, listed per build in manifest.json. Credit models.dev and LiteLLM (MIT) and Epoch AI (CC BY 4.0) when you redistribute; OpenRouter-derived values are marked unverified. Details under Attribution below.

Files

URLWhat it isSize
/api/v1/models.jsonAll models, slim rows2.3 MB
/api/v1/providers.jsonProviders and aggregators265 KB
/api/v1/creators.jsonCreators17 KB
/api/v1/manifest.jsonSources, licences, counts, checksums
/api/v1/models/<creator>/<slug>.jsonOne model with all its endpoints and prices. Example: anthropic/claude-sonnet-42,612 files
/api/v1/schema/*.schema.jsonJSON Schema (draft 2020-12) for every file type, e.g. model.schema.json
/feed.xmlAtom feed of catalogue changes (see Changes)

Model detail files are large in total, so fetch the ones you need and use the checksums in manifest.json for caching.

Using it

curl -s /api/v1/models.json | jq '.items[0]'
curl -s /api/v1/models/anthropic/claude-sonnet-4.json \
  | jq '.endpoints[].pricing.base'

Prepend the site's origin. Unknown is not no: null in a capability, limit or price means no source reports it. Do not render it as “No” or as zero.

Attribution

If you redistribute this data, credit models.dev and LiteLLM (both MIT) and show the “last refreshed” time per source from manifest.sources[].fetched_at. The API marks each source's redistribution status in manifest.sources[].redistribution. OpenRouter-derived values are marked "unverified" because its reuse terms are still under review. Full list: About and sources.

Version policy

The /v1/ prefix is the major version. Within it, fields, files and enum values may be added, so ignore what you do not know. A removal, rename or meaning change ships as /v2/, and v1 stays for an announced period. Questions or bugs: GitHub issues.

Reference

Rendered from docs/API.md in the repository.

Static files generated by pipeline/src/api.ts (npm run api, or npm run derive) into data/api/v1/. There is no server: host the folder as-is. Files are minified, keys are sorted recursively, rows are sorted by id, and generated_at is copied from the merged manifest, so the same input produces byte-identical output. Every file is validated against its zod schema (pipeline/src/schema.ts, pipeline/src/api.ts) before it is written.

pathcontents
/v1/models.json{schema_version, generated_at, count, items[]}; slim rows: id, name, creator, type, release_date, context, modalities{input,output}, capabilities, provider_count, cheapest{input_mtok,output_mtok,endpoint_id,provider_id,blended_mtok,ratio}, open_weights, quality (1.7.0)
/v1/redirects.json{..., items: [{from, to, reason, since}]}: model ids that no longer exist and the id that replaced them (e.g. folded *-batch models). Clients holding an old id should follow to
/v1/models/<creator>/<slug>.json{schema_version, model, endpoints[]}: the full Model and all of its Endpoints (with sources, alts, flags, snapshots, source_refs, performance)
/v1/providers.json{..., items: Provider[]}
/v1/creators.json{..., items: Creator[]}
/v1/plans.json{..., items: Plan[]}: curated subscription plans (docs/PLANS.md). Not token prices; never converted
/v1/plans/<provider>/<slug>.json{schema_version, plan} (plan id = <provider>/<slug>)
/v1/history/<creator>/<slug>.json(1.7.0) price history of the model's headline price (pipeline/src/series.ts); see "Price history" below
/v1/history/index.json(1.7.0) {schema_version, generated_at, boundary, models, changed[{model_id, changes, last_change}]}: models with a series, and those whose cheapest pair moved (newest change first)
/v1/manifest.jsonschema_version, api_version, generated_at, sources[] (id, url, license, fetched_at, status, rows, redistribution, attribution), excluded_sources, counts, files[] (bytes+sha256), model_files{count,bytes,sha256}, plan_files, history_files (1.7.0, same scheme; history/index.json is in files[])
/v1/schema/*.schema.jsonJSON Schema (draft 2020-12, generated with z.toJSONSchema) for model, endpoint, provider, creator, manifest, model-summary, model-detail, and the three list files, plus plan, plan-detail, plans-list, redirects-list, history, history-index (1.7.0)

Field meaning is defined in docs/SCHEMA.md; this API publishes the merged records unchanged (only the slim list rows are a projection). provider_count excludes aggregators (gateways); gateway pricing is published separately (see Gateways below). cheapest (schema 1.2.0) is one real endpoint's input/output pair, the headline-eligible endpoint with the lowest blended cost at 3 input : 1 output tokens (blended_mtok, ratio: "3:1"), identified by endpoint_id / provider_id; null when no endpoint is eligible. Before 1.2.0 it was the separate minimum of input and of output, possibly from different providers. creator in list rows is the creator_id. A model's file path is its canonical id (<creator>/<slug>); ids are validated to be path-safe at build time. Dated snapshots and aliases are never separate models; different model versions (for example v4-flash vs v4-pro) are different ids.

Gateways (additive, schema 1.x)

A gateway (aggregator) is a route to a model, not a provider of it. List rows (models.json) additionally carry price_range, cheapest_gateway and provider_count_gateways; model files carry the same on model plus route_kind, routes_to, gateway on each endpoint, and fees, gateway_stats on providers (providers.json). Definitions: docs/SCHEMA.md#gateways. All are nullable/defaulted, so older readers keep working. With --exclude-source, these are recomputed from the endpoints that remain.

Headline eligibility, vetting and batch rows (schema 1.2.0)

Every endpoint carries headline_eligible (boolean) and vetting (lab|cloud|inference|curated|reseller|gateway); model price_range and cheapest are computed over headline-eligible endpoints only. Use headline_eligible for any "from $X" or "cheapest" display; ineligible rows are still real listings, and rows flagged unverified-cheap: ... or price-sanity: ... should be labelled as unverified. Batch-API prices are endpoint rows with variant.service_tier: "batch", price_kind: "batch" and ids ending in batch (<model>@<provider>#batch, #<region>.batch): never compare them with standard prices. Rule details: docs/SCHEMA.md "Headline eligibility", "Price sanity", "Batch API rows", "Redirects".

Plans and price kinds (additive)

manifest.counts.plans and manifest.plan_files ({count, bytes, sha256}, same scheme as model_files; per-plan files are not in files[]). Endpoint files carry price_kind, price_kind_note, retires_in_days; model files plan_ids, retires_in_days; providers plan_count. Treat price_kind != "paid" as "no price": never display it as a bare $0 or compare it. unpriced means no pricing object (including non-token models whose only source price was a $0 token artefact).

Plan fields (schema 1.5.0)

  • plan.includes.model_ids_inferred: model ids the plan may include, resolved from its free-text model_families (a family word such as "Sonnet" -> the creator's newest current model of that family; an explicit name such as "GPT-6.1 Sol" -> that model; retired models never). Not a vendor statement: show it apart from model_ids_verified ("may include").
  • plan.price: seat_minimum, student {amount_usd, original, note}, regional[], tax_inclusive, pricing_model (flat | seat | seat_plus_usage | contact_sales | usage; seat_plus_usage = the price is a seat fee and usage is billed on top, e.g. Claude Enterprise "Seat $20 + usage at API rates"), and fx {rate, currency, date, source_url} when amount_usd was converted from original (indicative; the vendor's price is original). fx: null means the vendor states USD.
  • plan.limits.items[]: reset (rolling | fixed | null), at_limit (overage | throttle | downgrade | blocked | wait | null); plan.limits.overage_rate {amount_usd, unit, text} (amount_usd null when stated only in words, e.g. "at API rates").
  • plan.also_sold_by[]: the same subscription sold under another provider's name (e.g. xAI's X Subscription on cursor.com); plan.provider_type may be app.

Lifecycle and announced price changes (schema 1.3.0)

deprecation_date_kind ("firm" | "not_before" | null) on models and endpoints qualifies deprecation_date: not_before is a floor ("retirement not sooner than <date>", Anthropic): the model is still active, the date never means deprecated, and it should be shown as "not before <date>" even after it passes; firm is the vendor's stated retirement date; null is the source's date as stated. A model-level deprecation_date comes only from the creator's own source (a curated statement or the creator's first-party endpoint) or is the latest endpoint date when every endpoint is deprecated; one provider's retirement is only on that provider's endpoint. Endpoint pricing.scheduled[] ({kind: "promo_end"|"price_change", current_until, effective_from, prices, source_url, verified_on}, absent when none) lists announced price changes: the base price holds through current_until, and the listed components change on effective_from. Endpoints flagged lifecycle-unverified: ... (a first-party row missing from the vendor's current model list) are not headline-eligible. Rules: docs/SCHEMA.md "Lifecycle".

Identity, modalities and creators (schema 1.4.0)

Model ids are URLs: Phase 3 merged verified duplicates (unknown/databricks-gpt-5-5, alibaba/deepseek-r1, anthropic/claude-4-5-sonnet, openai/gpt-5-6, ...) into one id each, and every removed id is listed in /v1/redirects.json (follow to). One (provider, provider_model_id) maps to exactly one model; the few known exceptions stay separate on purpose and are listed in the repository's data/reports/identity.md. model.modalities is filled from the type where no source states it; such a side has model.sources["modalities.input"] / ["modalities.output"] equal to "inferred" (narrow and certainly true, e.g. chat text -> text, possibly narrower than reality); list rows (models.json) carry the same as modalities_inferred: true. A corrected type has sources.type = "inferred". creators.json rows carry website (or null). context / max_output are the creator's own limit when it publishes one.

Price provenance (schema 1.6.0)

  • Every endpoint in a model file carries price_source ({source, fetched_at} or null when unpriced): the source whose price the row shows (models.dev, litellm, openrouter, genai-prices, ... or curated) and when it was fetched (ISO timestamp from manifest.sources[].fetched_at), or for curated the date a person read the vendor page (YYYY-MM-DD). Show it as "via <source>, fetched <date>"; a fetch time is not a re-check of the price. With --exclude-source, rows whose price came from an excluded source get price_source: null (and no pricing).
  • providers.json rows carry pricing_url (the provider's own price page, or null) and pricing_url_verified_on.
  • Model files carry model.vendor_pricing ({url, verified_on, input_mtok, output_mtok, match, note} or null): the creator's list price as read on its own page, for about 80 high-traffic models. match compares it with our first-party row on every build (true same price, false differs, null nothing to compare); show "<creator> list price, verified <date>" with a link to url, and treat match: false as a data warning. Prices are null when the creator does not price the model (open weights; url is then the model page).
  • Flags starting price-note: are informational (e.g. a sale price with no stated end date); they do not affect headline_eligible. Rules: docs/SCHEMA.md "Provenance".

Price history (schema 1.7.0, audit B-06)

/v1/history/<creator>/<slug>.json = {schema_version: "1", model_id, since, boundary, starts_because, observed_through, ratio: "3:1", changes, points[]}; each point {at, input_mtok, output_mtok, blended_mtok, endpoint_id, provider_id, range{input{min, median}, output{min, median}} | null} is the model's cheapest pair and price_range (min/median) as published by the run at at, held until the next point. Points are written only when a value changes, so one point means "no change since since"; changes counts moves of the cheapest input/output pair (a provider switch at the same price is not a change). The series is rebuilt from the run diffs in data/history with the pipeline's own headline rule, so sanity-flagged rows never appear in it. It starts at boundary (the first run with today's single-endpoint headline shape, 2026-10-19T14:54:50Z) or later when the model's past cannot be reconstructed (starts_because: model_added, endpoint_removed, deprecated). Only models that had a headline price in the window have a file (about 1,360). The same files are in the repository at data/derived/history/.

Quality index (schema 1.7.0, audit B-07)

quality on list rows and on model in model files: {index: "eci", value, lo, hi, model_group, source_url, retrieved} or null. It is the Epoch Capabilities Index as Epoch AI publishes it (eci_scores.csv of the Benchmarking Hub download), with its confidence interval (lo/hi; null for the scale's two anchor models, GPT-5 = 150 and Claude 3.5 Sonnet = 130). model_group is Epoch's model name, retrieved the download date. null means not evaluated (about 150 of ~2,600 models have a score): never show it as 0 and never rank it. ECI is not a percentage; do not divide it by a price. Credit (CC BY 4.0) is in manifest.sources[] (id: "epoch-benchmarks", attribution) and must be shown with the numbers.

Three-state semantics

Booleans in capabilities, open_weights, data_policy.* and is_free are true / false / null. null means unknown, never "no". Likewise null for quantization, regions, supported_parameters, pricing, limits etc. means the data is not known. Clients must not render null as "No" or treat it as satisfying a filter unless the user opts in. For data_policy.zdr, true only when a source confirms it; otherwise null.

Versioning and compatibility

  • The path prefix (/v1/) is the API major version; schema_version (semver, in every file) tracks SCHEMA_VERSION.
  • Within /v1/: new fields, new files and new enum values may be added (minor). Clients must ignore unknown fields and tolerate unknown enum values.
  • Field removal, rename, type change or semantic change requires a new major (/v2/); /v1/ is then kept for a deprecation period announced in the repository.
  • Use the JSON Schema files to validate or generate types. Cache with the sha256 values in manifest.json.
  • Model detail file names follow canonical ids, which are stable unless an alias in data/curated/aliases.yaml changes.

Attribution and licences

Data is a merge of third-party sources; see manifest.sources[] for the exact list, URL and licence per build.

  • models.dev (MIT) and LiteLLM (MIT): keep attribution to both projects when redistributing.
  • OpenRouter: redistribution terms are unverified (redistribution: "unverified"). Values whose provenance (sources) is openrouter are its data (prices, per-provider endpoints, quantization, performance, supported parameters, ZDR).
  • Show "last refreshed" from manifest.sources[].fetched_at, per source.

--exclude-source openrouter

npm run api -- --exclude-source openrouter [--out <dir>] (repeatable / comma separated) produces a build without OpenRouter data:

  • endpoints with no remaining source reference (OpenRouter-only) are dropped; models and providers that only existed through it are dropped;
  • fields whose sources entry is excluded become null (unknown, or [] for env_vars/aliases/modalities) and the sources entry is removed; performance, alts, source_refs, snapshots, and flags that mention it are removed;
  • the value of a losing source is never promoted into a field (alt values are partial and not comparable);
  • provider_count, provider_count_all, cheapest, context, max_output, capabilities, type, endpoint_ids, aliases, and provider/creator counts are recomputed from what remains; manifest.sources omits the source and excluded_sources lists it.

Known remainder: models.dev lists an *OpenRouter provider* (provider_id: "openrouter", provider_model_id: "openrouter/..."). Those rows come from models.dev, not the OpenRouter API, so they stay (identity strings only; their OpenRouter-sourced prices are nulled). Endpoint ids that embed an OpenRouter-reported region/quantization variant (#...) keep the id for stability.

Other derived products (data/derived/)

changes.json (recent history events by day), feed.xml (Atom), per-model and per-plan Atom feeds feeds/models/<creator>/<slug>.xml and feeds/plans/<provider>/<slug>.xml (+ feeds/index.json), history/ (the price-history series above), stats.json. See "Derived products" in docs/SCHEMA.md.