TCGPlayer API Documentation
Complete REST access to TCGPlayer's catalog and marketplace data — 9 endpoints covering games, expansions, cards, prices, SKU pricing, sales history, historic prices, and live listings.
How the TCGPlayer API Works
categoryId → groupId → productId → skuId. Each call returns the IDs you need for the next.
List Games
/api/v2/gamesReturns categoryId for each supported game.
Get Expansions
/api/v2/expansions/:categoryIdUse categoryId to fetch every expansion. Each row carries groupId.
Get Cards
/api/v2/cards/:groupIdUse groupId to fetch every card in the set. Each row carries productId.
Get Prices / SKUs / Listings
/api/v2/prices/:productIdUse productId to fetch prices, SKU prices, sales history, historic prices, or live listings.
TCGPlayer API Endpoints
Authenticated via x-api-key.
/api/v2/gamesList all supported games. Each row carries categoryId for the next step.
/api/v2/expansions/:categoryIdPaginated expansions for a game. Each row carries groupId.
/api/v2/cards/:groupIdPaginated cards in an expansion with images, names, numbers, rarities. Each row carries productId.
/api/v2/prices/:productIdLatest TCGPlayer prices for a card across all printings (Normal / Foil / 1st Edition / etc).
/api/v1/skuprices/:skuIdPer-SKU price for one specific condition + printing + language combination.
/api/v1/skuprices/product/:productIdEvery SKU price for a card in one call — typically 50-150 SKUs covering all conditions, printings, languages.
/api/v2/sales-history/:productIdLive recent-transactions feed from TCGPlayer marketplace (~100 most recent sales). Includes statistics block.
/api/v2/sales-history/:productId/fullFull historic sales archive — 90+ days of bucketed data. Server-side filters by condition, variant, language, date range. Best for trend charts and per-condition pricing.
/api/v2/historic-prices/:productIdDaily price snapshots over time, broken out per variant (Normal/Foil). Ideal for trend charts.
/api/v2/livelistings/:productIdReal-time marketplace listings — every active seller with condition, printing, language, quantity, price, shipping.
Every Field We Expose
Complete field-by-field reference for every TCGPlayer-source endpoint, so you know exactly what you can build with.
Games
GET /api/v2/gamesTop of the catalog tree. One row per supported trading card game.
| Field | Type | Description |
|---|---|---|
| categoryId | integer | TCGPlayer category ID — use this to fetch expansions. |
| gameName | string | Human-readable name (e.g. "Magic: The Gathering"). |
| gameAbbreviation | string | Short code (e.g. "MTG", "POK", "YGO"). |
| gameSeoName | string | URL-safe slug used by TCGPlayer. |
Expansions
GET /api/v2/expansions/:categoryIdAll expansions (sets) for a game. Use the groupId to drill into cards.
| Field | Type | Description |
|---|---|---|
| groupId | integer | TCGPlayer group ID — use this to fetch cards in this set. |
| groupName | string | Internal group name from TCGPlayer. |
| expansionName | string | Full set name (e.g. "Crown Zenith"). |
| expansionAbbreviation | string | Short set code (e.g. "CRZ"). |
| releasedOn | ISO date | Release date of the set. |
| gameName | string | Parent game. |
| categoryId | integer | Parent category ID. |
Cards
GET /api/v2/cards/:groupIdEvery card (single) in an expansion with metadata and image.
| Field | Type | Description |
|---|---|---|
| productId | integer | TCGPlayer product ID — primary key for prices, listings, sales, SKUs. |
| name | string | Display name (may include variant suffixes). |
| cleanName | string | Stripped name for matching/joining. |
| number | string | Collector / set number (e.g. "025/200"). |
| rarity | string | Rarity tier (Common, Rare, Holo Rare, Mythic, Secret, etc.). |
| imageUrl | string | Hosted card image URL. |
| expansionName | string | Parent expansion. |
| gameName | string | Parent game. |
Prices (per product)
GET /api/v2/prices/:productIdLatest aggregate prices for a card. Returns one row per printing (subType): Normal, Foil, 1st Edition, etc.
| Field | Type | Description |
|---|---|---|
| productId | integer | TCGPlayer product ID. |
| subType | string | Printing variant — "Normal", "Foil", "1st Edition", "Holofoil", etc. |
| marketPrice | decimal | TCGPlayer's computed market price (recent sales + active listings). |
| lowPrice | decimal | Lowest currently listed price. |
| midPrice | decimal | Median listing price. |
| highPrice | decimal | Highest listed price. |
| directLowPrice | decimal | Lowest TCGPlayer Direct (verified) price — null if none available. |
| lastUpdated | ISO timestamp | When TCGPlayer last refreshed this row. |
SKU Prices (per SKU or per product)
GET /api/v1/skuprices/:skuId · GET /api/v1/skuprices/product/:productIdThe most granular pricing tier — one entry per (productId, condition, printing, language) combination. A typical card has 50-150 SKUs.
| Field | Type | Description |
|---|---|---|
| skuId | integer | TCGPlayer SKU ID. |
| productId | integer | Parent product ID. |
| lowPrice | decimal | Lowest current listing for this exact SKU. |
| lowestShipping | decimal | Cheapest shipping cost on the lowest listing. |
| lowestListingPrice | decimal | lowPrice + lowestShipping — landed cost from the cheapest seller. |
| marketPrice | decimal | TCGPlayer market price for this exact SKU. |
| directLowPrice | decimal | Lowest TCGPlayer Direct price for this SKU. |
| last_updated | ISO timestamp | Last refresh of the SKU price row. |
Sales History (Live)
GET /api/v2/sales-history/:productIdRecent completed sales pulled live from TCGPlayer marketplace transactions (~100 most recent).
| Field | Type | Description |
|---|---|---|
| date | ISO timestamp | When the sale closed. |
| marketplace | string | Always "TCGPlayer". |
| condition | string | Card condition at time of sale (Near Mint, Lightly Played, etc.). |
| variant | string | Printing variant ("Normal", "Foil", "1st Edition", etc.). |
| price | decimal | Final price paid (purchase price + shipping). |
| statistics | object | Summary block: avg / median / min / max prices, total sales count, date range. |
Sales History (Full Archive — Filterable)
GET /api/v2/sales-history/:productId/full90+ days of bucketed sales archive per (condition + variant + language) SKU. Server-side filterable by condition, variant, language, date range. Distinct from the live recent-sales feed above.
| Field | Type | Description |
|---|---|---|
| data.summary | object | Aggregate stats: avgMarketPrice, minMarketPrice, maxMarketPrice, totalSalesAllBuckets, totalSalesLastBucket, lastBucketDate, lastUpdated. |
| data.available.skus | array | Every (skuId, condition, variant, language) tuple discovered for this product — populate filter dropdowns from one call. |
| data.available.conditions / variants / languages | string[] | Distinct sorted lists of values present for this product. |
| data.rows[].skuId | string | TCGPlayer SKU ID this bucket belongs to. |
| data.rows[].condition | string | NM / LP / MP / HP / Damaged. |
| data.rows[].variant | string | Normal / Foil / 1st Edition / etc. |
| data.rows[].language | string | English / Japanese / etc. |
| data.rows[].bucketStartDate | date string | Start of the 3-day bucket (YYYY-MM-DD). |
| data.rows[].marketPrice | decimal | TCGPlayer market price snapshot for the bucket. |
| data.rows[].quantitySold | integer | Number of units sold in the bucket (0 if no sales). |
| data.rows[].transactionCount | integer | Distinct sale transactions in the bucket. |
| data.rows[].lowSalePrice / highSalePrice | decimal | Lowest / highest single sale price in the bucket. |
| data.rows[].lowSalePriceWithShipping / highSalePriceWithShipping | decimal | Same low/high but including shipping cost. |
Historic Prices
GET /api/v2/historic-prices/:productIdDaily price snapshots back through the product's tracked history. Top-level prices map is keyed by date (YYYY-MM-DD), then by variant (Normal/Foil).
| Field | Type | Description |
|---|---|---|
| productId | integer | TCGPlayer product ID. |
| createdAt | ISO timestamp | When tracking began for this product. |
| prices.<date>.<variant>.lowPrice | decimal | Lowest sold price on that day for that variant. |
| prices.<date>.<variant>.midPrice | decimal | Median sold price on that day for that variant. |
| prices.<date>.<variant>.highPrice | decimal | Highest sold price on that day for that variant. |
| prices.<date>.<variant>.marketPrice | decimal | TCGPlayer market price snapshot for that day. |
| prices.<date>.<variant>.directLowPrice | decimal | Lowest TCGPlayer Direct price for the day (may be null). |
Live Listings
GET /api/v2/livelistings/:productIdEvery active TCGPlayer seller listing for a product, refreshed in real time.
| Field | Type | Description |
|---|---|---|
| listingId | string | Unique TCGPlayer listing ID. |
| sellerName | string | Seller display name. |
| sellerId | string | Seller account ID. |
| sellerRating | decimal | Seller star rating. |
| condition | string | Condition of the listed card. |
| printing | string | Printing variant of the listed card. |
| language | string | Listing language (English, Japanese, etc.). |
| listingType | string | Standard, Direct, or other TCGPlayer listing class. |
| quantity | integer | Quantity available from this seller. |
| price | decimal | Per-unit price from this seller. |
| shippingPrice | decimal | Shipping cost from this seller. |
| currency | string | Always "USD". |
Example: Per-Product Prices
One row per printing variant, with all five price points and the freshness timestamp.
{
"success": true,
"data": {
"productId": 130289,
"name": "Forest",
"expansionName": "Magic 2014 (M14)",
"gameName": "Magic: The Gathering",
"prices": [
{
"subType": "Normal",
"marketPrice": 0.21,
"lowPrice": 0.01,
"midPrice": 0.15,
"highPrice": 8.00,
"directLowPrice": 0.10,
"lastUpdated": "2026-05-06T07:32:29.881Z"
},
{
"subType": "Foil",
"marketPrice": 0.85,
"lowPrice": 0.04,
"midPrice": 0.28,
"highPrice": 5.99,
"directLowPrice": null,
"lastUpdated": "2026-05-06T07:32:29.881Z"
}
]
}
}Frequently Asked Questions
What does the TCGPlayer API give me access to?
Everything TCGPlayer surfaces about a product: the catalog tree (categoryId -> groupId -> productId -> skuId), prices at three granularities (per-product, per-SKU, daily historic), real recent sales, and the live seller listings feed. You can build a price tracker, an inventory pricer, an arbitrage scanner, or a market-trend dashboard against the same set of endpoints.
How is per-product pricing different from per-SKU pricing?
Per-product (/prices/:productId) gives one row per printing variant (Normal / Foil / 1st Edition / Holofoil) — this is the headline price you usually see on TCGPlayer. Per-SKU (/skuprices/...) breaks every printing further down by condition (NM / LP / MP / HP / DMG) and language, so a typical card has 50-150 SKU rows. Use per-product for general dashboards, per-SKU when you need to price actual graded inventory.
When should I use sales-history vs sales-history/full vs historic-prices?
Three related but distinct surfaces. /sales-history/:productId is the live recent-transactions feed pulled from TCGPlayer marketplace each call (~100 most recent sales) — best for "what just sold" tickers. /sales-history/:productId/full is the stored archive (90+ days of 3-day buckets per condition+variant+language SKU) with server-side filters — best for trend charts, per-condition pricing, and CSV exports. /historic-prices/:productId is the per-day market-price snapshot collapsed to Foil/Normal — best for clean long-term price trend lines without the per-condition fan-out.
How fresh is the data?
Live listings hit TCGPlayer's marketplace API in real time (seconds-old). Per-product and per-SKU prices refresh on a continuous loop and carry a lastUpdated / last_updated field. Historic prices add a new daily bucket once per day. Sales history pulls the most recent N transactions live on each request.
What plan tier do I need?
/games is public, /expansions and /cards are Hobby+, /prices, /sales-history, and /historic-prices are Business+, /skuprices and /livelistings are Unlimited.