# Public API > Read GPU Ninja's catalogue as static JSON. No key, no rate limit, cached for five minutes, with plain-text companions for every page. URL: https://gpuninja.com/docs/api Last updated: 2026-10-11 ## Overview GPU Ninja publishes its whole catalogue as a read-only JSON API. Every response is a static file, rebuilt and uploaded on each deploy, so there is no server to query and nothing to sign up for. - Base URL: `https://gpuninja.com/api/v1/` - Format: JSON only, served as `application/json`. - Authentication: none. There is no API key and no account. - Rate limit: none. Please be reasonable: cache responses, revalidate with the `ETag`, and download the compact search index rather than crawling every entity. - Methods: `GET` and `HEAD`. Every other method, including `OPTIONS`, returns `405`. - Licence: the data is CC BY 4.0 (https://gpuninja.com/legal/data-licence). Use it for anything, including commercial apps, and credit GPU Ninja. The OpenAPI document is Apache 2.0. Sample data for now. Until the research pipeline publishes the real catalogue, the API serves GPU Ninja's small development dataset: a few chips, graphics cards, cases, models, motherboards and risers, with sample offers. Its prices and stock are illustrative, not quotes. The URLs, shapes and rules on this page are the real contract and won't change when the real data arrives. There is no server-side filtering. Filter on your side over the compact search index (see Search (https://gpuninja.com/docs/api#search)), or ask through the MCP servers (https://gpuninja.com/docs/mcp), which do it for AI assistants. The buyer's guide (https://gpuninja.com/docs/buyers-guide) does the same on the website. All of them use one open-source search library that you can run yourself. ## Quick start Fetch the first page of graphics cards: ```bash curl -s https://gpuninja.com/api/v1/boards ``` Fetch one card, then the cases it fits and the AI models it can run: ```bash curl -s https://gpuninja.com/api/v1/boards/asus-rog-strix-4090 curl -s https://gpuninja.com/api/v1/boards/asus-rog-strix-4090/fits curl -s https://gpuninja.com/api/v1/boards/asus-rog-strix-4090/can-run ``` Download the compact search index and the last 30 days of changes: ```bash curl -s https://gpuninja.com/api/v1/index curl -s https://gpuninja.com/api/v1/changes ``` Add `-L` if you want curl to follow redirects, which matters when a slug has been renamed. ## Endpoints `{collection}` is one of `chips`, `boards`, `chassis`, `models`, `platforms`, `benchmarks`, `motherboards`, `risers` or `sockets`. `{slug}` is a lowercase kebab-case identifier of at most 80 characters, such as `asus-rog-strix-4090`; `page`, `index` and `404` are never slugs. `{n}` is a page number of 2 or more, and `{month}` a calendar month in UTC, `YYYY-MM`. | Path | Returns | | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/api/v1/{collection}` | Page 1 of a collection, 50 items per page | | `/api/v1/{collection}/page/{n}` | Page `n` of a collection | | `/api/v1/{collection}/{slug}` | One entity in full | | `/api/v1/boards/{slug}/fits` | Every case, with a fit verdict for this card | | `/api/v1/chassis/{slug}/fits` | Every graphics card, with a fit verdict for this case | | `/api/v1/boards/{slug}/can-run` | AI models that fit in this card's VRAM | | `/api/v1/models/{slug}/runs-on` | Graphics cards with enough VRAM for this model | | `/api/v1/index` | The compact search index of chips, boards, chassis, models, motherboards and risers | | `/api/v1/changes` | Every data change merged in the last 30 days, and a list of the monthly archives | | `/api/v1/changes/{month}` | Every data change merged in that month, for each month that has one | | `/api/v1/openapi.json` | The OpenAPI 3.1.1 description of every path and schema (see OpenAPI and generated clients (https://gpuninja.com/docs/api#openapi-and-generated-clients)) | Field-by-field detail is in the pages of this section: Collections and entities (https://gpuninja.com/docs/api/collections), Compatibility (https://gpuninja.com/docs/api/compatibility), Search index (https://gpuninja.com/docs/api/search), Changes feed (https://gpuninja.com/docs/api/changes) and Caching, redirects and errors (https://gpuninja.com/docs/api/caching-and-errors). ## URL rules - Two forms, one resource. Every resource answers both without an extension and with `.json`: `/api/v1/boards/asus-rog-strix-4090` and `/api/v1/boards/asus-rog-strix-4090.json` return the same bytes and the same `ETag`. The OpenAPI document is the exception: it is only at `/api/v1/openapi.json`. - Lowercase and case-sensitive. Paths are lowercase. `/API/V1/BOARDS` is a `404`; nothing folds case for you. - No trailing slash. An API path with a trailing slash redirects with `308` to the same path without it. - Query parameters are ignored. `/api/v1/boards?page=2` and `/api/v1/boards?vram=16` return exactly what `/api/v1/boards` returns. There is no server-side filtering, sorting or field selection. - Pagination is by path. Page 1 is the collection URL itself, and later pages are `/page/2`, `/page/3` and so on, 50 items per page. There is no `/page/1`, and pages beyond `pageCount` don't exist. Each page links to `first`, `last`, `prev` and `next`. - Renames are `301`s. If an entity's slug changes, every old URL redirects permanently to the new one: the API document and its compatibility files (with or without `.json`), and the web page and its `.txt`. The query string is kept. Each redirect points straight at the final URL, so you never follow a chain. - 404s are HTML. A path that doesn't exist returns status `404` with the site's HTML error page as the body, even under `/api/`. Check the status code; don't try to parse the body. ## Response conventions Every JSON file except `openapi.json` carries the same envelope: `apiVersion` (always `"v1"`), `kind` (what the document is, such as `"board"`, `"collection"` or `"board-fits"`), `asOf`, and `links`. - Nothing is optional. Every property is always present. An unknown value is `null`, never a missing key, an empty string or `0`; a list with nothing in it is `[]`. - Property names are camelCase, and enumerated values are kebab-case (`does-not-fit`, `board-can-run`). - Units are in the field name. `lengthMm` is millimetres, `tdpW` watts, `vramGb` gigabytes, `factoryBoostClockMhz` megahertz, `memoryBusWidthBits` bits, `parametersB` billions of parameters, `contextLength` tokens, `memoryBandwidthGbps` decimal gigabytes per second, `fp32Tflops` trillions of floating-point operations per second and `int8Tops` trillions of integer operations per second. `slotWidth` and `maxGpuSlots` are expansion slots and may be fractional, such as `3.5`. - Timestamps are absolute. Instants are UTC at whole-second precision with a `Z` suffix, such as `2026-10-04T06:12:00Z`. Calendar dates are `YYYY-MM-DD`. Nothing in the API is relative ("3 days ago"); work that out yourself at the moment you display it. - Money. `lowestPriceUsd` and `launchMsrpUsd` are decimal US dollars. An offer's `price` is a decimal amount in that offer's own `currency`. Amounts have at most two decimal places. - Links are absolute. `links.self` is the extensionless API URL. `links.page` and `links.text` are the matching web page and its plain-text companion, or `null` for platforms, benchmarks, motherboards, risers and sockets, which have no pages. ### asOf and provenance `asOf` is the most recent time any value in the file was retrieved or verified. Each entity that appears in the file contributes the timestamps of its own values and offers, and nothing else. It is never the build time, so a cached copy is honest about how old its data is. It is `null` when nothing in the file has a timestamp. On `/api/v1/changes` it is the latest merge time in the window instead, and on a monthly archive the latest merge time in that month. Freshness for individual fields lives in each entity's `provenance` map, which names the source URL, when the value was retrieved, when a source last confirmed it, and its verification status. See Collections and entities (https://gpuninja.com/docs/api/collections) and Data (https://gpuninja.com/docs/data). ### Discontinued and frozen records Chips, boards, chassis, motherboards and risers have a `status` of `active` or `discontinued`. A discontinued record is a frozen snapshot: its specs, last recorded offers and benchmark results are preserved exactly as they were and never updated again, except by an explicit correction. A discontinued motherboard is frozen with its PCIe slots. Discontinued records stay in every collection, keep their URLs, and still get fit and can-run answers against newly added hardware and models. The one exception is a discontinued board, which is API only: it keeps its document at `/api/v1/boards/{slug}`, its place in the complete list and the search index, and it still appears in a case's `fits` and a model's `runs-on`, but it has no site page, no `.txt` companion and no `fits` or `can-run` document of its own. Its `links.page` and `links.text` are `null`, and so are `compatibility.fits` and `compatibility.canRun`. A discontinued board's or case's `inStock` is `false` and its `lowestPriceUsd` is `null`, because a frozen price is history, not a current price. Models, platforms, benchmarks and sockets are never discontinued and never freeze. ### Motherboards, risers and sockets Three collections exist for the Solution Builder and are API only: `/api/v1/motherboards`, `/api/v1/risers` and `/api/v1/sockets`, with one document per entity at `/api/v1/motherboards/{slug}`, `/api/v1/risers/{slug}` and `/api/v1/sockets/{slug}`. They are JSON only: they have no site page and no `.txt` companion, so their `links.page` and `links.text` are `null`. - A motherboard names its `socket` (a socket summary; its summary carries `socketSlug`) and lists its `pcieSlots` by `position` from the top, each with its `physicalLanes`, its `electricalLanes` and its `pcieGen`. It has a `status` and `offers`, but no `lowestPriceUsd` or `inStock`. - A riser (a riser cable or vertical-mount kit) has its cable `lengthMm`, its `pcieGen` and its `lanes`, a `status` and `offers`, and no derived price or stock. - A socket is a reference value, not a product: its `vendor`, its `segment` and the `motherboards` built for it. It has no status, offers or provenance. Three chassis fields point at them: `expansionSlots` (the case's expansion-slot positions), `verticalMountSlots` (the width in slots of its vertical GPU mount, or `null` when it has none) and, on the detail document only, `bundledRiser` (the riser that ships with the case, as a riser summary, or `null`). Details are on Collections and entities (https://gpuninja.com/docs/api/collections). ### Fit and can-run in brief A fit verdict is one of three values: `fits`, `check` or `does-not-fit`. A card longer than the case's clearance, or wider in slots than the case allows, is `does-not-fit`. A card whose length leaves between 0 and 10 mm of clearance is `check`, as is a pair where a length or slot count isn't recorded. Each verdict carries its `reasons` (one for length, one for slots), and a maintainer override replaces the dimensional answer. A PSU advisory compares the case's included power supply with the card's recommended wattage; it never changes the verdict. Can-run compares the card's VRAM with the model's minimum VRAM and lists only models that fit, with the spare VRAM as `headroomGb`; when either value isn't recorded, the answer is `determinable: false`. The full rules are on Compatibility (https://gpuninja.com/docs/api/compatibility). ### Changes `/api/v1/changes` lists every change record merged in the last 30 days, newest first, with each change's operation, entity, field and before and after values; an added or removed row also carries its whole contents as `values`. The window is chosen by merge time, so a record that merged late still appears; use the `mergedAt` timestamps as a polling cursor. A client that has been offline for longer than the 30-day window can't catch up from the feed: it must re-fetch every entity it watches. Older history is in the monthly archives at `/api/v1/changes/{month}`, which `archive` lists. See Changes feed (https://gpuninja.com/docs/api/changes). ## Plain-text companions The API is JSON only. Plain text lives beside the web pages instead: every chip, board, chassis and model page, every catalog page and the home page has a `.txt` companion at the same path plus `.txt`, such as `/boards/asus-rog-strix-4090.txt`, `/boards.txt` or `/boards/page/2.txt`; the home page's is `/index.txt`. The blog, docs, legal and digest pages have them too. They are served as `text/plain; charset=utf-8`. Platforms, benchmarks, motherboards, risers and sockets have no web page, so they have no `.txt` either. Two files help you find everything else: - `/llms.txt` indexes the `.txt` companions for AI agents. - `/sitemap.xml` lists every web page for crawlers, and `/robots.txt` points to it. The `.txt` files are built from the same data and wording as the HTML, with these conventions: - Absolute UTC times. Each file has a `Data as of:` line with an ISO timestamp, such as `2026-10-04T06:12:00Z`. Times in the body are written as `4 Oct 2026, 06:12 UTC`, and dates as `12 Oct 2022`. Relative times never appear, because the files are written at build time and must not age. - "Not recorded". A value that is `null` in the API appears as `Not recorded`. It is never left out, shown as `0`, or written as `N/A`. A file whose data has no timestamps says `Data as of: unknown`. - Units are always written out: `24 GB`, `450 W`, `357.6 mm`, `2,640 MHz`, `384-bit`, `3.5-slot`, `128K tokens`, `8B` parameters. Numbers use comma thousands separators. Prices carry their currency symbol, such as `$1,999.99` or `€1,799`. ## Caching Every API response and every `.txt` file is sent with `Cache-Control: public, max-age=300`, so data can be up to five minutes older than the latest deploy. Each response has an `ETag`; send it back in `If-None-Match` and an unchanged file returns `304 Not Modified`. An unchanged file keeps its `ETag` across deploys. Details, including the headers on redirects and errors, are on Caching, redirects and errors (https://gpuninja.com/docs/api/caching-and-errors). ## CORS Every response carries `Access-Control-Allow-Origin: *`, so browser code on any origin can read the API. Only simple requests work: a plain `GET` with no custom headers. Anything that triggers a CORS preflight fails, because the `OPTIONS` request returns `405`. That includes setting `If-None-Match` yourself from browser code; let the browser's own cache revalidate instead. No credentials or cookies are involved. ## Stability and versioning The `/api/v1/` contract is frozen against breaking changes. - Additive changes can happen at any time: a new property on a response object, a new endpoint, or a new value in an open vocabulary such as `verificationStatus`. Ignore properties you don't recognise, and accept `verificationStatus` values you don't know. - Closed vocabularies won't grow in v1. Every enumerated value is fixed, including `kind`, `status`, `op`, `rowOp`, `aspect`, `verdict`, `basis` and the fit reason `code`. So are `pageSize`, the 10 mm check margin, the ordering rules and the fit and can-run rules. - Nothing changes shape in v1. No property is removed, renamed or retyped, and no field that is never `null` becomes nullable. - Breaking changes ship as `/api/v2/`, beside v1, with their own search index and OpenAPI document. v1 keeps being served until its traffic, measured at the edge, stops. A new version will be announced on this page. The contract has a semantic version, `1.0.0` at launch: the minor number rises with each additive change and the patch number with editorial ones. It is the `info.version` of the OpenAPI document. The search index carries its own `formatVersion`, described under Search (https://gpuninja.com/docs/api#search). ## Search The compact search index at `/api/v1/index` holds one flat row per chip, board, chassis, model, motherboard and riser, with the fields most searches need. Download it once, cache it, revalidate it with its `ETag`, and filter it on your side. Platforms and benchmarks aren't in it. Sockets aren't either: there are few of them, and `/api/v1/sockets` lists them all. Every entry has the same properties; a property that doesn't apply to its kind is always `null` (or `[]` for `pciDeviceIds`): | Field | chip | board | chassis | model | motherboard | riser | | ---------------------------------------- | ------------- | -------------------------------------------------- | ------------ | --------------------------------- | ----------------- | --------------- | | `slug`, `kind`, `name`, `status` | Yes | Yes | Yes | Yes (`status` is always `active`) | Yes | Yes | | `vendor` | Designer | Board vendor | Vendor | Publisher | Vendor | Vendor | | `chipSlug` | `null` | The board's chip | `null` | `null` | `null` | `null` | | `vramGb` | Maximum VRAM | VRAM fitted | `null` | Minimum VRAM | `null` | `null` | | `tdpW` | Reference TDP | Board TDP | `null` | `null` | `null` | `null` | | `lengthMm` | `null` | The card's length | `null` | `null` | `null` | Cable length | | `slotWidth` | `null` | The card's slot width | `null` | `null` | `null` | `null` | | `lowestPriceUsd`, `inStock` | `null` | From offers | From offers | `null` | `null` | `null` | | `pciVendorId`, `pciDeviceIds` | PCI IDs | `null`, `[]` | `null`, `[]` | `null`, `[]` | `null`, `[]` | `null`, `[]` | | `socket` | `null` | `null` | `null` | `null` | Its socket's slug | `null` | | `pcieGen` | `null` | `null` | `null` | `null` | `null` | PCIe generation | | `speedTokPerSec` | `null` | Tokens per second on the speed reference | `null` | `null` | `null` | `null` | | `vramType`, `recommendedPsuW`, `widthMm` | `null` | Memory type, recommended PSU, height from the slot | `null` | `null` | `null` | `null` | | `powerConnectors` | `null` | `[{ "type", "count" }]`, `[]` when slot-powered | `null` | `null` | `null` | `null` | A case's clearances are deliberately left out of the index, so a "length at most" filter can never match a case; ask the compatibility (https://gpuninja.com/docs/api/compatibility) endpoints instead. A board entry doesn't repeat its chip's vendor and name: read them from the chip entry whose `slug` is the board's `chipSlug`. Entries are ordered by kind (`chip`, `board`, `chassis`, `model`, `motherboard`, `riser`), then slug. The envelope adds four fields to `apiVersion`, `kind` and `asOf`: - `formatVersion` is the index format as `MAJOR.MINOR`, `1.0` at launch. The major number equals the API version; the minor number rises when the index gains a property. Accept any `1.x`. - `datasetHash` is `sha256:` plus 64 hex digits. It changes exactly when some published value changes, so you can compare it with a copy you hold. - `speedReference` names what `speedTokPerSec` measures: the benchmark `llama-cpp-tg128` on the model `llama-3-1-8b-instruct-q4-k-m`. - `counts` gives the number of entries of each kind. The same search library is used by the website, the MCP servers and the desktop app, and it is open source in the gpuninja-mcp repository (https://github.com/gpuninja/gpuninja-mcp). Its limits and defaults are: | Search fact | Value | Meaning | | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- | | `LIMITS.defaultLimit` | `20` | Results per page when you don't set `limit` | | `LIMITS.maxLimit` | `1000` | The largest `limit` | | `LIMITS.maxTextLength` | `200` | Characters of search text | | `LIMITS.maxTextTokens` | `16` | Words of search text | | `LIMITS.maxSortKeys` | `3` | Sort keys per query | | `LIMITS.maxFilterDepth` | `8` | Nesting depth of a filter | | `LIMITS.maxFilterNodes` | `64` | Nodes in a filter | | `LIMITS.maxInValues` | `10000` | Values in one `in` filter | | `LIMITS.maxIssues` | `20` | Validation issues reported for one query | | `DEFAULT_SORT.withText` | `[{"by":"relevance","dir":"desc"},{"by":"name","dir":"asc"}]` | Default order when there is search text | | `DEFAULT_SORT.withoutText` | `[{"by":"name","dir":"asc"}]` | Default order without search text | | `SORT_FIELDS.chip` | `["relevance","name","vramGb","tdpW"]` | Sortable fields for chips | | `SORT_FIELDS.board` | `["relevance","name","lowestPriceUsd","vramGb","tdpW","lengthMm","slotWidth","speedTokPerSec","pricePerVramGb","recommendedPsuW","widthMm","inStock"]` | Sortable fields for boards | | `SORT_FIELDS.chassis` | `["relevance","name","lowestPriceUsd","inStock"]` | Sortable fields for cases | | `SORT_FIELDS.model` | `["relevance","name","vramGb"]` | Sortable fields for models | | `SORT_FIELDS.motherboard` | `["relevance","name"]` | Sortable fields for motherboards | | `SORT_FIELDS.riser` | `["relevance","name","lengthMm","pcieGen"]` | Sortable fields for risers | | `includeDiscontinued` | `false` | Discontinued entries are left out unless you ask for them | `pricePerVramGb` is worked out by the library from each board's `lowestPriceUsd` and `vramGb`; it is not in the index. Every order ends with `slug` ascending as a final tie-break. See Search index (https://gpuninja.com/docs/api/search) for text matching, filters and worked examples. ## OpenAPI and generated clients `https://gpuninja.com/api/v1/openapi.json` is an OpenAPI 3.1.1 document with every path above and every response schema, as JSON Schema 2020-12. It is licensed Apache 2.0, so you may generate, publish and sell clients made from it; the data they fetch stays CC BY 4.0. What the document tells a generator: - One `GET` per path, each with a stable `operationId` such as `listBoards`, `listBoardsPage`, `getBoard`, `getBoardFits`, `getModelRunsOn`, `getSearchIndex`, `getChanges` and `getChangesArchive`. - One tag per collection, plus `search` and `changes`, so generators that group operations by tag produce a `BoardsApi`, a `ChipsApi` and so on. - No authentication. `security` is an empty list, so a generated client sends no credentials. - One server, `https://gpuninja.com`. Point a client at another origin only for testing. - `200` has a JSON schema; `404` has none, because the body is the site's HTML error page. Treat a `404` as "no such resource" and don't parse it. - `page` is never a slug. `/api/v1/boards/page/{page}` and `/api/v1/boards/{slug}/fits` have the same shape, and some linters flag them as ambiguous. They aren't: `page`, `index` and `404` are reserved and never used as slugs. For example, TypeScript types with openapi-typescript (https://openapi-ts.dev): ```bash npx openapi-typescript https://gpuninja.com/api/v1/openapi.json -o gpuninja.d.ts ``` Or a client in another language with OpenAPI Generator (https://openapi-generator.tech): ```bash npx @openapitools/openapi-generator-cli generate -g python \ -i https://gpuninja.com/api/v1/openapi.json -o gpuninja-client ``` Remember the open-schema rule under Stability and versioning (https://gpuninja.com/docs/api#stability-and-versioning): new properties can appear at any time, and no schema forbids unknown ones. Generate in a mode that keeps or ignores unknown properties rather than rejecting the response, and regenerate when `info.version` rises to pick up new fields. A generated API reference at `/docs/api/reference`, listing each endpoint and schema in a readable form, is planned. Until it ships, Collections and entities (https://gpuninja.com/docs/api/collections) and the other pages of this section are the field reference. ## In this section - [Collections and entities](https://gpuninja.com/docs/api/collections): The nine collections, how paging works, and the fields of every entity summary and detail document, with provenance and frozen records. - [Compatibility](https://gpuninja.com/docs/api/compatibility): Which cases a card fits, which cards fit a case, and which AI models a card can run, with the exact rules behind each answer. - [Search index](https://gpuninja.com/docs/api/search): The compact search index of chips, boards, cases, models, motherboards and risers, its fields per kind, and how to search it with the open-source library. - [Changes feed](https://gpuninja.com/docs/api/changes): The machine-readable record of every data change in the last 30 days, the monthly archives, and how to poll them to keep a local copy current. - [Caching, redirects and errors](https://gpuninja.com/docs/api/caching-and-errors): Response headers, ETag revalidation, CORS limits, redirects for renames and trailing slashes, and what a 404 or 405 looks like.