PokéWallet API
Documentation
Complete REST reference for the most comprehensive Pokémon TCG platform. Real-time pricing, 50,000+ cards database, and generous rate limits.
PokéWallet is a REST API for Pokémon TCG card prices and data: 50,000+ cards with TCGPlayer (USD) and CardMarket (EUR) prices, refreshed daily, plus sets, search and card images. The free tier (100 requests/hour) only needs an API key; price history and set analytics need the Pro plan (€20/month) or its 7-day trial.
| Base URL | https://api.pokewallet.io |
|---|---|
| Cards | 50,000+ Pokémon TCG cards, plus sealed products priced on TCGPlayer |
| Card IDs | pk_ + hex for cards on TCGPlayer; hex without prefix for CardMarket-only cards |
| Prices | TCGPlayer (USD) for every variant and CardMarket (EUR) for normal and holo, refreshed daily |
| Free on every plan | Sets, set cards, card details, search and images |
| Pro plan or 7-day trial | Price history, prices by set, set statistics, completion value, trending sets and top cards |
| API key | One key for all 12 games, with shared rate limits |
Quick Start
Get started with PokéWallet API in 4 simple steps:
Create an Account
Sign up for free to start using the API. Upgrade anytime from your dashboard.
Sign Up NowGenerate an API Key
Create your first API key from the dashboard.
Make Your First Request
Start querying the API with your key.
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/search?q=charizard"Join the Discord Community
Stay up to date with new features, ask for help, and connect with other developers.
Join DiscordAuthentication
All API requests (except /health) require authentication using an API key.
API Key Format
API keys follow this format:
- Production keys:
pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - Development keys:
pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Authentication Methods
You can authenticate using either the X-API-Key header or Authorization header:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/search?q=pikachu"curl -H "Authorization: Bearer pk_live_your_key_here" \
"https://api.pokewallet.io/search?q=pikachu"Rate Limits
Rate limits vary depending on your subscription plan:
| Plan | Per hour | Per day | Paid endpoints | Price |
|---|---|---|---|---|
| Free | 100/hour | 1,000/day | — | €0 |
| Coffee | 1,000+/hour | 10,000+/day | — | Buy a coffee on Ko-fi |
| Pro | 5,000/hour | 50,000/day | Pokémon + One Piece | €20/month |
| Ultra All 12 | 7,000/hour | 70,000/day | All 12 games | €29/month |
| Business | Custom | Custom | All 12 games | Contact us |
| Early Access | 1,000/hour | 10,000/day | — | No longer available |
Early Access was our initial launch tier and is no longer available for new users.
Rate Limit Headers
Every API response includes rate limit information:
X-RateLimit-Limit-Hour: 100
X-RateLimit-Remaining-Hour: 95
X-RateLimit-Limit-Day: 1000
X-RateLimit-Remaining-Day: 823Rate Limit Exceeded (429)
When you exceed your rate limit, you'll receive a 429 Too Many Requests response:
{
"error": "Rate limit exceeded",
"message": "Hourly limit exceeded",
"limits": {
"hourly": {
"limit": 100,
"used": 100,
"remaining": 0
},
"daily": {
"limit": 1000,
"used": 523,
"remaining": 477
}
}
}Public Endpoints
/healthNo Auth RequiredCheck API status, database, cache, and storage health with response times.
Example Request:
curl "https://api.pokewallet.io/health"Response Example (Healthy):
{
"status": "healthy",
"timestamp": "2025-12-16T10:30:00.000Z",
"version": "1.1.0",
"checks": {
"database": {
"status": "healthy",
"responseTime": 45
},
"cache": {
"status": "healthy",
"responseTime": 3
},
"storage": {
"status": "healthy",
"responseTime": 12
}
},
"responseTime": 60,
"region": "FRA"
}Response Example (Unhealthy):
{
"status": "unhealthy",
"timestamp": "2025-12-16T10:30:00.000Z",
"version": "1.1.0",
"message": "Critical services unavailable - API may not function correctly",
"checks": {
"database": {
"status": "unhealthy",
"responseTime": null,
"message": "Connection failed"
},
"cache": {
"status": "healthy",
"responseTime": 3
},
"storage": {
"status": "healthy",
"responseTime": 12
}
},
"responseTime": 1050,
"region": "FRA"
}/No Auth RequiredGet API information, version, and available endpoints.
Example Request:
curl "https://api.pokewallet.io/"Response Example:
{
"name": "PokeWallet API",
"version": "1.1.0",
"status": "production",
"authentication": {
"required": true,
"method": "API Key",
"header": "X-API-Key",
"format": "pk_live_xxxxxxxxxxxxx"
},
"endpoints": {
"health": { "path": "/health", "auth_required": false },
"search": { "path": "/search?q=charizard&limit=20", "auth_required": true },
"cardDetail": { "path": "/cards/:id", "auth_required": true },
"sets": { "path": "/sets", "auth_required": true },
"setDetails": { "path": "/sets/:setCode?page=1&limit=50", "auth_required": true },
"images": { "path": "/images/:id?size=high", "auth_required": true }
},
"rate_limits": {
"per_hour": 100,
"per_day": 1000,
"plan": "free"
}
}/gamesNo Auth RequiredLists the games available under their own prefix (/mtg, /ygo, …) with their routes. Pokémon and One Piece are not in this list: they use /cards, /sets… and /op/….
Example Request:
curl "https://api.pokewallet.io/games"Response Example (first of ten games):
{
"success": true,
"data": [
{
"code": "mtg",
"name": "Magic: the Gathering",
"endpoints": {
"sets": "/mtg/sets",
"set": "/mtg/sets/:set",
"card": "/mtg/cards/:id",
"search": "/mtg/search?q=",
"image": "/mtg/images/:id"
}
}
]
}Pro (€20/month) covers Pokémon and One Piece only. Ultra (€29/month) includes everything in Pro plus the paid endpoints of the other 10 games: Magic, Yu-Gi-Oh!, Lorcana and more.
Compare plans →Card ID Formats
The API uses two different ID formats depending on the card's data source:
TCG Cards (TCGPlayer)
Format: pk_ + hexadecimal hash
Example:
pk_72046138a4c1908a9f27c93fdd8189ba...Usage: All cards with TCGPlayer data (even if they also have CardMarket data)
CardMarket-Only Cards
Format: Direct hexadecimal hash (no pk_ prefix)
Example:
2208e8a2750c07d89e54870ffcef80d1...Usage: Only cards exclusively from CardMarket (e.g., Japanese sets, European promos)
card_number but different variants (V1, V2, etc.) have unique IDs. Price Variants
Prices come from two different sources, each with its own way of classifying card variants. Understanding this distinction is important when reading the prices array in any response.
TCGPlayer
🇺🇸 USAUses a sub_type_name field to distinguish versions:
Normal | Common / non-holo cards |
Holofoil | Holo cards |
Reverse Holofoil | Most Vintage Sets (Base through Neo) |
1st Edition | Base Set 1st Ed and similar |
Unlimited | Standard version of sets that have 1st editions |
Shadowless | Specific Base Set variants |
CardMarket
🇪🇺 EuropeUses a simpler variant_type field:
normal | Standard non-holo version |
holo | Holo version |
Product Types
TCGPlayer also lists sealed products — booster boxes, elite trainer boxes, blisters, tins, displays, theme decks — alongside singles. The API surfaces both, labeled by a product_type field.
Cards
Singles — the default. Have a rarity, appear in price statistics, completion value and top-cards rankings.
Sealed Products
Booster boxes, ETBs, blisters, tins, displays, theme decks. Priced only via TCGPlayer — cardmarket is always null, since CardMarket sealed data isn't imported yet.
product_type appears: inside card_info on /search, /sets/:setCode and /cards/:id; at the row level (alongside id, card_number, name) on /prices/:setCode. /analytics/top-cards, /sets/:setCode/statistics and /sets/:setCode/completion-value — a booster box's price would otherwise dominate rankings and completion-cost estimates meant for singles. They still appear in /sets (counted separately via sealed_count) and /sets/:setCode (listed alongside the cards). Search Endpoints
/searchAdvanced card search with unified pricing from TCGPlayer and CardMarket.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | Required | Search query. Supports multiple formats:
|
page | number | Optional | Page number (default: 1) |
limit | number | Optional | Results per page (default: 20, max: 100) |
Example Requests:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/search?q=charizard+ex"curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/search?q=24541%20148"Response Example (TCG Card):
{
"query": "pikachu",
"results": [
{
"id": "pk_72046138a4c1908a9f27c93fdd8189ba4ac8e683efaed6b9161efcef129302394a9ec1d20d",
"card_info": {
"name": "Pikachu ex (Pikachu 60)",
"clean_name": "Pikachu ex Pikachu 60",
"set_name": "Battle Academy 2024",
"set_code": "BA2024",
"set_id": "23520",
"card_number": "106",
"rarity": "Holo Rare",
"card_type": "Lightning",
"hp": "200.0",
"stage": "Basic",
"card_text": null,
"attacks": ["[LLC] Thunderbolt (120)"],
"weakness": "Fx2",
"resistance": null,
"retreat_cost": "1.0",
"product_type": "card"
},
"images": {
"languages": ["en", "it", "de"]
},
"tcgplayer": {
"prices": [{
"sub_type_name": "Normal",
"low_price": 7,
"mid_price": 9.37,
"high_price": 18,
"market_price": 8.01,
"direct_low_price": null,
"updated_at": "2025-12-27T05:14:43.451818"
}],
"url": "https://www.tcgplayer.com/product/556443"
},
"cardmarket": null
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 56,
"total_pages": 3
},
"metadata": {
"total_count": 56,
"tcg": 18,
"cardmarket": 38,
"tcg_only": 18,
"cardmarket_only": 38,
"both_sources": 0
}
}Response Example (CardMarket-Only Card):
{
"query": "cubone cbb3c",
"results": [
{
"id": "8eb728bd59d4e1a0d94c354e4cc65a7465b55cfa4261bfa93301faa5ec921f97",
"card_info": {
"name": "Cubone (CBB3C 04)",
"set_code": "CBB3C",
"set_id": "-15",
"card_number": "4",
"product_type": "card"
},
"images": {
"languages": ["en"]
},
"tcgplayer": null,
"cardmarket": {
"product_name": "Cubone (CBB3C 04)",
"prices": [
{
"avg": null,
"low": 0.02,
"avg1": null,
"avg7": null,
"avg30": null,
"trend": 0,
"updated_at": "2025-12-29T04:54:57.728497",
"variant_type": "normal"
},
{
"avg": 0.37,
"low": 0.02,
"avg1": 0.1,
"avg7": 0.35,
"avg30": 0.35,
"trend": 0.29,
"updated_at": "2025-12-29T04:54:57.728497",
"variant_type": "holo"
}
],
"product_url": "https://www.cardmarket.com/en/Pokemon/Products/Singles/Gem-Pack-Vol-3/Cubone-V1-CBB3C04"
}
},
{
"id": "a7ed43b641d4f24b494ad5889845085f33966d1f19cb9e0ed353979025d8da31",
"card_info": {
"name": "Cubone (CBB3C 04)",
"set_code": "CBB3C",
"set_id": "-15",
"card_number": "4",
"product_type": "card"
},
"images": {
"languages": ["en"]
},
"tcgplayer": null,
"cardmarket": {
"product_name": "Cubone (CBB3C 04)",
"prices": [
{
"avg": null,
"low": 0.02,
"trend": 0,
"variant_type": "normal"
}
],
"product_url": "https://www.cardmarket.com/en/Pokemon/Products/Singles/Gem-Pack-Vol-3/Cubone-V4-CBB3C04"
}
}
],
"pagination": {
"page": 1,
"limit": 2,
"total": 7,
"total_pages": 4
},
"metadata": {
"total_count": 7,
"tcg": 0,
"cardmarket": 7,
"tcg_only": 0,
"cardmarket_only": 7,
"both_sources": 0
}
}card_number: "4" and set_code: "CBB3C", but each has a unique ID. This ensures each variant can be uniquely identified and its correct image can be retrieved. Set Identifiers: Use
set_id to match cards to their set: it is the same value returned by the /sets endpoint. card_info.set_code may contain the numeric set id instead of the short code for some cards. Image Languages: The
images.languages array lists the languages the card's image is available in. "en" is always present and refers to the card's default artwork (English for international sets, Japanese for Japanese sets); additional codes (it, fr, de, es, pt) mean a localized European variant can be requested via /images/:id?lang=xx. See the Images Endpoint. Sealed Products: Results can include sealed products (booster boxes, ETBs, displays, etc.) as well as cards — check
card_info.product_type. CardMarket-only results are always "card", since CardMarket sealed data isn't imported yet. See Product Types. /search/by-price-rangeComing SoonSearch cards by price range with optional filters for rarity and set.
⏳ This endpoint is currently in development and will be available soon after thorough testing.
/search/by-typeComing SoonSearch cards by card type (Pokemon, Trainer, Energy) and optional subtype filters.
⏳ This endpoint is currently in development and will be available soon after thorough testing.
Cards Endpoints
X-API-Key header. /cards/:idGet complete card details with unified pricing from TCGPlayer and CardMarket.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Required | Card ID - Two formats supported:
|
set_code | string | Optional | Set code for disambiguation (e.g., "SWSH3", "SV1", "CBB3C"). Supports both alphanumeric codes and numeric group IDs. |
Example Request:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/cards/pk_xxx"Response Example:
{
"id": "pk_xxx",
"card_info": {
"name": "Charizard VMAX",
"clean_name": "Charizard VMAX",
"set_name": "Darkness Ablaze",
"set_code": "SWSH3",
"set_id": "22789",
"card_number": "20/189",
"rarity": "Secret Rare",
"card_type": "Pokemon",
"hp": "330",
"stage": null,
"card_text": "VMAX rule: When your VMAX Pokemon is Knocked Out...",
"attacks": ["Fire Spin - 320 damage"],
"weakness": "Water",
"resistance": null,
"retreat_cost": "3",
"product_type": "card"
},
"images": {
"languages": ["en", "it", "fr", "de", "es"]
},
"tcgplayer": {
"url": "https://tcgplayer.com/product/123456",
"prices": [
{
"sub_type_name": "Normal",
"low_price": 245.99,
"mid_price": 299.99,
"high_price": 450.00,
"market_price": 285.00,
"direct_low_price": 250.00,
"updated_at": "2025-12-16T04:00:00Z"
}
]
},
"cardmarket": {
"product_name": "Charizard VMAX (Secret)",
"product_url": "https://cardmarket.com/product/789012",
"prices": [{
"variant_type": "normal",
"avg": 260.50,
"low": 240.00,
"trend": 270.00,
"avg1": 258.30,
"avg7": 255.80,
"avg30": 280.50,
"updated_at": "2025-12-16T04:00:00Z"
}]
}
}/cards/:id/price-historyProGet historical price snapshots from both TCGPlayer and CardMarket, with percentage changes over 7, 14, 30, 60 and 120 days.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Required | Card ID (pk_xxx for TCG+CM cards, encrypted_id for CM-only cards) |
Example Request:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/cards/pk_xxx/price-history"Response Example:
{
"id": "pk_abc123",
"card_name": "Charizard (Base Set)",
"tcgplayer": {
"variants": {
"Normal": {
"current": { "market": 12.50, "low": 10.00, "mid": 11.50, "high": 15.00, "direct_low": 11.00 },
"price_7d": 11.80,
"price_14d": 11.20,
"price_30d": null,
"price_60d": null,
"price_120d": null,
"change_7d": "+5.9%",
"change_14d": "+11.6%",
"change_30d": null,
"change_60d": null,
"change_120d": null,
"last_updated": "2026-04-26T06:00:00Z"
}
}
},
"cardmarket": {
"variants": {
"normal": {
"current": { "avg": 9.50, "low": 8.00, "trend": 9.20 },
"avg_1d": 9.40,
"avg_7d": 8.90,
"avg_30d": 8.50,
"price_7d": 8.90,
"price_14d": 8.60,
"price_30d": null,
"price_60d": null,
"price_120d": null,
"change_7d": "+6.7%",
"change_14d": "+10.5%",
"change_30d": null,
"change_60d": null,
"change_120d": null,
"last_updated": "2026-04-26T06:00:00Z"
}
}
}
}price_14d, price_30d, price_60d, price_120d return null until enough weekly snapshots have accumulated. price_7d is available from April 16, 2026.Trial Response Headers:
When accessing this endpoint during an active trial, two extra headers are included:
X-Trial-Expires-At: 2026-05-01T00:00:00.000Z
X-Trial-Days-Remaining: 7Error Responses:
| Status | Description |
|---|---|
403 — trial not activated | { "error": "Trial not activated", "redeem_url": "https://pokewallet.io/dashboard" } |
403 — trial expired | { "error": "Pro plan required", "upgrade_url": "https://pokewallet.io/pricing" } |
Sets Endpoints
/setsGet list of all Pokemon sets with card counts.
Response Fields:
| Field | Type | Description |
|---|---|---|
name | string | Set name |
set_code | string | null | Short code for the set (e.g., "SV1", "SWSH3"). May be null for some promo or special sets. |
set_id | string | Unique numeric identifier for the set (group_id) |
card_count | number | Number of card printings in the set — one per TCGPlayer product, so alternate printings of the same collector number (Master Ball Pattern, Poké Ball Pattern, …) count separately. Equals the number of card entries in /sets/:setCode. Sealed products are not included — see sealed_count. |
number_count | number | Number of distinct collector numbers in the set: 025/165 counts once however many printings it has. Omitted (not 0) when not available. |
sealed_count | number | Number of sealed products in the set. See Product Types. Omitted (not 0) when not yet available for this deployment — a missing field means "unknown", not "none". |
language | string | null | Set language code (e.g., "eng", "jap", "ger"). May be null if not specified. |
release_date | string | null | Set release date (e.g., "3rd August, 2007"). May be null if unknown. |
Example Request:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/sets"Response Example:
{
"success": true,
"data": [
{
"name": "SV09: Journey Together",
"set_code": "JTG",
"set_id": "24073",
"card_count": 190,
"number_count": 190,
"sealed_count": 27,
"language": "eng",
"release_date": "28th March, 2025"
},
{
"name": "SV2a: Pokemon Card 151",
"set_code": "SV2a",
"set_id": "23599",
"card_count": 516,
"number_count": 210,
"sealed_count": 4,
"language": "jap",
"release_date": "16th June, 2023"
},
{
"name": "Plasma Freeze",
"set_code": "PLF",
"set_id": "1382",
"card_count": 122,
"number_count": 122,
"sealed_count": 5,
"language": "eng",
"release_date": "8th May, 2013"
}
],
"total": 864
}card_count + sealed_count is the number of entries listed by /sets/:setCode (its total_cards). SV2a above has 210 collector numbers but 516 printings: most numbers exist as a base card plus Poké Ball Pattern and Master Ball Pattern versions, each with its own ID and price. /sets/:setCodeGet set details with paginated card list.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
setCode | string | Required | Set identifier - accepts either set_code (e.g., "PLF", "SV2a") or set_id (e.g., "1382"). Both values are returned by the /sets endpoint. Prefer set_id: it is always unique. |
page | number | Optional | Page number (default: 1) |
limit | number | Optional | Results per page (default: 50, max: 200) |
language | string | Optional | Filter by language when a set_code matches multiple sets (e.g., eng, jap, chn). Not needed when using a numeric set_id. |
Set Object Fields:
| Field | Type | Description |
|---|---|---|
name | string | Set name |
set_code | string | null | Short code for the set. May be null for some promo sets. |
set_id | string | Unique numeric identifier for the set (group_id) |
total_cards | number | Total number of entries in the cards list, across all pages: every card printing plus sealed products. |
language | string | null | Set language code (e.g., "eng", "jap"). May be null if not specified. |
release_date | string | null | Set release date (e.g., "3rd August, 2007"). May be null if unknown. |
cards list has one entry per printing. Alternate printings of the same collector number — Master Ball Pattern, Poké Ball Pattern, Pokémon Center exclusives, Prerelease [Staff], Cosmos Holofoil — are separate entries, each with its own id and prices. Sealed products are listed too: each entry's card_info.product_type is "card" or "sealed". See Product Types. Card Fields Specific to This Endpoint:
| Field | Type | Description |
|---|---|---|
card_info.variants | string[] | TCGPlayer finishes of this printing, e.g. ["Normal", "Reverse Holofoil"]. A reverse holo sold as the same product is a finish of the same entry, not a separate entry. Empty for CardMarket-only cards and sealed products. Only returned by /sets/:setCode. |
Example Request:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/sets/PLF"Response Example:
{
"success": true,
"set": {
"name": "Plasma Freeze",
"set_code": "PLF",
"set_id": "1382",
"total_cards": 127,
"language": "eng",
"release_date": "8th May, 2013"
},
"cards": [
{
"id": "pk_4687f4c4a0499fd6a7fa267a9bef2cb4c462f19478522c5a85eaf116ca1d1f0c8ad2ba5fc8ac3c668627bce5",
"card_info": {
"name": "Weedle",
"clean_name": "Weedle",
"set_name": "Plasma Freeze",
"set_code": "1382",
"card_number": "1/116",
"rarity": "Common",
"card_type": null,
"product_type": "card",
"variants": ["Normal", "Reverse Holofoil"],
"hp": "50.0",
"stage": "Basic",
"card_text": null,
"attacks": [
"[G] Triple Stab (10x) Flip 3 coins. This attack does 10 damage times the number of heads."
],
"weakness": "Rx2",
"resistance": null,
"retreat_cost": "1.0"
},
"images": {
"languages": ["en", "it", "fr", "de", "es", "pt"]
},
"tcgplayer": {
"prices": [],
"url": "https://www.tcgplayer.com/product/90547"
},
"cardmarket": {
"product_name": "Weedle",
"prices": [],
"product_url": "https://www.cardmarket.com/en/Pokemon/Products/Singles/Plasma-Freeze/Weedle-PLF1"
}
},
{
"id": "pk_d5e4b0f70f10d85b1439e7169de2b226b8265aa41579d52defcdbf3361dc53898e5e143670fdbcd2",
"card_info": {
"name": "Plasma Freeze Booster Box",
"clean_name": "Plasma Freeze Booster Box",
"set_name": "Plasma Freeze",
"set_code": "PLF",
"card_number": null,
"rarity": null,
"card_type": null,
"product_type": "sealed",
"variants": [],
"hp": null,
"stage": null,
"card_text": null,
"attacks": [],
"weakness": null,
"resistance": null,
"retreat_cost": null
},
"images": {
"languages": ["en"]
},
"tcgplayer": {
"prices": [],
"url": "https://www.tcgplayer.com/product/98516"
},
"cardmarket": null
}
Alternate Printings:
The same collector number can appear several times, once per printing. Real example from SV2a (IDs shortened):
[
{ "id": "pk_ca32920ee8a538e4794fa…", "card_info": { "name": "Pikachu - 025/165", "card_number": "025/165", "variants": ["Normal"] } },
{ "id": "pk_a2d13d65cfc4dfb669f2d…", "card_info": { "name": "Pikachu - 025/165 (Poke Ball Pattern)", "card_number": "025/165", "variants": ["Holofoil"] } },
{ "id": "pk_779e688ac75c524ebcdd6…", "card_info": { "name": "Pikachu - 025/165 (Master Ball Pattern)", "card_number": "025/165", "variants": ["Holofoil"] } }
]cardmarket block is attached to one of them — normally the base printing — and is null on the others. TCGPlayer prices are always the printing's own. Set Not Found:
{
"error": "Set not found: invalid set_code"
}Disambiguation Response:
Some set codes (e.g., "PR") are shared by multiple sets with different set_ids. When this happens, instead of returning a single set, the API returns a disambiguation response listing all matching sets so you can pick the right one.
{
"disambiguation": true,
"message": "Multiple sets found for set_code 'PR'. Use set_id to specify which one.",
"matches": [
{
"set_id": "1938",
"set_code": "PR",
"name": "Alternate Art Promos",
"language": "eng",
"release_date": null
},
{
"set_id": "1451",
"set_code": "PR",
"name": "XY Promos",
"language": "eng",
"release_date": null
},
{
"set_id": "1407",
"set_code": "PR",
"name": "Black and White Promos",
"language": "eng",
"release_date": null
}
],
"total": 21
}set_id of the set you need and call /sets/1938 (using the numeric set_id) to get that specific set with its cards. /sets/:setCode/imageRetrieve the logo/image for a set. Returns binary image data (PNG). Not all sets have an image available.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
setCode | string | Required | Set identifier — accepts either set_code (e.g., SWSH3) or numeric set_id (e.g., 23456). Both are returned by the /sets endpoint. |
language | string | Optional | Required only when a set_code is shared by multiple sets (e.g., eng, jap). Not needed when using a numeric set_id. |
Response Headers:
Content-Type:image/pngCache-Control:public, max-age=86400
Example Request:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/sets/SWSH3/image" \
--output swsh3.pngError Responses:
{
"error": "Image not available",
"message": "No set image is available for this set."
}{
"error": "Ambiguous set code",
"message": "Multiple sets found for set_code 'SM11'. Add ?language=eng (or jap, etc.) to disambiguate, or use a numeric set_id.",
"matches": [
{ "set_id": "2464", "language": "eng" },
{ "set_id": "23690", "language": "jap" }
]
}set_id (e.g., /sets/23456/image) to always get a unique result without disambiguation. /sets/:setCode/statisticsPROGet complete price statistics and rarity breakdown for a set. Returns average, min and max prices from both TCGPlayer (USD) and CardMarket (EUR), plus the most expensive card and a 7-day trend direction.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
setCode | string | Required | Numeric group_id (23599) or alphanumeric set code (sv2a) |
variant | string | Optional | Filter CardMarket prices by variant: normal, holo. Does not affect TCGPlayer data. |
Example Request:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/sets/23599/statistics"Response Example:
{
"set_info": {
"name": "SV2a_ Pokemon Card 151",
"set_code": "23599",
"total_cards": 524
},
"price_statistics": {
"tcgplayer": {
"avg_market_price": "7.80",
"min_price": 0.07,
"max_price": 307.56,
"most_expensive": { "name": "Charizard ex - 201/165", "price": 307.56 }
},
"cardmarket": {
"avg_price": "2.34",
"min_price": 0.37,
"max_price": 17.91,
"trend_direction": "up"
}
},
"rarity_breakdown": {
"Common": 199,
"Uncommon": 186,
"Rare": 77,
"Double Rare": 12,
"Art Rare": 18,
"Super Rare": 16,
"Special Art Rare": 8,
"Ultra Rare": 3,
"Unknown": 5
}
}price_statistics and rarity_breakdown — they don't have a rarity and would otherwise dominate the price range. See Product Types. Trial Response Headers:
When accessing this endpoint during an active trial, two extra headers are included:
X-Trial-Expires-At: 2026-05-01T00:00:00.000Z
X-Trial-Days-Remaining: 7Error Responses:
| Status | Description |
|---|---|
403 — trial not activated | { "error": "Trial not activated", "redeem_url": "https://pokewallet.io/dashboard" } |
403 — trial expired | { "error": "Pro plan required", "upgrade_url": "https://pokewallet.io/pricing" } |
/sets/trendingPROReturns the sets with the highest average price variation over the last 7 or 30 days, based on CardMarket moving averages. Each set includes the top movers (individual cards with the largest price change).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
period | string | Optional | Time window: 7d (default) or 30d |
limit | number | Optional | Number of sets to return (default: 10, max: 50) |
Example Request:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/sets/trending?period=7d&limit=5"Response Example:
{
"period": "7d",
"trending_sets": [
{
"set_name": "Miracle of the Desert",
"set_code": "-4",
"card_count": 46,
"cardmarket": {
"price_change": "+90.6%",
"avg_price_current": 15.67,
"avg_price_previous": 8.22,
"top_movers": [
{ "name": "Dusclops (ADV2 031)", "change": "+449.1%" },
{ "name": "Raichu ex (ADV2 023)", "change": "+433.3%" },
{ "name": "Typhlosion ex (ADV2 013)", "change": "+389.4%" }
]
},
"tcgplayer": null
},
{
"set_name": "BW1_ Black Collection",
"set_code": "23893",
"card_count": 18,
"cardmarket": {
"price_change": "+40.8%",
"avg_price_current": 2.22,
"avg_price_previous": 1.58,
"top_movers": [
{ "name": "Beartic (BW1b 018)", "change": "+171.2%" },
{ "name": "Emboar (BW1b 010)", "change": "+97.4%" },
{ "name": "Sawsbuck (BW1b 007)", "change": "-86.3%" }
]
},
"tcgplayer": {
"status": "work_in_progress",
"message": "TCGPlayer price history not yet available"
}
}
]
}Trial Response Headers:
When accessing this endpoint during an active trial, two extra headers are included:
X-Trial-Expires-At: 2026-05-01T00:00:00.000Z
X-Trial-Days-Remaining: 7Error Responses:
| Status | Description |
|---|---|
403 — trial not activated | { "error": "Trial not activated", "redeem_url": "https://pokewallet.io/dashboard" } |
403 — trial expired | { "error": "Pro plan required", "upgrade_url": "https://pokewallet.io/pricing" } |
/sets/:setCode/completion-valuePROCalculates the estimated cost to complete a set by buying one copy of every card. Returns separate estimates for TCGPlayer (USD) and CardMarket (EUR) — no cross-currency conversion is performed. Includes a breakdown by rarity.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
setCode | string | Required | Numeric group_id (23599) or alphanumeric set code (sv2a). CardMarket-only sets (negative group_id) return 404. |
Example Request:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/sets/23599/completion-value"Response Example:
{
"set_info": {
"name": "SV2a_ Pokemon Card 151",
"set_code": "23599",
"total_cards": 524
},
"completion_cost": {
"tcgplayer": {
"currency": "USD",
"low_estimate": 4516.16,
"market_estimate": 4056.03,
"high_estimate": 13687.29
},
"cardmarket": {
"currency": "EUR",
"low_estimate": 683.50,
"avg_estimate": 1232.46,
"trend_estimate": 1526.69
},
"note": "TCGPlayer prices in USD, CardMarket prices in EUR. Cross-currency comparison not available."
},
"breakdown_by_rarity": {
"Common": { "count": 199, "total_cost": 950.32 },
"Uncommon": { "count": 186, "total_cost": 732.37 },
"Rare": { "count": 77, "total_cost": 645.50 },
"Double Rare": { "count": 12, "total_cost": 8.29 },
"Art Rare": { "count": 18, "total_cost": 254.25 },
"Super Rare": { "count": 16, "total_cost": 85.38 },
"Special Art Rare": { "count": 8, "total_cost": 893.35 },
"Ultra Rare": { "count": 3, "total_cost": 31.02 },
"Unknown": { "count": 5, "total_cost": 12.47 }
}
}completion_cost and breakdown_by_rarity. See Product Types. {
"success": false,
"error": "This is a CardMarket-only set without TCGPlayer pricing data"
}Trial Response Headers:
When accessing this endpoint during an active trial, two extra headers are included:
X-Trial-Expires-At: 2026-05-01T00:00:00.000Z
X-Trial-Days-Remaining: 7Error Responses:
| Status | Description |
|---|---|
403 — trial not activated | { "error": "Trial not activated", "redeem_url": "https://pokewallet.io/dashboard" } |
403 — trial expired | { "error": "Pro plan required", "upgrade_url": "https://pokewallet.io/pricing" } |
Prices Endpoints
/prices/:setCodePROReturns prices for every card in a Pokémon set, flat list, all variants. Use ?source to restrict to a single marketplace.
Path Parameter:
| Parameter | Type | Examples |
|---|---|---|
:setCode | string or number | MEW, sv2a (set code, case-insensitive) | 22873, -188 (numeric group_id) |
Query Parameters:
| Parameter | Type | Required | Values |
|---|---|---|---|
source | string | No | tcg — TCGPlayer only | cm — CardMarket only | omit for both |
Example Requests:
# Both sources (default)
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/prices/MEW"
# TCGPlayer only
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/prices/MEW?source=tcg"
# By numeric group_id
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/prices/22873"Response Example:
{
"success": true,
"source": "both",
"set_code": "MEW",
"group_id": "23237",
"total": 361,
"data": [
{
"id": "pk_72046138a4c1908a9f27c93fdd8189ba4ac8e683efaed6b9161efcef129302394a9ec1d20d",
"card_number": "001/165",
"name": "Bulbasaur - 001/165",
"variant": "Normal",
"product_type": "card",
"tcgplayer": {
"low_price": 0.05,
"mid_price": 0.20,
"high_price": 2.00,
"market_price": 0.15,
"direct_low_price": 0.10,
"updated_at": "2026-05-04T07:43:36.088579"
},
"cardmarket": {
"avg": 0.10,
"low": 0.04,
"trend": 0.09,
"avg1": 0.08,
"avg7": 0.09,
"avg30": 0.11,
"updated_at": "2026-05-04T06:47:05.90041"
}
},
{
"id": "pk_72046138a4c1908a9f27c93fdd8189ba4ac8e683efaed6b9161efcef129302394a9ec1d20d",
"card_number": "001/165",
"name": "Bulbasaur - 001/165",
"variant": "Reverse Holofoil",
"product_type": "card",
"tcgplayer": { "market_price": 0.30, ... },
"cardmarket": null
},
{
"id": "pk_9a1c2e7f4b0d8365a1f2e9c7b4a08d6e1f3c5a7b9d0e2f4a6c8b0d2e4f6a8c0b",
"card_number": null,
"name": "Mew Booster Box",
"variant": "products",
"product_type": "sealed",
"tcgplayer": { "market_price": 145.0, ... },
"cardmarket": null
}
]
}Disambiguation (300):
If :setCode matches multiple sets (e.g. same code in different languages), a 300 is returned. Pass the numeric group_id directly to disambiguate.
{
"disambiguation": true,
"message": "Multiple sets found for 'SVI'. Use the numeric group_id to specify which one.",
"matches": [
{ "group_id": "22873", "set_code": "SVI" },
{ "group_id": "23822", "set_code": "svI" }
]
}Error Codes:
| HTTP | Condition |
|---|---|
400 | Invalid source value |
401 | Missing or invalid API key |
403 | Plan does not include this endpoint — upgrade to Pro or activate the 7-day trial |
404 | Set not found, or source=tcg on a CM-only set |
group_id < 0): tcgplayer: null on all cards and variant: null. For Japanese sets, cardmarket: null is expected as CM only covers the EU market. Response is cached for 15 minutes. Sealed Products: sealed rows (
product_type: "sealed") stay in the list, priced via TCGPlayer only — cardmarket is always null for them, on both TCG and CM-only sets. See Product Types. Analytics Endpoints
/analytics/top-cardsProGet the top N cards ranked by current price or 7-day percentage growth, from TCGPlayer or CardMarket.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
metric | string | Optional | Ranking metric. One of price (default) or growth (7-day % change). Any other value returns 400. |
source | string | Optional | Price source. One of tcg (default) or cm. Any other value returns 400. |
limit | number | Optional | Number of results to return (default: 20, max: 100). |
Example Request:
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/analytics/top-cards?metric=growth&source=cm&limit=10"Response Example — metric=price&source=tcg:
{
"metric": "price",
"source": "tcg",
"top_cards": [
{
"id": "pk_abc123",
"card_info": {
"name": "Charizard VSTAR",
"set_name": "Brilliant Stars",
"card_number": "018/172",
"rarity": "Ultra Rare"
},
"current_price": 42.50
}
]
}Response Example — metric=growth&source=cm:
{
"metric": "growth",
"source": "cm",
"top_cards": [
{
"id": "pk_def456",
"card_info": {
"name": "Charizard ex (SV3 125)",
"set_code": "SV3",
"card_number": "125"
},
"current_price": 18.50,
"change_7d": "+54.2%"
}
]
}metric=growth ranks by 7-day change. For source=tcg uses price_7d snapshots — cards without 7-day history are excluded. For source=cm uses CardMarket's native avg7.Trial Response Headers:
When accessing this endpoint during an active trial, two extra headers are included:
X-Trial-Expires-At: 2026-05-01T00:00:00.000Z
X-Trial-Days-Remaining: 7Error Responses:
| Status | Description |
|---|---|
403 — trial not activated | { "error": "Trial not activated", "redeem_url": "https://pokewallet.io/dashboard" } |
403 — trial expired | { "error": "Pro plan required", "upgrade_url": "https://pokewallet.io/pricing" } |
Images Endpoint
/images/:idRetrieve card images by card ID with automatic fallback system. Returns binary image data (JPEG, or WebP for localized images). Supports both TCG card IDs (pk_xxx) and CardMarket-only card IDs (no prefix). Localized card artwork is available in 5 European languages via the lang parameter.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Required | Card ID - Two formats supported:
/search, /cards/:id, or /sets/:setCode |
size | string | Optional | Image size: low (~500px, ~50KB) or high (~1000px, ~200KB). Default: low |
lang | string | Optional | Localized image language: it, fr, de, es, or pt. If a localized version exists, it is served as WebP; otherwise the request silently falls back to the card's default image (never a 404 because of the language). Check the card's images.languages field to know which languages are available. |
Response Headers:
Content-Type:image/jpeg, orimage/webp(localized images)X-Image-Lang: language code of the served image (only present on localized responses, e.g.it)Cache-Control:public, max-age=31536000, immutable
Localized Images (Multi-Language):
By default, each card is served with its original artwork: English for international sets, Japanese for Japanese sets. For English-language cards, localized European variants may also be available where a translated print exists: Italian (it), French (fr), German (de), Spanish (es) and Portuguese (pt).
The recommended flow:
- Fetch the card from
/cards/:id,/search, or/sets/:setCodeand read itsimages.languagesarray (e.g.["en", "it", "de"]). - If it contains your user's language, request
/images/:id?lang=xxto get the localized WebP. - If it doesn't (or the localized file is missing), the API serves the card's default image (English or Japanese) — requests with
langare always safe.
lang behave exactly as before. The X-Image-Lang header tells you when a localized WebP was served; its absence means the card's default image (English or Japanese) was returned. Example Requests:
TCG Card (with pk_ prefix):
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/images/pk_72046138a4c1908a9f27c93fdd8189ba4ac8e683efaed6b9161efcef129302394a9ec1d20d?size=high" \
--output pikachu_tcg.jpgLocalized Card Image (Italian):
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/images/pk_72046138a4c1908a9f27c93fdd8189ba4ac8e683efaed6b9161efcef129302394a9ec1d20d?size=high&lang=it" \
--output pikachu_it.webpCardMarket-Only Card (no prefix):
curl -H "X-API-Key: pk_live_your_key_here" \
"https://api.pokewallet.io/images/8eb728bd59d4e1a0d94c354e4cc65a7465b55cfa4261bfa93301faa5ec921f97?size=high" \
--output cubone_v1.jpgset parameter for disambiguation. The ID itself uniquely identifies the exact card variant you want. Example Response (Headers):
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 123456
Cache-Control: public, max-age=31536000, immutable
[Binary image data]Example Response (Localized, Headers):
HTTP/1.1 200 OK
Content-Type: image/webp
Content-Length: 98765
X-Image-Lang: it
Cache-Control: public, max-age=31536000, immutable
[Binary image data]Code Examples
const API_KEY = process.env.POKEWALLET_API_KEY;
const BASE_URL = 'https://api.pokewallet.io';
async function searchCards(query) {
const response = await fetch(`${BASE_URL}/search?q=${encodeURIComponent(query)}`, {
headers: {
'X-API-Key': API_KEY
}
});
if (!response.ok) {
if (response.status === 429) {
throw new Error('Rate limit exceeded');
}
throw new Error(`API error: ${response.status}`);
}
const data = await response.json();
return data;
}
async function getCardImage(cardId, size = 'high') {
const url = `${BASE_URL}/images/${cardId}?size=${size}`;
const response = await fetch(url, {
headers: {
'X-API-Key': API_KEY
}
});
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.status}`);
}
// Return blob for display or download
const blob = await response.blob();
return blob;
}
// Usage - Search TCG cards
searchCards('pikachu')
.then(data => {
console.log('TCG card results:', data);
// IDs will have pk_ prefix
})
.catch(error => console.error(error));
// Usage - Search CardMarket-only cards
searchCards('cubone cbb3c')
.then(data => {
console.log('CardMarket-only results:', data);
// IDs will NOT have pk_ prefix
})
.catch(error => console.error(error));
// Usage - Get Image (TCG card with pk_ prefix)
getCardImage('pk_72046138a4c1908a9f27c93fdd8189ba...', 'high')
.then(blob => {
const imageUrl = URL.createObjectURL(blob);
document.querySelector('img').src = imageUrl;
})
.catch(error => console.error(error));
// Usage - Get Image (CardMarket-only, no prefix)
getCardImage('8eb728bd59d4e1a0d94c354e4cc65a74...', 'high')
.then(blob => {
const imageUrl = URL.createObjectURL(blob);
document.querySelector('img').src = imageUrl;
})
.catch(error => console.error(error));Error Handling
The API uses standard HTTP status codes to indicate success or failure:
Request successful
Invalid parameters or malformed request
Missing or invalid API key
Paid endpoint without the required plan or an active trial: Pro for Pokémon and One Piece, Ultra for the other games. The body includes redeem_url (trial not activated yet) or upgrade_url (trial expired).
Card, set or image does not exist
The API only accepts GET requests.
/sets/:setCode/image: the set code matches several sets. Retry with ?language= or the numeric set_id.
Rate limit exceeded
Something went wrong on our side
An image could not be fetched from its source. Temporary: retry later.
Errors on game endpoints (/mtg, /ygo, …)
| Status | error | When |
|---|---|---|
| 400 | Invalid or corrupted card ID | ID is neither <game>_… nor 64 hex, or belongs to another game |
| 400 | Query parameter required | q missing, shorter than 2 or longer than 100 characters |
| 400 | Search query rejected | q contains SQL-like text: rephrase it |
| 400 | Invalid or corrupted card ID + did_you_mean | The ID belongs to another game (e.g. a lor_… ID on /mtg/cards): did_you_mean has the right path |
| 404 | Set not found + suggestions | No set with that set_id/set_code. If you wrote the set name, suggestions lists the matching sets with their set_id |
| 404 | Card not found, Image not found | Card or image does not exist |
| 502 | Image not available | Image source temporarily unreachable |
| 503 | Search temporarily unavailable | The search took too long under load. Retry after the seconds in the Retry-After header, or use more specific words |
Error Response Format
Every error has error (short, stable) and message (what to fix). When the API can tell what you meant, did_you_mean contains the corrected path:
// GET /magic/sets
{
"error": "Endpoint not found",
"message": "Did you mean /mtg/sets?",
"did_you_mean": "/mtg/sets",
"docs": "https://pokewallet.io/api-docs"
}Authentication errors (401) also include an example request. A trailing slash is ignored: /sets/ and /sets are the same endpoint.
Best Practices
Use Environment Variables
Never hardcode API keys. Always use environment variables or secure secret management.
Handle Rate Limits Gracefully
Implement exponential backoff when you receive a 429 response. Check rate limit headers to avoid hitting limits.
Cache Results
Cache API responses when appropriate to reduce requests and improve performance.
Use Search Endpoint
Always use /search for the most complete and accurate data.
Monitor Your Usage
Check your dashboard regularly to track API usage and avoid unexpected rate limit hits.
Error Handling
Always implement proper error handling for network failures, rate limits, and invalid responses.
Pokémon TCG API FAQ
Is the Pokémon TCG API free?
Yes. The free tier (100 requests/hour, 1,000/day) covers sets, set cards, card details, search and images, with TCGPlayer and CardMarket prices. Price history, prices by set, set statistics, completion value, trending sets and top cards need the Pro plan (€20/month); a 7-day free trial starts from the dashboard.
Does the Pokémon TCG API include CardMarket prices?
Yes. Cards return TCGPlayer (USD) prices for each variant (Normal, Holofoil, Reverse Holofoil, 1st Edition…) and CardMarket (EUR) prices for normal and holo. Cards sold only on CardMarket, such as Japanese sets and European promos, have an id without the pk_ prefix.
Can I get the price history of a Pokémon card?
Yes. GET /cards/:id/price-history returns TCGPlayer and CardMarket price snapshots with the percentage change over 7, 14, 30, 60 and 120 days. It needs the Pro plan (€20/month) or its 7-day trial.
Can I use the same API key for other games?
Yes. One PokéWallet API key works for all 12 games, Pokémon and One Piece included, and the rate limits are shared across them.
Need Help?
If you have questions or run into issues, we're here to help!