Skip to content
pokemontcgapi.com

Blog

Japanese and Chinese catalogues: what a developer needs to know

Three print regions, each its own catalogue: ids, names, twins, prices and the gaps. How to import the Japanese or Chinese line, and what a null means there.

Published catalogue

Most card databases cover the international print line and stop, and the apps built on them inherit the blind spot: a collector who buys Japanese boxes, or a shop in Hong Kong, finds half of their binder missing. The Japanese line releases first and has more sets than the Western one; the Simplified Chinese line is younger and growing. This article is how the API models the three lines, how to import one, and where the data is thinner than you would like, so that you find out here and not from a user.

A region is a catalogue, not a translation

A set carries region and a card carries print_region, with three values: WEST, JP and CN. A Japanese set is not the translation of a Western one. It has its own code, its own card list and numbering, its own release date, and often cards that never crossed the ocean. So the API does not merge the lines; it keeps each as a catalogue of its own, and a Japanese card is a card in its own right, with an id, a number, a rarity, an illustrator and an image.

Do not infer the region from the shape of a code. Codes are short and the lines have grown side by side for years, so two sets can look alike on paper and be printed on different continents. Read region off the set, or print_region off the card, and filter on it.

GET /v1/sets?region=JP            # the Japanese sets, with their own codes and dates
GET /v1/cards?q=set.region:JP     # any card search, narrowed to Japanese printings
GET /v1/sets/{code}/cards         # one set, whichever line it belongs to

Importing one line

The flat list in id order is the cheapest way to take a whole line: one loop, limit=250, follow links.next until it is absent. There is no need to discover the sets first and page each one, which costs several times as many requests. Each page costs 1 credit. The quickstart has the dated request counts for both lines, measured by paging them to the end and checking every returned card against the requested region.

# One print line, flat, in id order: follow links.next until it is absent.
curl -s -H "X-Api-Key: $PTCG_API_KEY" \
  "https://api.pokemontcgapi.com/v1/cards?limit=250&orderBy=id&q=set.region%3AJP"

# The Simplified Chinese line is the same loop with CN.
curl -s -H "X-Api-Key: $PTCG_API_KEY" \
  "https://api.pokemontcgapi.com/v1/cards?limit=250&orderBy=id&q=set.region%3ACN"

After the first import, do not re-read the list. GET /v1/changes?kind=CARD,SET reports every row that changed since a position you keep, written by database triggers, so a mirror of the Japanese line stays current at the cost of one small call a day. The coverage page shows, per region, the earliest and latest set held, read from the API when you open it; that is where to check that a set you expect has landed.

Names: which language you get, and why it is not the region

Two things get confused here, so the API keeps them apart. The region says where a card was printed. lang says which language you want the card name in. lang=ja on a Western card returns its Japanese name where we hold one; a Japanese card has a Japanese name to begin with, and lang=en gives you its English name where we hold one. A missing translation falls back to English rather than returning an empty string, so a client can always print something, and a name that comes back in English on a lang=zh request is the signal that the Simplified Chinese name is not held yet.

The locales the API accepts and the locales it actually holds names for are two different lists, and the coverage page publishes both, with the method. Accepting a value is not the same as holding data for it; the same page says which is which.

Twins across the ocean

Where we know that a Western card and a Japanese card are the same printing in two languages, the Western card carries jp_twin_id, and requesting that id returns the Japanese card. The pairing is recorded, not guessed from the artwork, and it is not complete: treat a null as "unknown", never as "was not printed in Japan". There is no automatic cross-region mapping, and we would rather serve a null than a wrong twin, because the twins are exactly the cards whose prices differ most between the two markets.

The photo route makes the same choice. When the image of a card cannot be told apart from its reprint or its Japanese twin, recognition answers ambiguous with the candidates listed and id null, instead of picking one and being wrong half the time on the most valuable cards.

Ids, variants, and the 404 that helps

Ids are stable strings built from the set code and the number. Japanese codes are bare, Chinese ones carry a cn- prefix, and a few cards exist only as printed variants, with a -v1, -v2 suffix on the id. When a request names a bare id that the catalogue holds only as a variant, or a Chinese id without its prefix, the API answers 404 CARD_NOT_FOUND with did_you_mean set to a real printing and, when there are several, details.variants listing them. Read those fields before showing the user a dead end: the card is there, under a slightly different id.

Prices on Japanese and Chinese cards

The price rows have the same shape on every line: source, basis, currency, locale, date, sample size. Japanese printings are priced where a source covers them, and coverage is uneven across eras, thinner on the older sets. The Chinese line has fewer sources still. The honest way to check is the per-region section of the coverage page, which reports how many sources and which currencies a probe card from each region returns today, rather than a sentence in an article that will age. A price call costs 2 credits whatever the region.

One plan rule matters here. Rows whose locale is not English are served from the Developer plan up; on the trial they are withheld and meta.withheld says so with non_english_locales. A Japanese card's rows are mostly ja, so a trial key sees the catalogue in full but a shorter price table. That is the plan doing what it says, not a gap in the data, and the response tells you which it is.

What is null there, and what it means

The nulls a client will meet on the Japanese and Chinese lines, and how to read each
Field or filterOn Japanese and Chinese cards
attacks, abilities, rulesNull. Game text is held in English for Western printings only. Null means "not held", not "has none".
jp_twin_id on a Western cardNull when the pairing is not recorded. Unknown, not absent.
region=KR, lang=koAccepted, and answered with an empty page. There are no sets printed in Korea in the catalogue today.
release_date on a setPresent on the sets of every line; use it to order, since codes do not sort by date.
image_urlOne image per card on every line, including the Chinese one.

The images deserve a sentence, because we got them wrong once. In September we found that part of the Chinese line had been given pictures matched by card name rather than by set and number, so a promo and a regular printing with the same name could share a picture. We replaced them with images keyed by set and number and rebuilt the recognition index on top. If you cached Chinese images before then, refresh them; GET /v1/changes?kind=IMAGE lists the rows that changed.

And the line that is not there: a price source we use offers a price line for cards printed in Korea alongside the Japanese ones, and we have not loaded it. Until we do, the API accepts the region and holds nothing for it, and every page on this site says so rather than implying otherwise. When it lands, the coverage page will show it before this article is updated.

Practical rules

  1. Filter by print_region or set.region, never by the look of a code or the language of a name.
  2. Import a line flat, in id order, then follow /v1/changes. Never re-page the catalogue to find what is new.
  3. Show a null twin as "unknown", a null attack as "not held", and an empty region=KR page as "not covered", because those are three different things to a user.
  4. On a 404, read did_you_mean and details.variants before giving up on the id.
  5. Read as_of and locale on every price row you display, and expect fewer rows per Japanese card than per Western card.

Where to go next

The Japanese card API page has the set and card shapes with a live example. The coverage page carries every count this article declined to write, read from the API. The query syntax lists the fields a search can narrow on.

Questions

Does the API include Japanese-exclusive sets?
Yes. The Japanese line is its own region with its own sets, including those never released in the West, each with its own codes, numbering and dates. List them with GET /v1/sets?region=JP. Japanese card API
How do I match a Japanese card to its English printing?
Western cards carry jp_twin_id where the pairing is recorded; request that id for the Japanese printing. A null means the pairing is unknown, not that there is no Japanese printing. There is no automatic mapping across regions.
Are there cards printed in Korea?
Not today. The API accepts region=KR and lang=ko and answers with an empty page, not an error. The coverage page lists the regions held, measured live, and will show a fourth line before any article does. Coverage, measured live

Keep reading

view this article as markdown