Documentation

/v2/cards

Beta

Preview of the next cards API: graded cards and multi-region localized pricing.

Looking for the stable API?This is the v2 beta. Every existing integration should stay on /cards (v1), which is unaffected and remains the recommended endpoint for production use.
GEThttps://api.justtcg.com/v2/cards
Beta:/v2/cards is in beta. The shape below is finalized but may still change before general availability. For now, v2 covers the /cards endpoint only, so /games and /sets stay on v1. Your existing v1 integration keeps working exactly as before, so you can adopt v2 one call at a time, at your own pace. New to v2? See migrating from v1.
card_id
uuid | slug
Optional
Look up one card directly. Accepts either a UUID or a legacy v1 slug.
variant_id
uuid | slug
Optional
Look up one variant directly. This is the fastest lookup. Accepts either a UUID or a legacy slug.
tcgplayer_id
string
Optional
Look up one card by its TCGplayer product ID, same as v1's tcgplayerId.
tcgplayer_sku
string
Optional
Look up one variant by its TCGplayer SKU ID, same as v1's tcgplayerSkuId.

Prices are quoted per region instead of converted between currencies — see Localized pricing for how the markets array works.

regions
string
Optional
A comma-separated list of region codes, listed in priority order (not case sensitive). The first region is your primary market. Currently only NA returns data; the other codes are reserved for regions rolling out later. Each region beyond the first adds to the request cost.
Default: NA
NAEUUKJPOCELATAMOTHER…ISO country codes

Graded cards (PSA, BGS, CGC, and more) are one of the biggest additions in v2 — see Graded cards for how they fit into the response shape. The params below are how you request them.

Response

typescript — request.ts
request.ts
// BETA: the justtcg-js SDK gains /v2 support after v2 ships. Until then, call
// the endpoint directly. Note: 'regions' defaults to NA and 'markets' replaces
// the flat price fields.
const params = new URLSearchParams({
  game: "pokemon",
  regions: "eu,na",   // optional (defaults to NA); first region is the primary market
  graded: "include",  // raw + graded variants (premium tier)
});

const res = await fetch(`https://api.justtcg.com/v2/cards?${params}`, {
  headers: { "x-api-key": process.env.JUSTTCG_API_KEY! },
});
const { data } = await res.json();

// price now lives per-region under markets[]
const eu = data[0].variants[0].markets.find((m) => m.region === "EU");
console.log(eu?.price, eu?.currency);
json — response · 200 OK (BETA)
response · 200 OK (BETA)
// GET /v2/cards?game=pokemon&regions=eu,na&graded=include&include=periods.7d,price_history.7d
// 200 OK
// RateLimit: limit=500000, remaining=499958, reset=...
// Link: <https://api.justtcg.com/v2/cards?...&cursor=eyJvIjoyMH0>; rel="next"
{
  "data": [
    {
      "id": "9b2e4d1a-1111-5v5v-aaaa-000000000000",   // card UUID (native)
      "slug": "pokemon-base-set-charizard-4",           // legacy v1 id
      "name": "Charizard",
      "game": { "id": "pokemon", "name": "Pokemon" },
      "set": { "id": "base-set-pokemon", "name": "Base Set" },
      "number": "4",
      "rarity": "Rare Holo",
      "external_ids": { "tcgplayer": "42445", "scryfall": null, "mtgjson": null },
      "variants": [
        {
          "id": "d41f-raw-uuid",
          "slug": "pokemon-base-set-charizard-4-near-mint-holofoil",
          "type": "raw",
          "condition": "Near Mint",
          "printing": "Holofoil",
          "language": null,
          "grading": null,
          "markets": [
            {
              "region": "EU",              // markets[0] = primary market (drives sort/filter)
              "currency": "EUR",
              "price": 142.30,             // observed EU price; null if none observed
              "updated_at": 1765635970,
              "change_24h_pct": -1.8,
              "periods": {
                "7d": { "change_pct": -3.1, "avg": 148.0, "min": 140.0, "max": 151.2 }
              },
              "price_history": [
                { "t": 1765550000, "p": 150.0 },
                { "t": 1765636400, "p": 142.3 }
              ]
            },
            {
              "region": "NA",             // requested explicitly as the USD fallback reference
              "currency": "USD",
              "price": 155.00,
              "updated_at": 1765635970,
              "change_24h_pct": -0.9,
              "periods": {
                "7d": { "change_pct": -2.4, "avg": 158.0, "min": 151.0, "max": 162.0 }
              },
              "price_history": [
                { "t": 1765550000, "p": 160.0 },
                { "t": 1765636400, "p": 155.0 }
              ]
            }
          ]
        },
        {
          "id": "d41f-psa10-uuid",
          "slug": "pokemon-base-set-charizard-4-psa-10",
          "type": "graded",
          "condition": null,
          "printing": "Holofoil",
          "language": null,
          "grading": {
            "company": "PSA", "grade": 10, "grade_label": null,
            "qualifier": null, "canonical": "PSA 10"
          },
          "markets": [
            { "region": "EU", "currency": "EUR", "price": null,    "updated_at": 1765630000, "change_24h_pct": null, "periods": {}, "price_history": [] },
            { "region": "NA", "currency": "USD", "price": 4570.00, "updated_at": 1765630000, "change_24h_pct": 0.4,  "periods": { "7d": { "change_pct": 1.2, "avg": 4480.0 } }, "price_history": [] }
          ]
        }
      ]
    }
  ]
}

Two time signalsBeta

  • price_history is the { t, p } series of observed market prices over time. It is exactly what v1 exposed, so your existing charts keep working, and it is now scoped to each market entry.
  • periodsholds aggregate statistics (average, min and max, standard deviation, trend, and more), now grouped by time window. The fields line up one-to-one with v1's flat stats and carry the same values, so anything you computed in v1 continues to match.

Request costBeta

Most requests cost the same as v1. Two optional features add to that cost, and they are easy to spot below. If you use neither, you pay the base rate.

Base rate

One region, raw OR graded variants only

The same cost as the equivalent v1 call. This is what you pay by default.

Two features add a surcharge

Both raw & graded+1 Surcharge
graded=include

Returning raw and graded variants together adds a surcharge. Asking for just one kind (graded=exclude or graded=only) stays at normal cost.

Extra regions+1 Surcharge
regions=na,eu,…

Each region beyond the first is a separate price lookup, so it adds cost. This applies as more regions come online.

Surcharges stack: use both features and both apply.

Migrating from v1Beta

v1 does not change. v2 is a new, additional path you can opt into. The defaults already reproduce v1 pricing:regions falls back to NA and graded defaults to exclude, so a plain request returns the same raw NA pricing as v1. The identifier rename is covered in full on the Identifiers page.

What changes for an existing integrationThe call-outs that matter when you adopt /v2/cards
  • id is now the UUID. The old slug moves to a field called slug. This is the single biggest rename.
  • regions defaults to NA. That matches v1's US pricing, and NA is the only region live today.
  • price & price_history now live inside markets[]. With regions=NA, markets[0] is the drop-in replacement.
  • There is no more offset pagination. Use the cursor from the Link header instead.
  • There is no standalone us_price field. Request NA and read that market entry.
  • The flat stat fields move into periods. They are regrouped by time window under markets[].periods, with the same values as v1.
  • printing now holds the print type only. The " - <Language>" suffix has been removed, so read language separately.
  • Absent is not the same as null. v2 leaves out fields you did not request instead of sending them as null. The one exception is a market's price.
  • Errors now use application/problem+json. Update any parser that keys on { error, code }.