theserverless.dev InferenceList

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/changes

Daily price diffs

Compares consecutive UTC snapshots. Default `since` is 7 days before today. A first-day catalog has no diffs.

NameInRequiredNotes
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

Response appears here.
  • 200 Price changes
  • 400

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.

NameInRequiredNotes
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

Response appears here.
  • 200 Model list
  • 400

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.

NameInRequiredNotes
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

Response appears here.
  • 200 Model detail
  • 404

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.

NameInRequiredNotes
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

Response appears here.
  • 200 Cheapest provider, reference price, and savings percent
  • 404

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.

NameInRequiredNotes
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

Response appears here.
  • 200 History points
  • 404

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.

NameInRequiredNotes
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

Response appears here.
  • 200 Offer rows and the cheapest summary
  • 404

GET

/v1/models/{id}/similar

Models near this list price

Active models with a similar input or flat rate, preferring the same modality.

NameInRequiredNotes
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

Response appears here.
  • 200 Similar models with their primary price
  • 404

GET

/v1/movers

Largest absolute price moves

Same diffs as /v1/changes, ordered by absolute input, flat, or output delta.

NameInRequiredNotes
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

Response appears here.
  • 200 Ranked price changes
  • 400

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.

NameInRequiredNotes
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

Response appears here.
  • 200 Price rows

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.

NameInRequiredNotes
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

Response appears here.
  • 200 All catalog providers

GET

/v1/providers/{id}

Get one provider and its models

NameInRequiredNotes
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

Response appears here.
  • 200 Provider detail
  • 404

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

Response appears here.
  • 200 Catalog stats

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

Response appears here.
  • 200 Sync status

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

Response appears here.
  • 200 Worker is up

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

Response appears here.
  • 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

Response appears here.
  • 200 HTML home page

GET

/changes

Price changes feed (HTML)

NameInRequiredNotes
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

Response appears here.
  • 200 HTML changes feed

GET

/compare

Compare up to 4 models (HTML)

NameInRequiredNotes
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

Response appears here.
  • 200 HTML comparison

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

Response appears here.
  • 200 HTML API reference

GET

/models

Model list (HTML)

Default sort is input price, lowest published rate first. Null amounts sort last. Filters stay in the URL.

NameInRequiredNotes
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

Response appears here.
  • 200 HTML model explorer

GET

/models/{id}

Model detail (HTML)

Current price plus a history chart and table.

NameInRequiredNotes
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

Response appears here.
  • 200 HTML model page

GET

/pricing

Pricing explorer (HTML)

NameInRequiredNotes
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

Response appears here.
  • 200 HTML pricing table

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

Response appears here.
  • 200 HTML list of providers

GET

/providers/{id}

Provider detail (HTML)

NameInRequiredNotes
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

Response appears here.
  • 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

Response appears here.
  • 200 HTML status page

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.

  • 200 Sync report
  • 401
  • 503

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.

  • 200 Sync report
  • 401
  • 503