Skip to content

Pokémon TCG card data ​

Ruleset and calculator scripts get Pokémon TCG cards as plain objects straight from the card catalog. This page lists every field on those objects and in the catalog globals, with a real example and a few recipes.

Where the cards show up:

  • Card rules receive one card as their first argument.
  • Deck and deck set rules receive cardsById, an object keyed by card ref that holds every card in the deck (it can hold more).
  • Calculators receive cardsById as their second argument.

See the ruleset script API and the calculator script API for the full function signatures.

Card keys and deck refs ​

A Pokémon card in the catalog is a card identity: one playable card with all of its printings (reprints, alternate arts, promos) listed under printings. Two ids matter:

  • The identity id, card.id: a name slug plus a hash, like pikachu-ex--1f29b66b68bc.
  • A printing id: <set code>-<collector number>, like sv2-11 or svp-106.

Decks store printing ids, so a deck is a map like { "me2pt5-276": 2, "svp-106": 2 }. cardsById is keyed by those same printing ids, and each one points to its identity. In that example both refs are Pikachu ex, so cardsById["me2pt5-276"] and cardsById["svp-106"] are the same card and share one card.id:

  • Count copies of "the same card" by card.id (or card.name), not by ref. The deck above runs 4 Pikachu ex.
  • To read the printing a ref points to, find it in the list: card.printings.find((p) => p.id === ref).
  • ctx.globals.printings[ref] gives the identity id for any printing id, when globals are available.

A card rule gets the identity card itself, so card.id is always the identity id, never a printing id.

Guard against a missing card before reading from it: cardsById[ref] can be undefined when the catalog doesn't know a ref.

Card fields ​

Every card, in every game, has these top-level fields:

PropertyTypeDescription
idstringCatalog id of the card identity ("01DE012" in LoR, "pikachu-ex--1f29b66b68bc" in Pokémon).
namestringDisplay name in the catalog locale.
setCodestringSet of the card, or of its default printing ("set1", "sv2", "OGN").
collectible?booleanFalse for cards that can't go in a deck (LoR tokens and level-ups).
assets?CardCatalogCardAssetContract[]Images of the card's default printing.
printings?CardPrintingContract[]Every printing of the identity, default printing first. Absent in LoR.
hasImage?booleanFalse when none of the card's printings has an image in this language. Absent means it has one.
game?TGameDataGame-specific fields; see the per-game *CardGameData type.

Printings ​

Each entry of printings (CardPrintingContract):

PropertyTypeDescription
idstringPrinting id; deck refs use it ("sv2-11" for Pokémon, "ogn-030-298" for Riftbound).
setCodestringSet the printing belongs to ("sv2", "OGN").
number?stringCollector number within the set.
language?stringLanguage of the printing, when it is not the catalog's own.
releaseDate?stringRelease date as the source gives it ("2023/06/09").
assets?CardCatalogCardAssetContract[]This printing's own images.
variants?CardVariantContract[]Treatments of this printing (foil, alternate art, …).
metadata?JsonObjectExtra per-printing data (rarity, artist, store ids); game-specific.

Each entry of a printing's variants:

PropertyTypeDescription
idstringVariant id, usually <printing id>:<kind> ("ogn-030-298:normal").
kind?stringTreatment kind ("normal", "foil", "alternate_art"); values are per game.
label?stringDisplay label, when the kind alone is not enough.
metadata?JsonObjectExtra per-variant data; game-specific.

Each entry of assets (on the card and on each printing):

PropertyTypeDescription
kindCardAssetKindWhat the image shows: "card" (framed render), "full" (full art), "icon", "banner", "slice", "portrait", …
urlstringImage URL.
format?CardAssetFormatImage format ("webp"), when known.
width?numberWidth in pixels, when known.
height?numberHeight in pixels, when known.
metadata?JsonObjectExtra per-asset data; game-specific.

Game fields (card.game) ​

Everything specific to the Pokémon TCG lives on card.game. The type tokens (supertype, subtypes, types, Energy costs, weakness types) are English in every language, so they are safe to compare. Names and text follow the viewer's language.

Watch for two things:

  • supertype is "Pokemon", without the accent. Compare against both spellings if in doubt.
  • hp, damage and level are strings, as printed ("60+"). Convert with Number() before doing math.
PropertyTypeDescription
associatedCardRefs?string[]Reserved for related-card ids; not emitted by the catalog today.
abilities?PokemonAbilityPayload[]Abilities, in printed order.
artist?stringIllustrator of the default printing.
attacks?PokemonAttackPayload[]Attacks, in printed order.
clientName?stringPokémon TCG Live display name when it differs from the printed name.
convertedRetreatCost?numberNumber of Energy in the retreat cost (length of retreatCost).
defaultPrintingId?stringPrinting id of the identity's representative (default art) printing.
digitalOnly?booleanTrue when every printing exists only in Pokémon TCG Live.
evolvesFrom?stringPrinted "Evolves from" name ("Pikachu").
evolvesFromIds?string[]Catalog ids of the identities this card evolves from.
evolvesTo?string[]Printed "Evolves to" names.
evolvesToIds?string[]Catalog ids of the identities this card evolves into.
flavorText?stringFlavor text, markup removed.
hp?stringPrinted HP as a string ("120"); convert with Number() before comparing.
identityAliases?string[]Older identity ids that now point to this card (ids it had before its Western release), so saved refs to them keep working.
inMarket?booleanFalse when the card has no printing in this language's market (for example a Japan-only card in the English catalog). Absent means in-market.
isProvisional?booleanTrue while the card is an unofficial pre-release entry, read off an official reveal before card data is published. Cleared when the official data lands.
isLiveAvailable?booleanTrue when at least one printing is playable in Pokémon TCG Live.
legalities?JsonObjectFormat key (standard, expanded, unlimited, standard-jp, expanded-jp, standard-future) to "Legal", "Illegal" or "Banned". Compare case-insensitively.
level?stringPrinted level on older cards ("45").
liveCardId?stringPokémon TCG Live card id.
nationalPokedexNumbers?number[]National Pokédex numbers of the Pokémon on the card ([25]); several for tag teams.
numberstringCollector number of the default printing ("276"); the set is the card's setCode.
rarity?stringRarity of the default printing as printed ("Rare", "Special Illustration Rare").
regulationMark?stringRegulation mark letter ("G", "H"), which drives Standard rotation.
resistances?PokemonResistancePayload[]Resistances, usually zero or one.
retreatCost?string[]Energy type per retreat-cost Energy (["Colorless", "Colorless"]).
rules?string[]Rule-box lines (Pokémon ex / V / Tera rules, Trainer rules).
subtypes?string[]Stage and kind tokens (["Basic", "ex"], ["Stage 1"], ["Item"], ["Supporter"]).
supertypestring"Pokemon" (unaccented), "Trainer" or "Energy".
types?string[]Energy types of a Pokémon (["Psychic"]); absent on Trainers and Energy.
weaknesses?PokemonWeaknessPayload[]Weaknesses, usually zero or one.

Abilities ​

Each entry of abilities:

PropertyTypeDescription
namestringAbility name ("Quick Search").
textstringEffect text.
typestring"Ability", "Poké-Power", "Poké-Body" etc., as printed.

Attacks ​

Each entry of attacks:

PropertyTypeDescription
convertedEnergyCost?numberNumber of Energy the attack needs (length of cost).
cost?string[]Energy type per required Energy (["Lightning", "Colorless"]).
damage?stringPrinted damage as text ("30", "60+", "×"); absent when the attack does no printed damage.
namestringAttack name.
text?stringEffect text.

Weaknesses ​

Each entry of weaknesses:

PropertyTypeDescription
typestringEnergy type the Pokémon is weak to ("Fighting").
valuestringPrinted modifier ("×2", "+20").

Resistances ​

Each entry of resistances:

PropertyTypeDescription
typestringEnergy type the Pokémon resists ("Metal").
valuestringPrinted modifier ("-30").

Globals (ctx.globals) ​

The catalog's globals hold set details and the printing index that maps every printing id to its identity.

When globals are available

Globals are passed to ruleset scripts as ctx.globals (the last argument). Calculators may not receive ctx at all, and a ruleset can run without it too. Always check ctx && ctx.globals before using them.

PropertyTypeDescription
printings?Record<string, string>Printing id → owning card identity id, covering every emitted printing.
sets?Record<string, PokemonCatalogSetLookupEntry>Sets by set code ("sv2", "me2pt5").

Set entries ​

Each entry of sets:

PropertyTypeDescription
images?PokemonSetImagesPayloadSet logo and symbol image URLs.
labelstringSet name in the catalog locale ("Paldea Evolved").
printedTotal?numberCard count printed on the cards (the /193 in 001/193).
ptcgoCode?stringPTCGO/PTCG Live set abbreviation (e.g. "PAL") used in text deck lists.
releaseDate?stringRelease date as YYYY/MM/DD.
series?stringSeries ("Scarlet & Violet").
total?numberTotal cards in the set, secret rares included.

Set images ​

A set entry's images:

PropertyTypeDescription
logo?stringSet logo image URL.
symbol?stringSet symbol image URL.

Example card ​

Pikachu ex, trimmed to two printings, one image each and two identity aliases:

json
{
  "id": "pikachu-ex--1f29b66b68bc",
  "name": "Pikachu ex",
  "setCode": "me2pt5",
  "collectible": true,
  "assets": [
    {
      "kind": "card",
      "url": "https://cdn.turny.gg/cards/pokemon/assets/me2pt5-276-en-card-685c27781bd507cac386d4a882d063dedea2430e20472857fe1881360eae4777.webp"
    }
  ],
  "printings": [
    {
      "id": "me2pt5-276",
      "setCode": "me2pt5",
      "number": "276",
      "releaseDate": "2026/01/30",
      "assets": [
        {
          "kind": "card",
          "url": "https://cdn.turny.gg/cards/pokemon/assets/me2pt5-276-en-card-685c27781bd507cac386d4a882d063dedea2430e20472857fe1881360eae4777.webp"
        }
      ],
      "variants": [],
      "metadata": {
        "rarity": "Special Illustration Rare",
        "regulationMark": "H",
        "artist": "booota"
      }
    },
    {
      "id": "svp-106",
      "setCode": "svp",
      "number": "106",
      "releaseDate": "2023/01/01",
      "assets": [
        {
          "kind": "card",
          "url": "https://cdn.turny.gg/cards/pokemon/assets/svp-106-en-card-6834a96f03cf2394d164d4c948035eddc63428fcfd0c08d201e14064fe9b21dd.webp"
        }
      ],
      "variants": [],
      "metadata": {
        "rarity": "Promo",
        "regulationMark": "H",
        "artist": "takuyoa"
      }
    }
  ],
  "game": {
    "supertype": "Pokemon",
    "subtypes": ["Basic", "ex"],
    "hp": "200",
    "types": ["Lightning"],
    "rules": [
      "Pokémon ex rule: When your Pokémon ex is Knocked Out, your opponent takes 2 Prize cards."
    ],
    "attacks": [
      {
        "name": "Thunderbolt",
        "cost": ["Lightning", "Lightning", "Colorless"],
        "convertedEnergyCost": 3,
        "damage": "120"
      }
    ],
    "weaknesses": [{ "type": "Fighting", "value": "×2" }],
    "retreatCost": ["Colorless"],
    "convertedRetreatCost": 1,
    "number": "276",
    "nationalPokedexNumbers": [25],
    "rarity": "Special Illustration Rare",
    "regulationMark": "H",
    "artist": "booota",
    "legalities": {
      "expanded": "Legal",
      "expanded-jp": "Legal",
      "standard": "Legal",
      "standard-future": "Legal",
      "standard-jp": "Legal",
      "unlimited": "Legal"
    },
    "identityAliases": ["pikachu-ex--1f4e7709a44c", "pikachu-ex--3f6f59171eb0"],
    "defaultPrintingId": "me2pt5-276"
  }
}

Common recipes ​

js
// Calculator: Pokémon, Trainer and Energy counts.
export default function compute(pile, cardsById) {
  const counts = { Pokémon: 0, Trainer: 0, Energy: 0 };

  Object.keys(pile).forEach((ref) => {
    const game = (cardsById[ref] && cardsById[ref].game) || {};
    const supertype = game.supertype === "Pokemon" ? "Pokémon" : game.supertype;

    if (counts[supertype] !== undefined) {
      counts[supertype] += pile[ref];
    }
  });

  return {
    widgets: [
      {
        kind: "donut",
        label: "Supertypes",
        segments: Object.keys(counts).map((name) => ({
          label: name,
          value: counts[name],
        })),
      },
    ],
  };
}
js
// Card rule: legal in Standard. Legality text is compared case-insensitively.
export default function validateCard(card) {
  const legalities = (card.game && card.game.legalities) || {};
  const standard = String(legalities.standard || "").toLowerCase();

  if (standard === "legal") {
    return true;
  }

  return {
    valid: false,
    issues: [{ message: card.name + " is not legal in Standard." }],
  };
}
js
// Card rule: no Special Illustration Rares or Hyper Rares.
export default function validateCard(card) {
  const rarity = (card.game && card.game.rarity) || "";

  if (rarity !== "Special Illustration Rare" && rarity !== "Hyper Rare") {
    return true;
  }

  return {
    valid: false,
    issues: [{ message: card.name + " is a " + rarity + "." }],
  };
}
js
// Calculator: copies per card identity, so reprints count together.
export default function compute(pile, cardsById) {
  const copies = {};
  const names = {};

  Object.keys(pile).forEach((ref) => {
    const card = cardsById[ref];
    const id = card ? card.id : ref;

    copies[id] = (copies[id] || 0) + pile[ref];
    names[id] = card ? card.name : ref;
  });

  return {
    widgets: [
      {
        kind: "table",
        label: "Copies",
        columns: ["Card", "Copies"],
        rows: Object.keys(copies).map((id) => [names[id], copies[id]]),
      },
    ],
  };
}
js
// Calculator: average HP of the Pokémon in the deck.
export default function compute(pile, cardsById) {
  let total = 0;
  let count = 0;

  Object.keys(pile).forEach((ref) => {
    const game = (cardsById[ref] && cardsById[ref].game) || {};
    const hp = Number(game.hp);

    if (hp > 0) {
      total += hp * pile[ref];
      count += pile[ref];
    }
  });

  return {
    widgets: [
      {
        kind: "stat",
        label: "Average HP",
        value: count > 0 ? Math.round(total / count) : 0,
      },
    ],
  };
}

Turny.gg documentation