← compsapi.com

CompsAPI Reference

Real eBay sold prices as JSON. Up to 3 years of history, prices are what buyers actually paid (accepted best offers included), with a trading card layer for graded cards, raw cards and comps.

https://api.compsapi.com

Quickstart

1. Check your key

Every request sends your key in the X-API-Key header. This call is free and shows your limits.

curl -H "X-API-Key: YOUR_API_KEY" https://api.compsapi.com/v1/usage

2. Get comps for a card

One call returns price stats from every matching sale in the last 90 days, plus the 10 newest sales.

curl -H "X-API-Key: YOUR_API_KEY" \
  "https://api.compsapi.com/v1/comps?q=umbreon+vmax+215/203&grader=PSA&grade=10"

3. Read the answer

{
  "ok": true,
  "query": "umbreon vmax 215/203",
  "count": 84,
  "count_before_filters": 241,
  "filters": { "grader": "PSA", "grade": "10", "exclude": "junk" },
  "stats": {
    "count": 84, "median": 3937.0, "mean": 3993.86, "p25": 3849.99, "p75": 4058.93,
    "min": 3375.0, "max": 4650.0, "outliers_removed": 0,
    "newest_sale": "2026-10-05T22:46:00Z", "oldest_sale": "2026-09-14T23:45:00Z"
  },
  "items": [
    {
      "item_id": "820200933060",
      "title": "Pokemon TCG Umbreon VMAX 215/203 PSA 10 Evolving Skies",
      "last_sold": "2026-10-05T22:46:00Z",
      "price": 3800.0,
      "format": "FIXED_PRICE",
      "url": "https://www.ebay.com/itm/820200933060",
      "card": { "graded": true, "grader": "PSA", "grade": "10", "card_number": "215/203",
                "language": null, "first_edition": false, "flags": [] }
    }
  ]
}

Same card, ungraded: /v1/comps?q=umbreon+vmax+215/203&graded=false (94 sales, median $1,692.50 at the time of writing).

Authentication

Send your key in the X-API-Key header. Authorization: Bearer YOUR_API_KEY also works. Keep the key on your server; do not ship it in a browser or mobile app.

Set a User-Agent header on every request (most HTTP libraries do this for you). Requests from Python's built-in urllib without one are blocked by our firewall; requests, httpx, Node fetch, axios, Go and curl all work as is.

Sold listings

GET/v1/sold returns sold listings for a search, newest sale first.

ParameterDefaultDescription
qrequiredSearch terms, max 300 characters. eBay matches every word in the title.
days90How far back to search, 1 to 1095 (3 years).
size200Results per page, 10 to 240.
page1Page number, 1 to 50. When next_page is true, ask for the next page to get older sales.
conditionanyOnly sales in that condition: new, open_box, refurbished, used or parts. Comma separate to combine, for example new,open_box. With one value, every item also carries condition. Works on /v1/comps too.
best_offeroff1 adds best_offer to every item: true when the sale went through as an accepted offer. only returns accepted best offer sales and nothing else. Works on /v1/comps too.
card optionsoffAdd any of the card options to parse, filter and price the results.

Each search covers eBay US plus international eBay sites and a common spelling variant of your terms, merged and de-duplicated, so count can be a little higher than size.

Comps

GET/v1/comps is built for pricing a card. It searches the newest 200 sales over 90 days, removes junk listings, applies your card options and returns stats plus the 10 newest matching sales. One call counts as one request.

ParameterDefaultDescription
qrequiredThe card, as specific as you can (see tips).
days, size90, 200Same as /v1/sold.
excludejunkPass exclude=none to keep every listing.
card optionsgrader, grade, graded, lang, first_edition.

Stats

FieldDescription
countMatching sales with a price.
median, meanMiddle and average sold price (USD) after removing outliers.
p25, p7525th and 75th percentile: the range the middle half of sales fell in.
min, maxLowest and highest price used.
outliers_removedSales more than 3 times the middle range away from it (8+ sales needed), usually mislabeled listings.
newest_sale, oldest_saleThe time span the stats cover (UTC).

Usage

GET/v1/usage shows searches used today (UTC day), your daily limit and when your key expires. It does not count towards your limit.

{"ok": true, "day_utc": "2026-10-09", "used": 1250, "daily_cap": 5000,
 "trial_hours": 72, "trial_started": "2026-10-07T09:12:44Z", "expires": "2026-10-10T09:12:44Z"}

A trial key's clock starts at its first search, so expires is null until then.

Card options

Add these to /v1/sold or /v1/comps. Each item then gets a card object, and the options filter the results. On /v1/sold they filter the page you asked for; count_before_filters shows how many there were before.

OptionExampleKeeps
cards=1Everything, just adds the card object.
graderPSA, BGS,CGCCards graded by these companies. BECKETT counts as BGS. Also SGC, TAG, ACE and others.
grade10, 9.5, 9,10Cards with this grade.
gradedtrue / falseOnly slabs, or only raw cards. "PSA 10 contender" style listings count as raw.
langja, en,jaCards whose title names this language: en ja zh ko de fr it es pt. Titles that name none are left out when you use it.
first_editiontrue1st edition cards only (or false for none).
excludejunk, lot,sealedDrops listings with these flags. junk means lot, mystery, accessory, replica, keyword_stuffing, title_missing and not_graded_claim.
stats=1Adds stats for what is left (on /v1/comps it is always on).
# Which sales were accepted offers
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://api.compsapi.com/v1/sold?q=omega+speedmaster&days=30&best_offer=1"
# PSA 9 and 10 Japanese Luffy cards, no junk, with stats
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://api.compsapi.com/v1/sold?q=luffy+psa&grader=PSA&grade=9,10&lang=ja&exclude=junk&stats=1"

Card fields

Read from the listing title. Fields are null when the title does not say.

FieldExampleDescription
gradedtrueThe title names a grading company and a grade.
grader"PSA"PSA, BGS, CGC, SGC, TAG, ACE, AGS, HGA, GMA, MNT or ARS.
grade"9.5"Grade as text, so 9.5 stays exact.
grade_label"pristine"gem mint, pristine, black label, mint or near mint, when stated.
card_number"215/203", "OP05-119"Collector number or set code as written.
year1999Year in the title.
language"ja"Language named in the title.
first_editionfalseTitle says 1st edition.
flags["lot"]Warnings about the listing, see below.

Flags

FlagMeansExample title
lotMore than one card sold together."4 x Ace Grade 10 Charizard Bundle"
mysteryMystery pack, repack or "chance to win" listing."Mystery Graded Slab, chance at PSA 10 Charizard"
sealedSealed product: booster box, pack, ETB, tin."151 Booster Box SV2a Sealed"
accessoryCase, sleeves, binder or display, not a card."Acrylic case for booster box"
replicaCustom, proxy, fan art or fake."Umbreon VMAX Fan Art Holo"
keyword_stuffingSeveral graders named without a grade, usually to show up in searches."Charizard PSA bgs CGC tag"
not_graded_claimRaw card described with a grade ("contender", "potential PSA 10")."Charizard 4/102 PSA 10 Contender"
title_missingThe listing title was not available.

Card fields and flags come from rules that read the title. They catch the common patterns but will miss unusual titles, so treat flags as hints. We report what sold; we do not authenticate cards.

Getting good comps

Item fields

FieldDescription
item_ideBay item number.
titleListing title.
last_soldTime of the most recent sale on this listing (UTC).
priceAverage price actually paid per unit, USD. Accepted best offers show the real offer price, not the asking price.
units_sold, total_salesUnits sold on this listing in the window, and their total value.
formatFIXED_PRICE or AUCTION.
bidsNumber of bids (auctions).
best_offerOnly with best_offer=1 or only. true: sold as an accepted best offer, and price is the accepted offer. false: sold at the listed price or at auction. null: could not be confirmed either way (rare, mostly very busy searches).
shipping_cost, free_shipping_pctAverage shipping charged, and the share of sales with free shipping (0 to 100).
url, imageListing link and main image.
cardOnly with card options: see card fields.

Response fields: ok, query, page, ms (our response time), count, no_results, next_page, days, size, cached and cached_age_s (identical searches within 15 minutes come from cache), plus filters, count_before_filters and stats when card options are used.

Errors

StatusMeaningWhat to do
400Missing or invalid parameter, or eBay rejected the search as too broad.Fix the request or narrow the terms.
401Missing or invalid API key.Check the X-API-Key header.
403Key expired, or the request was blocked by our firewall (no User-Agent).Contact us, or set a User-Agent header.
429Daily limit reached, or too many requests at once.Wait, or lower your concurrency.
503Temporary problem on our side.Retry after a second or two.

Failed searches do not count towards your daily limit. Every error body is JSON with "ok": false and an error message.

Limits

Your daily limit, how many requests you can run at the same time, and your expiry are set on your key and listed in the email it came with; /v1/usage always shows them. Trial keys run 72 hours from your first search.

About the data

OpenAPI / Postman

Import https://api.compsapi.com/openapi.json into Postman, Insomnia or any OpenAPI tool to get every endpoint ready to call. Set your key as the X-API-Key header.

Questions, or something you need added: reply to the email your key came with.