/v2/cards
BetaPreview of the next cards API: graded cards and multi-region localized pricing.
card_idvariant_idtcgplayer_idtcgplayer_skuPrices are quoted per region instead of converted between currencies — see Localized pricing for how the markets array works.
regionsNANAEUUKJPOCELATAMOTHER…ISO country codesGraded 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
// 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);// GET /v2/cards?game=pokemon®ions=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_historyis 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.
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
graded=includeReturning raw and graded variants together adds a surcharge. Asking for just one kind (graded=exclude or graded=only) stays at normal cost.
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
idis now the UUID. The old slug moves to a field calledslug. This is the single biggest rename.regionsdefaults toNA. That matches v1's US pricing, andNAis the only region live today.price&price_historynow live insidemarkets[]. Withregions=NA,markets[0]is the drop-in replacement.- There is no more
offsetpagination. Use thecursorfrom theLinkheader instead. - There is no standalone
us_pricefield. RequestNAand read that market entry. - The flat stat fields move into
periods. They are regrouped by time window undermarkets[].periods, with the same values as v1. printingnow holds the print type only. The" - <Language>"suffix has been removed, so readlanguageseparately.- 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'sprice. - Errors now use
application/problem+json. Update any parser that keys on{ error, code }.