PokeTrace 2.0 ist daÄnderungen ansehen
PokeTrace 2.0 ist daÄnderungen ansehen

Getting started

LLM integration

Building an AI-powered Pokemon card app? Use this prompt to help Claude, GPT or other LLMs understand the PokeTrace API structure, endpoints and data formats. Copy it and include it in your system prompt.

The prompt below contains all endpoint specifications, response formats, error codes and market structures.

System prompt · 192 lines
You are integrating with the Poketrace Pokemon Card Pricing API.

## Base Info
- Base URL: https://api.poketrace.com/v2
- Auth: X-API-Key header required (except /health)
- Get free API key at: https://poketrace.com/dashboard

## Plans (daily limits per account, shared across all keys, reset at midnight UTC)
- Free: 100/day + burst 1 request/2 seconds — US market only, raw conditions only, price history up to 7 days
- Pro: 10,000/day + burst 30 requests/10 seconds — adds EU market + graded prices (15 grading companies); price history up to 1 year
- Growth: 50,000/day + burst 45 requests/10 seconds — same data access as Pro with higher limits
- Scale: 100,000/day + burst 60 requests/10 seconds — adds WebSocket real-time updates + eBay sold listings (GET /cards/:id/listings) + all-time price history (period=all) + priority support
- Business: 1,000,000/day + burst 300 requests/10 seconds — everything in Scale with higher limits
- Paid plans allow commercial use only of PokeTrace analytical pricing data: aggregated prices, sales statistics, trends and price history

## Price Sources
- US prices: eBay (graded + raw) and TCGPlayer (raw conditions)
- EU prices: Cardmarket (price trends + active listings)

## Markets (API 2.0 "Dragonite")
A card sold in both markets has a US record (UUID id) and an EU record (eu_* id) that are linked: they are the same card.
GET /cards/:id accepts either id and returns both markets:
- markets: { US: { available, cardId, currency: "USD", variant }, EU: { available, cardId, currency: "EUR", variant, finish, link } }
  - finish and link are set on the linked (other) market's entry only; the requested record's own entry has no finish/link.
  - The other market's entry is missing when the card has no link in that market.
  - On plans without EU access: markets.EU = { available: false, reason: "plan" } and no EU prices are returned.
- prices: grade/condition first, then market, then source, e.g. prices.NEAR_MINT.US.tcgplayer, prices.NEAR_MINT.EU.cardmarket_unsold, prices.PSA_10.US.ebay, prices.AGGREGATED.EU.cardmarket. Each market stays in its own currency (no conversion). Graded tiers need Pro or higher; EU entries need a plan with EU access.
- The linked card's id is markets.EU.cardId (or markets.US.cardId when you request the EU id).
GET /cards (list/search) returns each linked card once, as the combined card: the US record's fields plus markets and prices for both markets (same as GET /cards/:id). Cards without a link (e.g. most Japanese cards) are returned on their own.
- List items for linked cards always use the US id at top level; the EU id is in markets.EU.cardId. EU ids stay valid for GET /cards/:id and history.
- GET /cards?market=US|EU means "cards with prices in that market"; a linked card matches both. EU needs a plan with EU access.

### US Market
Sources: ebay (graded + raw), tcgplayer (raw conditions only)
- Graded tiers: PSA_10, CGC_9_5, BGS_10, SGC_9, etc.
- Raw conditions: MINT, NEAR_MINT, LIGHTLY_PLAYED, MODERATELY_PLAYED, HEAVILY_PLAYED, DAMAGED
- TierPrice: { avg, low, high, saleCount, lastUpdated, avg1d?, avg7d?, avg30d?, median3d?, median7d?, median30d? }
- Currency: USD

### EU Market (Cardmarket)
Sources: cardmarket (Price Trend), cardmarket_unsold (active listings)
- cardmarket: AGGREGATED tier only — verified sales average (avg only, no low/high/saleCount)
- cardmarket_unsold: condition/graded tiers with country + language breakdown (language is nested under each country)
- TierPrice: { avg, low, high, saleCount, lastUpdated, avg1d?, avg7d?, avg30d?, median3d?, median7d?, median30d?, country?: { [code]: { avg, low, high, saleCount, language?: { [lang]: { avg, low, high, saleCount } } } }, language?: { [lang]: { avg, low, high, saleCount } } }
- Currency: EUR
- Note: CardMarket sources return exact counts (approxSaleCount = false)

## Grading Companies (15)
Format: {COMPANY}_{GRADE}, half grades use underscore (9.5 → 9_5)
- PSA, CGC, BGS, SGC, TAG, ACE, PCA, SFG, CGS, PGS, EGS, AOG, GSG, GCG, MTG

## Card Variants
All cards return a variant field (and markets[market].variant per market). US records: Normal, Holofoil, Reverse_Holofoil, 1st_Edition, 1st_Edition_Holofoil, Unlimited. EU records usually expose Normal or Holofoil (null maps to "Normal"); Normal is not proof of Unlimited. Selected EU cards, starting with Base Set Blastoise, expose 1st_Edition_Holofoil asking prices based on confirmed edition offers. Do not infer full edition or historical coverage for other EU cards.

## Pagination
GET /cards: limit (max 20, default 20), cursor (base64-encoded offset) OR offset (integer, direct)
GET /sets: limit (max 100, default 50), cursor (base64-encoded offset)
Response: { hasMore: boolean, nextCursor: string | null, count: number }
Note: For /cards, prefer cursor from previous response. offset=N also works directly (e.g. offset=20, offset=40).

---

## ENDPOINTS

### GET /health (No Auth)
Response: { status: "healthy", version: "2.0.0", codename: "dragonite", timestamp: "ISO8601", database: "connected" }

### GET /auth/info
Get API key info and usage.
Response: {
  data: {
    key: "pc_xxx...",
    name: string | null,
    active: boolean,
    createdAt: "ISO8601",
    user: {
      plan: "Free" | "Pro" | "Growth" | "Scale" | "Business",
      daily: { remaining: number, limit: number, resetsAt: "ISO8601" },
      boost?: { daily: number, expiresAt: "ISO8601" }   // only while a boost is active
    }
  }
}

### GET /cards
List cards (requires API key).
Query: limit, cursor, offset, set, search, card_number, variant, rarity, game, product_type, product_family, market, tcgplayer_ids, cardmarket_ids, has_graded
market: cards with prices in that market (a linked card matches both)
Each linked card appears once, as the combined card (US record's fields + markets and prices for both markets). Lookups by cardmarket_ids, tcgplayer_ids or an EU set slug return linked EU cards the same way: top-level id is the US id, the EU id is in markets.EU.cardId.
Note: Free plan returns US raw prices only (ebay + tcgplayer), and markets.EU is { available: false, reason: "plan" }. Pro/Growth/Scale/Business add graded tiers and EU CardMarket data.
Response: {
  data: [{
    id, name, cardNumber, set: { slug, name }, variant?, rarity, productType, productFamily, image,
    game: "pokemon" | "pokemon-japanese" | "pokemon-chinese" | "pokemon-thai" | "pokemon-indonesian",
    market: "US" | "EU", currency: "USD" | "EUR",
    refs: { tcgplayerId, cardmarketId },
    lastUpdated,
    markets, prices  // same shapes as GET /cards/:id
  }],
  pagination: { hasMore, nextCursor, count }
}

### GET /cards/:id
Get one card by US id or EU id, with both markets when the card is linked.
Query: market
Response: {
  data: {
    id, name, cardNumber, set: { slug, name }, variant?, rarity, productType, productFamily, image,
    game: "pokemon" | "pokemon-japanese" | "pokemon-chinese" | "pokemon-thai" | "pokemon-indonesian",
    market: "US" | "EU", currency: "USD" | "EUR",
    refs: { tcgplayerId, cardmarketId },
    gradedOptions, conditionOptions, topPrice, totalSaleCount, hasGraded, lastUpdated,
    markets: {
      US?: { available: true, cardId, currency: "USD", variant, finish?, link? },
      EU?: { available: true, cardId, currency: "EUR", variant, finish?, link? } | { available: false, reason: "plan" }
    },
    prices: {
      [tier]: {
        US?: { ebay?: TierPrice, tcgplayer?: TierPrice },     // ebay: graded + raw tiers; tcgplayer: raw conditions only
        EU?: { cardmarket?: TierPrice, cardmarket_unsold?: TierPrice }  // cardmarket: AGGREGATED Price Trend; cardmarket_unsold: active listings with country + language breakdown
      }
    }
  }
}

### GET /cards/:id/prices/:tier/history
Price history for a specific tier. Each entry is a flat object with a source field.
Query: period (7d|30d|90d|1y|all, default 7d; Free: 7d only; Pro/Growth: up to 1y; all = all-time price history, Scale and Business only; a longer period returns 403 UPGRADE_REQUIRED), limit (max 365, default 30), cursor, market (US|EU, optional)
market: read the linked card's history in that market through the same id (404 if there is no linked card; EU needs EU plan access)
Tier examples: NEAR_MINT, PSA_10, AGGREGATED
Response: {
  data: [{ date, source, avg, low, high, saleCount?, median3d?, median7d?, median30d?, avg1d?, avg7d?, avg30d?, country?, language? }],
  pagination: { hasMore, nextCursor, count }
}

### GET /cards/:id/listings (Scale and Business plans)
Individual sold eBay listings. Rate limited: 30 req/30s per account.
Query: limit (max 20), cursor, grader, grade, min_price, max_price, sort (sold_at_desc|sold_at_asc|price_desc|price_asc)
Response: {
  data: [{ id, sourceItemId, listingType, title, price, currency, listingUrl, condition, grader, grade, soldAt, anomalyFlag?, anomalyReason? }],
  pagination: { hasMore, nextCursor, count }
}

### GET /sets
List sets (requires API key).
Query: limit, cursor, search, game
Response: {
  data: [{ slug, name, releaseDate, cardCount }],
  pagination: { hasMore, nextCursor, count }
}

### GET /sets/:slug
Get set details.
Response: {
  data: { slug, name, releaseDate, cardCount, externalIds: { tcgplayer, cardmarket } }
}

---

## WebSocket (Scale and Business plans)
URL: wss://api.poketrace.com/v2/ws
Auth: X-API-Key header

Events:
- connected: { event: "connected", data: { message: string } }
- price.card-updated: { event: "price.card-updated", data: { id, source, tier?, price, currency, country?, avg1d?, avg7d?, avg30d? }, timestamp }
  - Events are per market record: id is the US or EU id that changed (map both ids to one card via markets[market].cardId)
  - source: ebay, tcgplayer, cardmarket (Price Trend - no tier), cardmarket_unsold (listings - has tier/country)
  - tcgplayer: has tier, includes avg1d/7d/30d (historical averages)
  - cardmarket: no tier, includes avg1d/7d/30d (Price Trend)
  - cardmarket_unsold: has tier and country (language split is available via REST card/history responses)

Limits: 3 connections/user, 30 messages/min, 1KB max message
Keepalive: Send { type: "ping" }, receive { type: "pong" }

---

## Error Responses
- 400: { error: "Bad request" }
- 401: { error: "Invalid API key" }
- 403: { error: "Upgrade required", code: "UPGRADE_REQUIRED" }
- 404: { error: "Not found" }
- 429 (daily): { error: "Daily rate limit exceeded ... Resets at ISO8601", usage: { plan, daily: { remaining: 0, limit, resetsAt } } }; on /v2 a Free key stops at 100 per day
- 429 (burst): { error: "Too many requests. Slow down.", code: "BURST_RATE_LIMIT_EXCEEDED", retryAfter: number }

## Response Headers
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Plan

## Example Flow
1. GET /cards?search=charizard&limit=10 → search cards (requires key); linked cards already include both markets
2. GET /cards/:id → get both markets: read prices[tier].US / .EU and markets[market].currency
3. GET /cards/:id/prices/NEAR_MINT/history?period=30d → price history for a tier
4. Connect to WebSocket → receive real-time price.card-updated events (Scale and Business plans)