Skip to content
pokemontcgapi.com
Documentation

Get a card

Fetch one card by our id or its alternate {set}-{number} id, with prices, images and translations on request.

GET/v1/cards/{id}1 creditfree plan

Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600

Objects returned

Returns the card object directly, not wrapped in a collection envelope. A missing id is 404 CARD_NOT_FOUND, which is a statement about the catalogue — cache it, do not poll it.

This is the price endpoint. include=prices expands the full per-source breakdown for the card, and the card row itself already carries index_eur and last_price_at whether you ask for the relation or not. The response below is a real one, trimmed at the fifteenth price row.

Path parameters

Path parameters
NameTypeDefaultDescription
id requiredstringOur public id (bs-4) or the alternate legacy_id, a string of the same {set}-{number} form (base1-4). Both resolve to the same row, so ids you already have stored need no translation table.

Query parameters

Query parameters
NameTypeDefaultDescription
selectstringComma-separated card fields to return. id is always included. camelCase and snake_case both resolve, so nationalPokedexNumbers works and comes back as national_pokedex_numbers. An unknown name is INVALID_SELECT_FIELD, with the full list in details.valid_fields.
includestringComma-separated relations to expand: prices, translations, images, set, artist. Each one is an extra join, so ask only for what you render. include=prices is how you get the per-source price breakdown. legalities is not an accepted value and is rejected with 400 INVALID_INCLUDE.
langstringLocale for the card name: en, ja, fr, de, es, it — the six with translation rows in the catalogue. A card with no translation in the requested locale falls back to English rather than to null.

Headers

Headers
NameTypeDefaultDescription
X-Api-Key requiredstringYour API key. Authorization: Bearer <key> is accepted as an alias.
If-None-MatchstringSend back the ETag you stored. The API returns a strong ETag on every catalogue response, and a 304 is a header exchange: no body, no database row read.

Example request

curl -s -G "https://api.pokemontcgapi.com/v1/cards/base1-4" \
  --data-urlencode "include=prices" \
  -H "X-Api-Key: $PTCG_API_KEY"

Example response

200 OK · Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600

response.json
{
  "id": "bs-4",
  "legacy_id": "base1-4",
  "name": "Charizard",
  "number": "4",
  "number_sort": 4,
  "supertype": "Pokémon",
  "hp": 120,
  "rarity": "Rare Holo",
  "tcgplayer_id": 42382,
  "cardmarket_id": 273699,
  "index_eur": 561.84,
  "last_price_at": "2026-08-26T19:03:20.955Z",
  "row_version": 6,
  "updated_at": "2026-08-26T17:47:39.900Z",
  "set_code": "bs",
  "set_name": "Base",
  "set_total": 134,
  "ptcgo_code": "BS",
  "release_date": "1999-01-09",
  "print_region": "WEST",
  "series": "Base",
  "artist_name": "Mitsuhiro Arita",
  "artist_slug": "mitsuhiro-arita",
  "prices": [
    {
      "source": "CARDMARKET",
      "variant": "LOW",
      "basis": "ASKING",
      "amount": 599.9,
      "currency": "EUR",
      "locale": "en",
      "condition": "NEAR_MINT",
      "printing": null,
      "grading": null,
      "as_of": "2026-09-01",
      "sample_n": null,
      "provenance": "Cardmarket"
    },
    {
      "source": "CARDTRADER",
      "variant": "LOW",
      "basis": "ASKING",
      "amount": 1250.64,
      "currency": "EUR",
      "locale": "en",
      "condition": "NEAR_MINT",
      "printing": null,
      "grading": null,
      "as_of": "2026-09-01",
      "sample_n": 4,
      "provenance": "CardTrader"
    },
    {
      "source": "TCGPLAYER",
      "variant": "LOW",
      "basis": "GUIDE",
      "amount": 510,
      "currency": "USD",
      "locale": "en",
      "condition": null,
      "printing": "HOLOFOIL",
      "grading": null,
      "as_of": "2026-07-30",
      "sample_n": null,
      "provenance": "TCGplayer"
    },
    {
      "source": "EBAY",
      "variant": "MEDIAN_GRADED",
      "basis": "ASKING",
      "amount": 400,
      "currency": "USD",
      "locale": "en",
      "condition": null,
      "printing": null,
      "grading": {
        "company": "PSA",
        "score": "1"
      },
      "as_of": "2026-08-26",
      "sample_n": 7,
      "provenance": "eBay"
    },
    {
      "source": "PRICECHARTING",
      "variant": "MEDIAN_GRADED",
      "basis": "GUIDE",
      "amount": 20061.4,
      "currency": "USD",
      "locale": "en",
      "condition": null,
      "printing": null,
      "grading": {
        "company": "PSA",
        "score": "10"
      },
      "as_of": "2026-08-24",
      "sample_n": null,
      "provenance": "PriceCharting"
    },
    {
      "source": "PTCG_INDEX",
      "variant": "INDEX",
      "basis": "DERIVED",
      "amount": 556.23,
      "currency": "EUR",
      "locale": "en",
      "condition": null,
      "printing": null,
      "grading": null,
      "as_of": "2026-09-02",
      "sample_n": 16,
      "provenance": "pokemontcgapi composite index"
    }
  ]
}

Errors

Every error body carries error.code, error.message and error.request_id. Switch on the code, never on the message.

Errors returned by this endpoint
StatusCodeWhen
401MISSING_API_KEYNo X-Api-Key header and no bearer token on a route that requires one.
401INVALID_API_KEYThe key does not match any account.
404CARD_NOT_FOUNDNo card with that id. Both our id (bs-4) and the alternate {set}-{number} id (base1-4) resolve here.
400INVALID_SELECT_FIELDA name in select is not a card field.
400INVALID_INCLUDEA name in include is not a known relation.
400INVALID_PARAMETERA query parameter has the wrong type or an unsupported value — a non-integer limit, an unknown lang, an unknown region, a sort key that is not sortable.

The full taxonomy, with what to do about each code, is on the errors page.

Reading the price rows

One row per live series. source says who observed it, basis says what kind of number it is (SOLD a completed sale, ASKING a listing, GUIDE a published guide value, DERIVED ours), and currency is the currency the row was observed in — a single card returns USD and EUR rows side by side, and they are not converted for you.

MEDIAN_GRADED rows carry grading with the company and the score, so a PSA 10 and a CGC 10 stay separate numbers. Every row carries provenance and as_of; display the provenance wherever you display the price. The sources, their delays and how the composite is built are on price methodology.

The other relations

include takes any comma-separated subset of six names. What each one costs you is one join:

include relations
RelationShapePopulated today
pricesArray of price rowsYes — a dozen or more rows on a well-covered card
imagesArray of image rowsYes — one FRONT / NORMAL rendition per card
setOne set objectYes
artistOne artist objectYes, where the card is attributed
translationsArray of { locale, name }Yes — en, ja, fr, de, es, it
legalitiesNot an accepted value: 400 INVALID_INCLUDE. Format legality is not in the catalogue, and an empty array would look like an answer
include-images-set-artist.json
{
  "images": [
    {
      "face": "FRONT",
      "size": "NORMAL",
      "locale": null,
      "url": "https://media.rarebit.app/cards/BASE/4-normal.webp",
      "image_source": "rarebit-media",
      "width": null,
      "height": null
    }
  ],
  "set": {
    "id": "bs",
    "code": "bs",
    "slug": "base",
    "legacy_id": "base1",
    "name": "Base",
    "series": "Base",
    "region": "WEST",
    "release_date": "1999-01-09",
    "total": 134,
    "printed_total": 102,
    "ptcgo_code": "BS",
    "symbol_url": null,
    "logo_url": "https://media.rarebit.app/sets/BASE/logo-normal.webp",
    "updated_at": "2026-08-26T17:47:39.900Z"
  },
  "artist": { "slug": "mitsuhiro-arita", "name": "Mitsuhiro Arita", "card_count": 760 }
}

translations returns an array of { locale, name }, one entry per locale that has a name for this card — never every locale, and never a null-filled row for the ones that do not. A card with no entry for the locale you asked for in lang comes back with its English name.

Image dimensions are null

The API returns one rendition per card and does not measure it on ingest, so width and height come back null. Reserve layout space with a fixed aspect ratio rather than reading those two fields.

view this page as markdown