{"slug": "free-rest-api-for-llm-pricing-context-windows-and-cost-estimation", "title": "Free REST API for LLM pricing, context windows and cost estimation", "summary": "Axium Lab has released a free REST API that serves pricing, context windows, and capability data for 3,214 LLM models from 127 providers, along with a cost estimator that itemizes each rate key used. The API reads a 1.7 MB JSON file at boot and serves filtered, sorted, and projected model data from memory without a database, with endpoints for model details and cost estimation. The hosted instance at https://api-llm-specs.axium-lab.com is not yet live, but the service can be run locally via Docker.", "body_md": "**Every LLM's price, context window and capabilities behind one REST API — and a cost estimator that shows its work.**\n\nPicking a model means checking four things at once: what it costs, how much context it takes, what it can do,\nand whether it is about to be deprecated. That lives in a 1.7 MB JSON file you have to parse yourself. This\nservice reads it once at boot and serves **3,214 models from 127 providers** out of memory, with no database —\nfiltered, sorted, compared — and prices a single call down to the exact rate key it used.\n\n```\ncurl https://api-llm-specs.axium-lab.com/v1/models/claude-sonnet-4-5\n```\n\nAsk for a model and you get everything the catalog knows about it — every rate, including the ones that only apply past a threshold or to a cache write, plus the context window and the capability flags:\n\n```\n{                                    // 29 attributes in total, trimmed here\n  \"deprecation_date\": \"2026-09-29\",\n  \"cache_creation_input_token_cost\": 0.00000375,\n  \"cache_creation_input_token_cost_above_1hr\": 0.000006,\n  \"cache_read_input_token_cost\": 3e-7,\n  \"input_cost_per_token\": 0.000003,\n  \"input_cost_per_token_above_200k_tokens\": 0.000006,\n  \"output_cost_per_token_above_200k_tokens\": 0.0000225,\n  \"provider\": \"anthropic\",\n  \"max_input_tokens\": 200000,\n  \"max_output_tokens\": 64000,\n  \"mode\": \"chat\",\n  \"output_cost_per_token\": 0.000015,\n  \"supports_prompt_caching\": true,\n  \"supports_vision\": true,\n  \"prompt_cache_min_tokens\": 1024,\n  \"id\": \"claude-sonnet-4-5\"\n}\n```\n\nOr ask a question of the whole catalog — a provider, a mode, a price ceiling, a context window — and project just the fields you care about:\n\n```\ncurl 'https://api-llm-specs.axium-lab.com/v1/models?provider=anthropic&mode=chat&sort=input_cost_per_token:desc&fields=id,input_cost_per_token,output_cost_per_token,max_input_tokens&limit=3'\n{\n  \"total\": 26,\n  \"limit\": 3,\n  \"offset\": 0,\n  \"data\": [\n    { \"id\": \"claude-3-opus-20240229\", \"input_cost_per_token\": 0.000015, \"output_cost_per_token\": 0.000075, \"max_input_tokens\": 200000 },\n    { \"id\": \"claude-4-opus-20250514\", \"input_cost_per_token\": 0.000015, \"output_cost_per_token\": 0.000075, \"max_input_tokens\": 200000 },\n    { \"id\": \"claude-opus-4-1\",        \"input_cost_per_token\": 0.000015, \"output_cost_per_token\": 0.000075, \"max_input_tokens\": 200000 }\n  ]\n}\n```\n\n`total`\n\nis the size of the filtered set before the page is cut, and 126 more providers' worth of models are one\n`provider=`\n\naway. [Every filter, sort and projection →](https://llm-specs.axium-lab.com/api-models.html)\n\nRates are one thing; knowing which of those four Anthropic cache keys applies to *your* request is another.\nThat is what `POST /v1/estimate`\n\nis for — and it answers with a receipt, not a number. Every line carries\n`rate_key`\n\n, the literal key it was billed with:\n\n```\ninput.text         190000 x 0.000006   = 1.14    [input_cost_per_token_above_200k_tokens]\noutput.text          4000 x 0.0000225  = 0.09    [output_cost_per_token_above_200k_tokens]\ncache_read.text     20000 x 6e-7       = 0.012   [cache_read_input_token_cost_above_200k_tokens]\ncache_write.1h       8000 x 0.000012   = 0.096   [cache_creation_input_token_cost_above_1hr_above_200k_tokens]\n                                        ------\n                                         1.338 USD\n```\n\nThat prompt crossed the 200k threshold, so the **whole** request was repriced — output included — and the 1 hour\ncache TTL composed with it into that quadruple key. Both are decisions the estimator makes explicitly and\nreports back in `resolution`\n\n. [The estimator in full →](https://llm-specs.axium-lab.com/api-estimate.html)\n\n⚠️ Hosted instance — not live yet.`https://api-llm-specs.axium-lab.com`\n\nis the address the free instance will answer on; it is not deployed at the time of writing. Until then, run it locally or deploy your own — it is one`docker run`\n\naway, and the dataset ships inside the image.\n\n**📖 Full API reference at llm-specs.axium-lab.com** — every\nendpoint, parameter, response shape and error, with the numbers taken from real responses.\n\n**Auditable, not magic.** Every cost line names the dataset key it used (`rate_key`\n\n) and the quantity it multiplied. A total you cannot check against the source is a total you cannot trust.**Decimal arithmetic, never** The catalog ships floating point noise already serialized (`number`\n\n.`1.2999000000000001e-07`\n\n) and rates as small as`1.3e-10`\n\n. Everything accumulates in`Decimal`\n\n.**A missing rate is never billed as 0.** 258 models legitimately declare`output_cost_per_token: 0`\n\n, so \"free\" and \"unknown\" have to stay distinguishable: unknown usage goes to`unpriced[]`\n\nand never inflates or deflates the total silently.**It boots without network.** The dataset is versioned in the repo and baked into the image. At boot the instance revalidates it upstream with`If-None-Match`\n\n; on a`304`\n\nit transfers**0 bytes**, and if upstream is down it serves the local copy and says so in`/health`\n\n.**Errors you can branch on.** Every failure is RFC 9457`application/problem+json`\n\nwith a stable`type`\n\nslug —`model-not-found`\n\n,`ambiguous-model`\n\n,`model-not-priced`\n\n,`limits-exceeded`\n\n,`invalid-query`\n\n.\n\nRequires [Bun](https://bun.sh).\n\n```\ngit clone https://github.com/axium-lab/llm-specs-api.git\ncd llm-specs-api\nbun install\nbun start          # http://localhost:8080\n```\n\nOr straight from the published image — nothing to build, and the dataset is already inside:\n\n```\ndocker run --rm -p 8080:8080 ghcr.io/axium-lab/llm-specs-api:latest\n```\n\nTo build it yourself instead:\n\n```\ndocker build -t llm-specs-api .\ndocker run --rm -p 8080:8080 llm-specs-api\n```\n\nThen ask it something:\n\n```\n# The cheapest chat models with a 1M context window\ncurl 'localhost:8080/v1/models?mode=chat&min_input_tokens=1000000&sort=input_cost_per_token:asc&fields=id,provider,input_cost_per_token&limit=5'\n\n# Ids containing / and : need no escaping — the lookup route takes them literally\ncurl 'localhost:8080/v1/models/bedrock/us.anthropic.claude-3-5-haiku-20241022-v1:0'\n```\n\n| Method | Path | Description |\n|---|---|---|\n`GET` |\n`/health` |\n\n`startup_error`\n\n.`GET`\n\n`/v1/models`\n\n`GET`\n\n`/v1/models/*`\n\n`/`\n\n, `:`\n\nand `*`\n\n.`GET`\n\n`/v1/models/by-id?id=`\n\n`GET`\n\n`/v1/compare?ids=a,b,c`\n\n`GET`\n\n`/v1/providers`\n\n`GET`\n\n`/v1/modes`\n\n`GET`\n\n`/v1/attributes`\n\n`GET`\n\n`/v1/meta`\n\n`POST`\n\n`/v1/estimate`\n\nFilters for `/v1/models`\n\n: `provider`\n\n, `mode`\n\n, `q`\n\n, any of the 37 `supports_*`\n\nkeys, `min_input_tokens`\n\n,\n`max_input_cost`\n\n, `sort=field:asc|desc`\n\n, `fields`\n\n, `limit`\n\n, `offset`\n\n.\n[Full parameter reference →](https://llm-specs.axium-lab.com/api-models.html)\n\nEverything is optional — the service runs out of the box.\n\n| Environment variable | Default | Description |\n|---|---|---|\n`PORT` |\n`8080` |\nInjected by Cloud Run. |\n`DATASET_PATH` |\n`data/model_prices_and_context_window.json` |\nThe source of truth. The sidecar path is derived from it. |\n`UPSTREAM_URL` |\nLiteLLM's `litellm_internal_staging` branch |\nRevalidation target. See\n|\n\n`FETCH_TIMEOUT_MS`\n\n`30000`\n\n`DEFAULT_LIMIT`\n\n`50`\n\n`/v1/models`\n\n.`MAX_LIMIT`\n\n`500`\n\n`limit`\n\n; a larger value is clamped, not rejected.Positive integers only — a malformed value fails the boot instead of being silently ignored.\n\nEvery [release](https://github.com/axium-lab/llm-specs-api/releases) ships a `docker-compose.yml`\n\nwith the\nimage pinned to that exact version:\n\n```\ncurl -LO https://github.com/axium-lab/llm-specs-api/releases/latest/download/docker-compose.yml\ndocker compose up -d\ncurl localhost:8080/health\n```\n\nImages are published for `linux/amd64`\n\nand `linux/arm64`\n\nat\n[ ghcr.io/axium-lab/llm-specs-api](https://github.com/axium-lab/llm-specs-api/pkgs/container/llm-specs-api),\ntagged\n\n`X.Y.Z`\n\n, `X.Y`\n\nand `latest`\n\n. A pre-release is never tagged `latest`\n\n.The compose file declares a **named volume** over `/app/data`\n\n, and it matters: the dataset travels inside the\nimage and the service rewrites it when upstream has something newer, so without the volume every restart\nthrows that update away and starts again from the copy baked in at build time. It has to be a *named* volume —\nDocker seeds one from the image on first use, whereas an empty bind mount would hide the dataset and leave the\nservice with nothing to serve.\n\n```\ngcloud run deploy llm-specs-api --source . --region europe-west1 \\\n  --min-instances 1 --cpu-boost --allow-unauthenticated\n```\n\n`--min-instances 1`\n\nis a latency choice, not a correctness one: a cold start revalidates the baked-in copy with\n`If-None-Match`\n\nand transfers nothing on a `304`\n\n, and a boot while GitHub is down serves the local dataset\ninstead of failing. Keep it if you care about cold-start latency, drop it if you care about idle cost.\n\nIf you mount a Cloud Storage bucket, do not mount it over`data/`\n\n: GCS FUSE hides whatever sits below the mount point, just like any Linux`mount`\n\n, and you would lose the file baked into the image. Use a separate path (`/mnt/dataset`\n\n) and point`DATASET_PATH`\n\nat it.\n\nThe estimator is honest about what it does not price. These are accepted inputs or dataset features that\ncurrently produce **no cost line**, and they are worth knowing before you trust a total:\n\n| Limitation | Effect |\n|---|---|\n`usage.web_search` and `usage.search_results` |\nAccepted and validated, but never billed. `search_context_cost_per_query` (282 models) is declared in the catalog and never read. They do not even show up in `unpriced[]` . |\n`options.tier_policy: \"marginal\"` |\nDoes not compute per-band pricing. It falls through to the base rate, so the result is the same as a request that never crossed a threshold. |\n`tiered_pricing` |\nNot read. The 21 models that price only through it answer `200` with a total of `0` and all usage in `unpriced[]` . |\n| Databricks DBU rates | The `input_dbu_cost_per_token` / `output_dbu_cost_per_token` keys (47 models) are described in the catalog but no usage field maps to them, so a DBU total is never produced. |\n| Malformed JSON, or a body over 256 kB | Answers `500 internal-error` instead of `400` / `413` . |\n\nThe catalog is LiteLLM's [ model_prices_and_context_window.json](https://github.com/BerriAI/litellm), MIT\nlicensed, vendored into\n\n`data/`\n\nand redistributed **normalized**:\n\n`src/data/parse.ts`\n\nrenames\n`litellm_provider`\n\nto `provider`\n\non the way in, and that is the only place where upstream's shape is adjusted.\nThe prices are the ones LiteLLM publishes — this project does not source, correct or negotiate them, and\n[flags the implausible ones](https://llm-specs.axium-lab.com/dataset.html#suspicious)rather than fixing them.\n\n[How the dataset is loaded →](https://llm-specs.axium-lab.com/dataset.html)\n\n```\nbun run dev        # start with file watching\nbun test           # HTTP surface, pricing engine, dataset resolution, catalog completeness\nbun run typecheck  # tsc --noEmit\n```\n\nStack: [Bun](https://bun.sh) + TypeScript + [Express 5](https://expressjs.com). No build step, no database, no\nstate: `src/data/`\n\nowns the dataset, `src/pricing/`\n\nowns the cost engine, `src/routes/`\n\nowns the HTTP surface.\n\nIssues and PRs are welcome — see [CONTRIBUTING.md](/axium-lab/llm-specs-api/blob/main/CONTRIBUTING.md). The one hard rule: every endpoint and every\npricing rule keeps a test that proves it.", "url": "https://wpnews.pro/news/free-rest-api-for-llm-pricing-context-windows-and-cost-estimation", "canonical_source": "https://github.com/axium-lab/llm-specs-api", "published_at": "2026-08-27 10:25:37+00:00", "updated_at": "2026-08-27 10:49:06.483586+00:00", "lang": "en", "topics": ["ai-infrastructure", "developer-tools", "artificial-intelligence"], "entities": ["Axium Lab", "Anthropic", "Claude Sonnet 4.5", "Claude 3 Opus", "Claude 4 Opus", "Claude Opus 4.1"], "alternates": {"html": "https://wpnews.pro/news/free-rest-api-for-llm-pricing-context-windows-and-cost-estimation", "markdown": "https://wpnews.pro/news/free-rest-api-for-llm-pricing-context-windows-and-cost-estimation.md", "text": "https://wpnews.pro/news/free-rest-api-for-llm-pricing-context-windows-and-cost-estimation.txt", "jsonld": "https://wpnews.pro/news/free-rest-api-for-llm-pricing-context-windows-and-cost-estimation.jsonld"}}