Skip to content
· 8 min read

Migrating Off the TCGPlayer API: A Working Code Walkthrough

Port your TCGPlayer API integration to TCG API endpoint by endpoint — request mapping, response shape changes, and the four errors that bite most people during the switch.

apitcgplayerpricing datadeveloper tools

If you’ve tried to get access to the TCGPlayer API recently, you already know the problem: TCGPlayer closed API access to new developers. No application form, no waitlist — just a dead end.

This post is the hands-on half of that story: how to actually port working code off the TCGPlayer API. If you are still deciding whether to switch, read TCG API vs TCGPlayer API first — it covers coverage, freshness, and cost side by side. Come back here when you want the diff.

Everything below is a real request mapping, not a summary. Skip to Common errors when migrating if something already broke.

What you’re migrating to

TCG API was built specifically because TCGPlayer closed their doors. Here’s what we offer:

Game coverage

While most alternatives focus on 1-3 games, TCG API covers every game on TCGPlayer — all 54 of them. That includes:

  • Pokemon — 200+ sets, 30,000+ cards
  • Magic: The Gathering — 430+ sets, 110,000+ cards
  • Yu-Gi-Oh! — 600+ sets, 45,000+ cards
  • Disney Lorcana — All sets, updated daily
  • One Piece Card Game — All sets, updated daily
  • Flesh and Blood — All sets, updated daily
  • Star Wars: Unlimited, Digimon, Dragon Ball Super, Weiss Schwarz, and 58 more

Browse all supported games at tcgapi.dev/games.

Daily Pricing with Per-Printing Data

Every card has separate pricing for each printing type:

{
"name": "Charizard ex",
"set_name": "Obsidian Flames",
"prices": [
{
"printing": "Normal",
"market_price": 12.45,
"low_price": 10.99,
"median_price": 12.50,
"price_change_24h": 2.89,
"price_change_7d": -6.04,
"price_change_30d": 20.87
},
{
"printing": "Holofoil",
"market_price": 45.99,
"low_price": 42.00,
"median_price": 46.50,
"price_change_24h": 2.68
}
]
}

prices is an array with one entry per printing. The price_change_* fields are percentages, tracked across 24-hour, 7-day, and 30-day windows — no need to store historical data yourself (though we offer that on Pro plans too).

The shape of a request

No OAuth, no API application process, no approval wait. Sign up, get a key, start making requests:

Terminal window
# Search for any card across all games
curl "https://api.tcgapi.dev/v1/search?q=charizard"
# Get all Pokemon sets
curl "https://api.tcgapi.dev/v1/games/pokemon/sets"
# Get prices for a specific card
curl "https://api.tcgapi.dev/v1/cards/12345" \
-H "X-API-Key: YOUR_API_KEY"

JavaScript:

const response = await fetch(
'https://api.tcgapi.dev/v1/search?q=charizard&game=pokemon',
{ headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const data = await response.json();
console.log(data.data[0].market_price); // search rows are flat: printing + market_price

Python:

import requests
response = requests.get(
'https://api.tcgapi.dev/v1/search',
params={'q': 'charizard', 'game': 'pokemon'},
headers={'X-API-Key': 'YOUR_API_KEY'}
)
cards = response.json()['data']
print(cards[0]['market_price']) # search rows are flat: printing + market_price

Before you start

Two things worth knowing up front, because they cause most of the confusion:

  • Auth is a static header, not OAuth. No token refresh, no client-credentials dance.
  • Prices are per printing. A card is not one price; Normal and Foil are separate rows with separate markets.

Feature-by-feature coverage, rate limits and plan costs are on the comparison page and pricing page — this post assumes you have already decided to move.

Migration Guide: TCGPlayer API → TCG API

If you have existing code that used the TCGPlayer API, here’s how the endpoints map:

Listing Games/Categories

Terminal window
# TCGPlayer (old)
GET /catalog/categories
# TCG API
GET /v1/games

Searching Cards

Terminal window
# TCGPlayer (old)
GET /catalog/products?categoryId=1&productName=charizard
# TCG API
GET /v1/search?q=charizard&game=pokemon

Getting Prices

Terminal window
# TCGPlayer (old)
GET /pricing/product/12345
# TCG API
GET /v1/cards/12345
# (prices included in card response)

The response formats are similar but simplified. Check our Quick Start guide for a complete walkthrough.

What Developers Are Building

Since launching, developers have used TCG API to build:

  • Price tracking bots for Discord and Telegram
  • Collection managers that track portfolio value across games
  • Store pricing tools that auto-update inventory prices
  • Arbitrage finders that compare prices across platforms
  • Deck builders with up-to-date price estimates
  • Investment trackers for sealed product prices

Get Started in 2 Minutes

  1. Sign up at tcgapi.dev/signup (no credit card required)
  2. Get your API key from the dashboard
  3. Make your first request — try searching for your favorite card
  4. Read the docs at tcgapi.dev/introduction

The free tier gives you 100 requests per day — enough to build and test your entire integration before committing to a paid plan.

Common errors when migrating

These are the three gotchas that catch almost every team moving off the TCGPlayer API:

1. 401 Unauthorized after copy-pasting the Bearer example

TCGPlayer used OAuth 2.0 with Authorization: Bearer <access_token> where the access token was refreshed from a client-credentials flow. TCG API uses a static X-API-Key header — the word “Bearer” is nowhere in the mix.

headers = {"Authorization": "Bearer eyJhbGciOi..."}
headers = {"X-API-Key": "tcg_live_xxxxxxxxxxxxx"}

If you hit 401 with a fresh key, this is 90% of the time the reason.

2. productId became id (and tcgplayer_id is separate)

The old TCGPlayer API used productId as the identifier. TCG API has its own internal id and tracks the original TCGPlayer product ID as a separate tcgplayer_id field. If you are migrating a catalog that stored TCGPlayer product IDs, use the lookup-by-TCGPlayer-ID endpoint to resolve them cleanly:

Terminal window
# Old: look up product by TCGPlayer productId
GET /catalog/products/12345
# New: look up by TCGPlayer ID directly (returns TCG API card data)
GET /v1/cards/tcgplayer/12345

3. Sealed products appeared as Normal printing (fixed in March 2026)

Until March 28 2026, sealed products (booster boxes, ETBs) were returning printing: "Normal" instead of printing: "Sealed". If your integration filtered by printing, you may have accidentally excluded sealed inventory. This is fixed on the live API — just make sure your client isn’t caching the old response shape.

4. Rate-limit semantics are daily, not per-second

TCGPlayer’s rate limit was requests-per-second with bursts. TCG API’s rate limit is requests-per-day that reset at UTC midnight. You do not need exponential-backoff logic on every request — you need a daily-budget monitor. A simple X-RateLimit-Remaining header check at the start of a long-running job is enough to plan your batch size.

Webhooks and event-driven integrations

TCG API does not yet offer webhooks, which is the one area where the old TCGPlayer API had a clear edge. The current workaround: hit /v1/prices/top-movers once per hour to see which cards moved significantly since the last refresh. For store inventory tooling where you mostly care about your existing stock, a batch GET /v1/bulk/prices?ids=… on a cron schedule is more efficient than a webhook firehose anyway.

Webhook support is on the roadmap; subscribe to the changelog to hear when it ships.


Have questions? Join our Discord community or email us at [email protected].

Ready to get started?

Free tier includes 100 requests per day. No credit card required.