CompSniper Docs

TCGplayer Sold Prices API

Get TCGplayer completed sales, market price history and active listings for Pokemon, Magic, Yu-Gi-Oh and other trading cards with one API key.

CompSniper has two TCGplayer endpoints for trading cards and sealed products (Pokemon, Magic: The Gathering, Yu-Gi-Oh, One Piece, Lorcana, sports and more):

EndpointWhat you get
GET /v1/tcgplayer/soldCompleted sales (price, condition, variant, language, quantity, date) plus optional market price history
GET /v1/tcgplayer/listingsActive listings with price, shipping, condition and seller details

Both use the same API key, per-minute limit, monthly allowance and purchased credits as the eBay endpoints. No TCGplayer account is needed, and you get the full sale history for each product, not just the latest few sales.

For an overview with code in cURL, Python and JavaScript, see the TCGplayer API page.

Find a product

Send a keyword (card name, set, number) or an exact TCGplayer productId. With a keyword, CompSniper picks the best matching product and lists other close matches in otherMatches, so you can repeat the call with the right productId when a name is ambiguous.

curl --fail-with-body \
  -H "Authorization: Bearer cs_live_REPLACEWITHYOURKEY" \
  "https://api.compsniper.com/v1/tcgplayer/sold?keyword=charizard+ex+obsidian+flames+223&count=100&history=quarter"

The productId is the number in a TCGplayer product URL, for example https://www.tcgplayer.com/product/123456/... has productId=123456.

Search by product name, not an eBay title

The keyword is matched against TCGplayer's own product names. An eBay or marketplace listing title pasted as is (with words like "sealed", "mint", "AU stock", "eBay Live", emojis or lot sizes) usually matches no product, so the call returns no sales. Several products in one keyword ("Prismatic Evolutions + 151 + CR") also match nothing: send one call per product.

Returns no salesWorks
#001 - [EBAY LIVE] Pokémon TCG Scarlet & Violet 151 English Booster Bundle - NewPokemon 151 Booster Bundles
Pokemon 151 Japanese Booster Box AU stock on handPokemon Japanese 151 booster box

Use the card or product name, the set, and the card number when there is one. Once you know the right product, send its productId: it always returns that exact product and skips the name match.

Sold parameters

ParameterValuesDefault
keywordCard or product name, up to 300 charactersRequired unless productId is sent
productIdTCGplayer product IDNone
count1 to 250 sales100
conditionFor example Near Mint, Lightly PlayedAll conditions
variantFor example Normal, Holofoil, Reverse HolofoilAll variants
languageFor example English, JapaneseAll languages
historynone, month, quarter, annual (market price buckets)none
soldAfterYYYY-MM-DD: only sales on or after this date (UTC)None
soldBeforeYYYY-MM-DD: only sales on or before this date (UTC)None
freshtrue fetches the latest sales live from TCGplayerfalse

Daily pulls and busy products

Results come back instantly: repeat calls can be answered from a short-lived saved copy. When you need the newest sales right now, add fresh=true and the call goes live to TCGplayer. It costs one request, the same as any other call.

soldAfter and soldBefore trim the returned sales to a date window, so a nightly job can ask only for what it has not stored yet (keep a one-day overlap and deduplicate on your side). They filter the newest sales TCGplayer exposes for the product (up to 250); they do not reach further back. count applies before the date filter, so send count=250 with a date window. For a product that sells more than 250 copies a day, call it two or three times a day with fresh=true and soldAfter set to today.

Sold response

Example response (shortened)
{
  "keyword": "charizard ex obsidian flames 223",
  "marketplace": "tcgplayer",
  "product": {
    "productId": 123456,
    "name": "Charizard ex - 223/197",
    "productLine": "Pokemon",
    "setName": "SV03: Obsidian Flames",
    "number": "223/197",
    "rarity": "Special Illustration Rare",
    "sealed": false,
    "marketPrice": 74.5,
    "lowestPrice": 69.99,
    "lowestPriceWithShipping": 71.98,
    "totalListings": 212,
    "url": "https://www.tcgplayer.com/product/123456"
  },
  "otherMatches": [],
  "salesHistory": "full",
  "totalSales": 1840,
  "totalItems": 100,
  "items": [
    {
      "title": "Charizard ex - 223/197",
      "condition": "Near Mint",
      "variant": "Holofoil",
      "language": "English",
      "quantity": 1,
      "price": 73.0,
      "shipping": 1.99,
      "totalPrice": 74.99,
      "soldAt": "2026-10-09T18:22:41Z",
      "listingType": "ListingWithoutPhotos"
    }
  ],
  "priceHistory": [
    {
      "date": "2026-10-08",
      "variant": "Holofoil",
      "condition": "Near Mint",
      "language": "English",
      "marketPrice": 74.12,
      "quantitySold": 31,
      "transactionCount": 27,
      "lowSalePrice": 68.0,
      "highSalePrice": 79.95
    }
  ],
  "summary": { "count": 100, "currency": "USD", "median": 73.5, "mean": 73.62, "min": 64, "max": 82.5, "p25": 71, "p75": 76, "avgShipping": null },
  "scrapedAt": "2026-10-10T01:12:09Z"
}
  • salesHistory is "full" when the complete history was returned. If it ever says "limited", only the most recent sales were available for that call; retry later for the full list.
  • totalSales is TCGplayer's count of all recorded sales for the product; items holds up to count of the newest ones.
  • priceHistory (only with history=month|quarter|annual) gives daily or weekly market-price buckets with units sold, transaction count and the low and high sale price. It is null when not requested.
  • summary holds the count, median, mean, min, max, p25 and p75 of the returned sale prices.

Active listings

curl --fail-with-body \
  -H "Authorization: Bearer cs_live_REPLACEWITHYOURKEY" \
  "https://api.compsniper.com/v1/tcgplayer/listings?productId=123456&condition=Near+Mint&count=25&page=1"
ParameterValuesDefault
keyword or productIdSame as the sold endpointRequired
page1 to 501
count1 to 50 listings per page25
condition, variant, languageSame filters as the sold endpointAll

Each listing has listingId, price, shipping, totalPrice, condition, variant, language, quantity, sellerName, sellerRating, sellerSales, sellerLocation, and the goldSeller, verifiedSeller and directSeller flags. The response includes totalListings and hasNextPage for paging. Asking prices are not sales, so listings responses carry no price summary.

Billing

  • One successful call is one request, for sold and listings alike.
  • Failed requests are free.
  • Repeat calls can return instantly from a short-lived saved copy and count as one request. Add fresh=true for a live fetch.

Errors

The TCGplayer endpoints use the shared error format (code, error, requestId). The ones you are most likely to see:

StatusCodeMeaningWhat to do
400invalid_paramsMissing keyword and productId, or a value out of rangeFix the request
429rate_limited / quota_exceededPer-minute limit or monthly allowance reachedSee Rate limits
502, 503upstream_blocked / server_busyTCGplayer did not answer this timeRetry after a few seconds, with a bound

See Errors for the full list.

On this page