DEV Community

Mr. Rari
Mr. Rari

Posted on Fully Autonomous

A Pokémon TCG API that covers the Japanese and Chinese print runs, with prices that say where they come from

Most Pokémon TCG side projects start the same way: GET https://api.pokemontcg.io/v2/cards?q=name:charizard. It works until it does not. The catalogue is English only, the Japanese sets are missing entirely, and this summer the endpoint spent long stretches answering 500 (bindarr's issue tracker has a good specimen: "Intermittent 500 errors on card search").

We hit the same wall building RareBit, a collection tracker for European collectors whose users own Japanese cards, Italian cards, and increasingly Simplified Chinese ones. So we built the data layer we needed and opened it as an API: pokemontcgapi.com. Disclosure up front: I am one of the two people behind it, and it is a paid API with a free trial, not a free one.

Here is what is different about it, with real requests.

Three print runs, six languages

curl -s -G "https://api.pokemontcgapi.com/v1/sets" \
  --data-urlencode "region=JP" \
  -H "X-Api-Key: $PTCG_API_KEY" | jq '.meta'
Enter fullscreen mode Exit fullscreen mode

region is WEST, JP or CN. Today that is 176 Western sets, 379 Japanese and 60 Simplified Chinese, 52,337 cards in total. Every card carries its names in en, ja, fr, de, es and it under translations, and print_region tells you which physical run it belongs to, so a Japanese ピカチュウ and an English Pikachu with the same artwork are two cards, not one card with a translated name.

Prices that carry their source, basis and sample size

curl -s "https://api.pokemontcgapi.com/v1/cards/ar-71/prices" \
  -H "X-Api-Key: $PTCG_API_KEY" | jq '{card_id: .data.card_id, index: .data.index, quotes: .data.quotes[0:2], meta}'
Enter fullscreen mode Exit fullscreen mode

Trimmed to two of the eleven quotes this card has today:

{
  "card_id": "ar-71",
  "index": { "eur": 4.69, "as_of": "2026-09-10", "sample_n": 2 },
  "quotes": [
    {
      "source": "CARDMARKET", "variant": "LOW", "basis": "ASKING",
      "amount": 7.99, "currency": "EUR", "locale": "en",
      "condition": "NEAR_MINT", "printing": null, "grading": null,
      "as_of": "2026-09-09", "sample_n": 256, "provenance": "Cardmarket"
    },
    {
      "source": "TCGPLAYER", "variant": "LOW", "basis": "GUIDE",
      "amount": 4, "currency": "USD", "locale": "en",
      "condition": null, "printing": "NORMAL", "grading": null,
      "as_of": "2026-09-09", "sample_n": null, "provenance": "TCGplayer"
    }
  ],
  "meta": { "quotes": 11, "delayed_hours": 0, "withheld": ["graded", "non_english_locales"] }
}
Enter fullscreen mode Exit fullscreen mode

Every quote says which marketplace it came from, what it measures (variant: low, trend, market, 7-day average), what kind of number it is (basis: an asking price on a marketplace is not a sold price or a guide value), in which currency, for which printing, condition and locale, and how many observations sit behind it. Cardmarket rows are in EUR, TCGplayer rows in USD, and nothing is converted behind your back. index.eur is our own composite across sources, labelled as such. Graded quotes (PSA, BGS, CGC, SGC) are separate rows with a grading object; meta.withheld tells you honestly what your plan is not seeing, here graded rows and non-English locales on the trial.

The part that surprised us: prices are what your credits pay for

The API meters credits, not requests. A page of 250 cards is 1 credit. The same page with include=prices is about 40, because every card drags its price rows along. We learned this the expensive way while contributing a provider to an open-source collection manager: the first live run spent 84 credits on three searches. The fix was simple and it is the pattern I would recommend to anyone integrating a metered card API:

  • list and search without prices (names, images, translations),
  • fetch prices for the cards the user actually owns or opens,
  • cache aggressively and send If-None-Match, the API answers 304 for free.

The same scenario after the change: 8 credits. The pull request has the whole story if you want the details.

Ask your editor instead of writing the client

There is an MCP server, so Claude Code, Claude Desktop, Cursor and VS Code can query the catalogue directly:

claude mcp add pokemontcgapi --env PTCG_API_KEY=$PTCG_API_KEY -- npx -y @pokemontcgapi/mcp
Enter fullscreen mode Exit fullscreen mode

Eight read-only tools: search cards, get cards by id, get prices, list sets, list artists, reference values, catalogue status, and identify a card from a photo (25 credits). The docs are also published as llms.txt and llms-full.txt, which in practice means you can paste the URL into your agent and it writes the client for you.

There is a TypeScript SDK too (@pokemontcgapi/sdk), MIT licensed like the MCP server.

What it costs, and what it does not do yet

The trial is 800 credits, no card, granted once. Paid plans start at 29 EUR a month for 50,000 credits, commercial use allowed everywhere. Until 17 September the code EARLY50 takes 50% off the first three months of Developer and Growth.

Honest limits: card text exists for about a third of the catalogue, mostly Western; Simplified Chinese cards have no price rows yet; on the trial plan prices for non-English locales are withheld, so a Japanese card shows a price only on a paid plan.

If you are building something with Pokémon card data, I would like to hear what, and what you could not find. Reply here or write to riccardo@rarebit.app.

Top comments (0)