Introduction
A REST API for Pokemon TCG cards, sets, artists and prices, with one response shape and pagination that never repeats or drops a row.
Everything is JSON over HTTPS. Every endpoint is a GET unless it uploads something, every response is cacheable unless it is about your account, and every error has a code you can switch on.
The base URL is https://api.pokemontcgapi.com. There is no sandbox host: the free tier is the sandbox.
Start here
| Page | What it answers |
|---|---|
| Quickstart | First successful request, in three minutes. |
| Authentication | Where the key goes, and which key type to use in a browser. |
| Query syntax | The whole query grammar, and which fields hold data today. |
| Pagination | Cursors, and why there is no page parameter. |
| Errors | Every code, its status, and what to do about it. |
| Versioning | What /v1 guarantees and what may change without notice. |
| API reference | One page per operation. |
What the API covers
Counts below are from GET https://api.pokemontcgapi.com/v1/status and from the collection endpoints, read on 2026-08-27. They move as the catalogue grows; the endpoint is always the current answer.
- Cards — 52,337 of them, searchable with a Lucene-style query grammar. Names, ids, collector numbers, rarity, artist, set membership and images.
- Sets — 615, across three print regions: 176 Western, 379 Japanese, 60 Chinese. Codes, slugs, alternate ids, release dates, printed and true totals.
- Six languages — card translations in
en,ja,fr,de,esandit. - Artists — 399 illustrators with maintained card counts.
- Prices — per source, in the source’s own currency, with the basis, the as-of timestamp and the provenance attached to every row. Graded rows carry the grading company and score.
What is not in here
This is a catalogue and price API that also carries card game text, in English, on the printings we hold it for — attacks, abilities, subtypes, rules text and retreat costs, roughly a third of the catalogue and four fifths of the Western printings. Format legalities are not populated at all. Every field publishes its measured fill rate on the card object, so you can tell before you integrate rather than after.
Design rules we do not break
These are the three that show up in the response body, so they are worth stating before you write any code.
| Rule | Why it exists |
|---|---|
Every sort ends with id | Without a tiebreaker, rows sharing a sort key have undefined order between queries, so paging duplicates and drops rows. With one, pagination never repeats or drops a row, at any page depth. |
| A client mistake is never a 5xx | A malformed query returns 400, not 500. On resale marketplaces a 5xx sinks the listed service level for thirty days and is excluded from quota counting — a mislabelled response is both free traffic and burnt reputation. |
Quota exhaustion is 429, not 402 | Gateways and CDNs in the middle handle 402 unpredictably — some cache it, some rewrite it. 429 QUOTA_EXCEEDED is unambiguous everywhere. |
One request, end to end
curl -s -G "https://api.pokemontcgapi.com/v1/cards" \
--data-urlencode "q=name:charizard set.code:bs" \
-H "X-Api-Key: $PTCG_API_KEY"Query fields and response keys are spelled differently
The query above uses set.code; the card that comes back carries "set_code": "bs". Queries are camelCase and dotted, responses are snake_case, and neither spelling is accepted in the other’s place. It is the one thing worth reading query syntax for before anything else.
Documentation for machines
Every page here is also served as markdown: append /md to any docs URL. `/llms.txt` indexes the whole set in the llmstxt.org format, so a coding assistant can pull the reference at integration time instead of guessing at endpoint names.