API 0.8.1
API reference
The JSON catalog lives under /v1. This page is rendered from OpenAPI 3.1 . Omit limit and a list route still returns the full collection.
Licence
The code is MIT. The catalog data is CC0 1.0 . No attribution is required for the data. Each price keeps its source_url for provenance. GET /v1/status returns the data licence.
How prices are written
Null means the source did not publish that amount. The HTML shows a dash. A stored zero is a real zero. Cache amounts are USD per 1M tokens. pricing_detail holds tier overrides and extras such as image, web search, and audio.
input_per_1m_usd, output_per_1m_usd, flat_usd
cache_read_per_1m_usd, cache_write_per_1m_usd, cache_write_1h_per_1m_usd
Units include token, image, and image_token.
GET /v1/changesGET /v1/modelsGET /v1/models/{id}GET /v1/models/{id}/compareGET /v1/models/{id}/historyGET /v1/models/{id}/offersGET /v1/models/{id}/similarGET /v1/moversGET /v1/pricingGET /v1/providersGET /v1/providers/{id}GET /v1/searchGET /v1/statsGET /v1/statusGET /healthGET /openapi.jsonGET /GET /changesGET /compareGET /docsGET /modelsGET /models/{id}GET /pricingGET /providersGET /providers/{id}GET /statusPOST /v1/admin/syncPOST /v1/sync
GET
/v1/changes
Daily price diffs
Compares consecutive UTC snapshots. Default `since` is 7 days before today. A first-day catalog has no diffs.
Name In Required Notes
since
query
no
UTC date YYYY-MM-DD. Inclusive.
provider
query
no
q
query
no
direction
query
no
up, down
limit
query
no
offset
query
no
fields
query
no
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/changes?since=2026-09-01&q=astra&limit=2'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/changes?since=2026-09-01&q=astra&limit=2");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/changes?since=2026-09-01&q=astra&limit=2").read().decode())
Try it
GET
/v1/models
List models
Served from the R2 catalog snapshot when one is published. Edge-cached via caches.default (browser 5m, Cache API 30m). List payloads also sit in KV for 1 hour. A successful sync increments a cache generation and busts both layers. Anonymous ?fresh=1 does not bypass the cache; a SYNC_SECRET bearer does.
Name In Required Notes
provider
query
no
Filter by provider id
modality
query
no
text, image, video, audio
q
query
no
sort
query
no
name, provider, context, price, output, cache, created
order
query
no
asc, desc
min_context
query
no
max_input
query
no
Maximum input or flat USD per 1M
limit
query
no
Omit for the full list
offset
query
no
fields
query
no
Comma-separated response fields
cheaper
query
no
When 1, only models with a cheaper provider than the lab or the OpenRouter list price
fresh
query
no
Bypass edge Cache API and KV snapshot caches
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/models?q=astra&limit=2'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/models?q=astra&limit=2");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/models?q=astra&limit=2").read().decode())
Try it
GET
/v1/models/{id}
Get one model with prices
Model ids are OpenRouter ids (`provider/slug`), DeepInfra ids (`deepinfra/...`), or a leading ~ alias, and may contain slashes. Prices include cache_read_per_1m_usd, cache_write_per_1m_usd, cache_write_1h_per_1m_usd, and pricing_detail (tiers and extra components). Null amounts are not published. A stored 0 is a real zero, usually a :free SKU.
Name In Required Notes
id
path
yes
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/models/openai/gpt-6-astra'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/models/openai/gpt-6-astra");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/models/openai/gpt-6-astra").read().decode())
Try it
GET
/v1/models/{id}/compare
Cheapest provider versus a baseline
Compares the cheapest live offer with the lab price, or with the OpenRouter list price when baseline=openrouter or no lab offer exists.
Name In Required Notes
id
path
yes
unit
query
no
blended
baseline
query
no
lab, openrouter
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/models/openai/gpt-5.6-terra/compare'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/models/openai/gpt-5.6-terra/compare");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/models/openai/gpt-5.6-terra/compare").read().decode())
Try it
200 Cheapest provider, reference price, and savings percent404
GET
/v1/models/{id}/history
Daily price history for one model
One snapshot per UTC date and unit. The first row is the migration backfill or the first cron run.
Name In Required Notes
id
path
yes
unit
query
no
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/models/openai/gpt-6-astra/history'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/models/openai/gpt-6-astra/history");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/models/openai/gpt-6-astra/history").read().decode())
Try it
GET
/v1/models/{id}/offers
Provider prices for one model
Live and listed seller rows for this canonical model, sorted by a 3:1 input/output blend. Read from the R2 catalog snapshot. Each row has a source URL. A null amount was not published.
Name In Required Notes
id
path
yes
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/models/openai/gpt-5.6-terra/offers'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/models/openai/gpt-5.6-terra/offers");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/models/openai/gpt-5.6-terra/offers").read().decode())
Try it
200 Offer rows and the cheapest summary404
GET
/v1/models/{id}/similar
Models near this list price
Active models with a similar input or flat rate, preferring the same modality.
Name In Required Notes
id
path
yes
limit
query
no
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/models/openai/gpt-5.6-terra/similar?limit=2'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/models/openai/gpt-5.6-terra/similar?limit=2");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/models/openai/gpt-5.6-terra/similar?limit=2").read().decode())
Try it
200 Similar models with their primary price404
GET
/v1/movers
Largest absolute price moves
Same diffs as /v1/changes, ordered by absolute input, flat, or output delta.
Name In Required Notes
since
query
no
provider
query
no
limit
query
no
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/movers?since=2026-09-01&limit=2'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/movers?since=2026-09-01&limit=2");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/movers?since=2026-09-01&limit=2").read().decode())
Try it
200 Ranked price changes400
GET
/v1/pricing
List prices
Token prices use input_per_1m_usd / output_per_1m_usd. Media prices use flat_usd plus a unit such as image, second_video, character_audio, minute_audio, or request. Served from the R2 catalog snapshot when one is published. Edge-cached via caches.default; list payloads also sit in KV. Anonymous ?fresh=1 does not bypass the cache; a SYNC_SECRET bearer does.
Name In Required Notes
model
query
no
provider
query
no
unit
query
no
limit
query
no
Omit for the full list
offset
query
no
fields
query
no
fresh
query
no
1
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/pricing?limit=2'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/pricing?limit=2");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/pricing?limit=2").read().decode())
Try it
GET
/v1/providers
List providers
Served from the R2 catalog snapshot when one is published. Edge-cached via caches.default. Anonymous ?fresh=1 does not bypass the cache; a SYNC_SECRET bearer does. Omit limit to receive every provider.
Name In Required Notes
q
query
no
Match provider id or name
limit
query
no
offset
query
no
fields
query
no
Comma-separated response fields
fresh
query
no
Bypass edge Cache API
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/providers?q=astra&limit=2'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/providers?q=astra&limit=2");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/providers?q=astra&limit=2").read().decode())
Try it
200 All catalog providers
GET
/v1/providers/{id}
Get one provider and its models
Name In Required Notes
id
path
yes
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/providers/openai'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/providers/openai");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/providers/openai").read().decode())
Try it
GET
/v1/search
Search providers and models
Name In Required Notes
q
query
yes
fresh
query
no
1
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/search?q=astra'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/search?q=astra");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/search?q=astra").read().decode())
Try it
200 Matching providers and models400
GET
/v1/stats
Catalog headline stats
Provider, model, and price counts plus the latest snapshot time. sync_status is null when no sync run is stored.
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/stats'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/stats");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/stats").read().decode())
Try it
GET
/v1/status
Sync health
Last sync run, per-source adapter health, and stale=true when the last good sync is older than 12 hours. A good sync is status ok, or partial with OpenRouter ok. warnings lists per-1M token amounts above 1000 USD; those amounts are stored as null. Not edge-cached. Null price amounts elsewhere in the API mean the source did not publish a rate.
Examples
curl curl 'https://inferencelist.theserverless.dev/v1/status'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/status");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/v1/status").read().decode())
Try it
GET
/health
Liveness
Examples
curl curl 'https://inferencelist.theserverless.dev/health'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/health");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/health").read().decode())
Try it
GET
/openapi.json
OpenAPI document
Examples
curl curl 'https://inferencelist.theserverless.dev/openapi.json'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/openapi.json");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/openapi.json").read().decode())
Try it
200 This OpenAPI 3.1 document
GET
/
Product home (HTML)
Search, modality filters, featured providers, last snapshot time.
Examples
curl curl 'https://inferencelist.theserverless.dev/'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/").read().decode())
Try it
GET
/changes
Price changes feed (HTML)
Name In Required Notes
since
query
no
provider
query
no
q
query
no
direction
query
no
up, down
Examples
curl curl 'https://inferencelist.theserverless.dev/changes?since=2026-09-01&q=astra'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/changes?since=2026-09-01&q=astra");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/changes?since=2026-09-01&q=astra").read().decode())
Try it
GET
/compare
Compare up to 4 models (HTML)
Name In Required Notes
ids
query
no
Repeat the parameter or use a comma-separated list.
Examples
curl curl 'https://inferencelist.theserverless.dev/compare'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/compare");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/compare").read().decode())
Try it
GET
/docs
API reference (HTML)
Rendered from this OpenAPI document, with curl, JavaScript, and Python examples.
Examples
curl curl 'https://inferencelist.theserverless.dev/docs'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/docs");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/docs").read().decode())
Try it
GET
/models
Model list (HTML)
Default sort is input price, lowest published rate first. Null amounts sort last. Filters stay in the URL.
Name In Required Notes
q
query
no
provider
query
no
modality
query
no
text, image, video, audio
sort
query
no
name, provider, context, price, output, cache, created
order
query
no
asc, desc
page
query
no
HTML pagination (50 per page)
Examples
curl curl 'https://inferencelist.theserverless.dev/models?q=astra'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/models?q=astra");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/models?q=astra").read().decode())
Try it
GET
/models/{id}
Model detail (HTML)
Current price plus a history chart and table.
Name In Required Notes
id
path
yes
Examples
curl curl 'https://inferencelist.theserverless.dev/models/openai/gpt-6-astra'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/models/openai/gpt-6-astra");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/models/openai/gpt-6-astra").read().decode())
Try it
GET
/pricing
Pricing explorer (HTML)
Name In Required Notes
provider
query
no
unit
query
no
page
query
no
HTML pagination (50 per page)
Examples
curl curl 'https://inferencelist.theserverless.dev/pricing'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/pricing");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/pricing").read().decode())
Try it
GET
/providers
Provider index (HTML)
Examples
curl curl 'https://inferencelist.theserverless.dev/providers'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/providers");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/providers").read().decode())
Try it
200 HTML list of providers
GET
/providers/{id}
Provider detail (HTML)
Name In Required Notes
id
path
yes
Examples
curl curl 'https://inferencelist.theserverless.dev/providers/openai'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/providers/openai");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/providers/openai").read().decode())
Try it
200 HTML provider page with models, prices, and history
GET
/status
Catalog status (HTML)
When the catalog last updated, plus one row per source. Same facts as GET /v1/status, without the per-source list on the home page.
Examples
curl curl 'https://inferencelist.theserverless.dev/status'
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/status");
const body = await res.json();
Python import urllib.request
print(urllib.request.urlopen("https://inferencelist.theserverless.dev/status").read().decode())
Try it
POST · auth
/v1/admin/sync
Refresh the live catalog
Fetches OpenRouter GET /api/v1/models, upserts providers/models/prices, writes today's price_history, and bumps caches. Protected by SYNC_SECRET (Authorization: Bearer or X-Sync-Secret).
Examples
curl curl -X POST 'https://inferencelist.theserverless.dev/v1/admin/sync' \
-H "Authorization: Bearer $SYNC_SECRET"
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/admin/sync", {
method: "POST",
headers: { Authorization: "Bearer " + process.env.SYNC_SECRET },
});
const body = await res.json();
Python import os, urllib.request
req = urllib.request.Request("https://inferencelist.theserverless.dev/v1/admin/sync", method="POST", headers={"Authorization": "Bearer " + os.environ["SYNC_SECRET"]})
print(urllib.request.urlopen(req).read().decode())
This call changes the catalog. Use the curl example. It is not sent from this page.
POST · auth
/v1/sync
Refresh the live catalog (alias)
Same as POST /v1/admin/sync.
Examples
curl curl -X POST 'https://inferencelist.theserverless.dev/v1/sync' \
-H "Authorization: Bearer $SYNC_SECRET"
JavaScript const res = await fetch("https://inferencelist.theserverless.dev/v1/sync", {
method: "POST",
headers: { Authorization: "Bearer " + process.env.SYNC_SECRET },
});
const body = await res.json();
Python import os, urllib.request
req = urllib.request.Request("https://inferencelist.theserverless.dev/v1/sync", method="POST", headers={"Authorization": "Bearer " + os.environ["SYNC_SECRET"]})
print(urllib.request.urlopen(req).read().decode())
This call changes the catalog. Use the curl example. It is not sent from this page.