Sold Comps API Docs

v1 · base URL https://api.soldcomps.io/v1 · JSON over HTTPS · Bearer auth

Quickstart

  1. Create a free account and copy your key (sh_live_…).
  2. Send one GET request to /v1/sold with a keyword. That's the whole API.
  3. Read stats.median for a price, or loop over items for the raw sales.
curl
curl "https://api.soldcomps.io/v1/sold?q=rolex+submariner&condition=used" \
  -H "Authorization: Bearer sh_live_xxxxxxxx"

GET/v1/sold

The only endpoint in the sold comps API. Returns up to 200 completed sales matching a keyword, newest first, plus summary stats. One call counts as one request whether it returns 3 sales or 200.

ParameterTypeDefaultNotes
qstringrequiredWhat you'd type in eBay's search box. Put exact phrases in quotes ("psa 10") and exclude words with a minus (-lot).
siteenumEBAY_USEBAY_US (ebay.com), EBAY_GB (ebay.co.uk) or EBAY_DE (ebay.de).
conditionenumanynew, open_box, refurbished, used or for_parts.
min_price / max_pricenumbernoneOnly sales in this price range, in the site's currency.
buying_formatenumanyauction or fixed_price (Buy It Now and Best Offer).
daysinteger90Look-back window, 1 to 90 days.

Response

200 OK application/json
{
  "query": "rolex submariner",
  "site": "EBAY_US",
  "window_days": 90,
  "count": 162,
  "stats": {
    "median": 9450.00, "p25": 8100.00, "p75": 11200.00,
    "min": 5200.00, "max": 16950.00, "excluded": 21, "currency": "USD"
  },
  "items": [
    {
      "item_id": "306123456789",
      "title": "Rolex Submariner Date 126610LN Black Ceramic 41mm Box & Papers 2023",
      "sold_price": { "value": 11450.00, "currency": "USD" },
      "shipping": { "value": 0, "currency": "USD" },
      "sold_at": "2026-10-22",
      "condition": "Pre-Owned",
      "buying_format": "fixed_price",
      "best_offer_accepted": false,
      "best_offer_price_known": true,
      "url": "https://www.ebay.com/itm/306123456789",
      "image": "https://i.ebayimg.com/images/g/.../s-l225.jpg",
      "flags": []
    }
  ]
}

Item fields

FieldTypeDescription
item_idstringeBay item number
titlestringListing title at the time of sale
sold_price.value / .currencynumber / stringSale price shown by eBay, e.g. 42.50 / "USD"
shipping.valuenumber | nullShipping the buyer paid. 0 = free shipping, null = not shown
sold_atstring (date)Day the item sold, YYYY-MM-DD
conditionstringeBay's condition label, e.g. "Pre-Owned", "Brand New", "New (Other)", "Parts Only"
buying_formatstringauction or fixed_price
best_offer_acceptedbooleantrue when the sale was an accepted Best Offer
best_offer_price_knownbooleanfalse when the accepted offer amount isn't shown; these sales are left out of stats
urlstringLink to the eBay listing
imagestring | nullListing photo URL
flagsstring[]Why a sale is left out of stats: lot, for_parts, box_only, replica, accessory, outlier. Empty = counted

How stats are computed

stats is computed only from sales with an empty flags array and a known price. excluded tells you how many were left out, and every sale is still in items so you can apply your own rules. More in median vs. average sold price.

FlagMeansExample title
lotSeveral items sold togetherN64 Console Bundle 8 Games · Pokemon cards x10
for_partsBroken, untested or for repairSuper Nintendo SNES ***For Parts or Repair***
box_onlyPackaging without the itemEmpty box only, no console
replicaDescribed as fake, replica or homage2 fake Rolex watches, props
accessoryA part or add-on far below the typical priceWatch box · bezel gasket for Rolex · card sleeves
outlierMore than 1.5× the interquartile range from the middleA $2,039 typo among $40 sales

Matching

eBay pads sold results with loose matches. We keep a sale only if every number in your query appears in the title as a whole number (“N64” matches64, “64GB” doesn't), quoted phrases appear exactly, and at least 80% of the other words appear. Minus words exclude a sale. Sales that don't match aren't returned or counted.

Examples

Python

sold.py
import requests

r = requests.get(
    "https://api.soldcomps.io/v1/sold",
    params={"q": "rolex submariner 126610ln", "condition": "used"},
    headers={"Authorization": "Bearer sh_live_xxxxxxxx"},
    timeout=30,
)
r.raise_for_status()
data = r.json()
print(data["count"], "sales, median", data["stats"]["median"])

JavaScript (Node 18+ / Deno / Bun)

sold.mjs
const url = new URL("https://api.soldcomps.io/v1/sold");
url.searchParams.set("q", "charizard 4/102 \"psa 9\"");
url.searchParams.set("buying_format", "auction");

const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.SALEHISTORY_KEY}` } });
if (!res.ok) throw new Error(`${res.status} ${(await res.json()).error.code}`);
const { count, stats, items } = await res.json();

Walkthroughs: eBay sold prices in Python · eBay sold comps in Google Sheets

Errors

Statuserror.codeMeaningCounts?
400invalid_paramBad or missing parameter; error.param names itNo
401unauthorizedMissing or revoked keyNo
402quota_exceededMonthly requests used up and no credits leftNo
429rate_limitedOver your per-minute limit; honor Retry-AfterNo
502upstream_unavailableeBay didn't answer cleanly; safe to retry with backoffNo

Failed requests are never billed. Every response carries X-Request-Id, X-Quota-Remaining and X-RateLimit-Remaining headers.

Rate limits & quotas

Limits are per key: Free 30/min, Starter 60/min, Growth 120/min, Scale 300/min. Monthly quotas reset on the 1st (UTC). When the quota runs out, prepaid credits are used automatically if you have them. See pricing.

Data notes

  • Each request returns up to 200 of the most recent matching sales from the last 90 days, newest first. For busy searches (like “pokemon card”) that may cover only the last day or two; add detail to the query to go further back for one item.
  • Prices are in the site's currency: USD on EBAY_US, GBP on EBAY_GB, EUR on EBAY_DE.
  • Some accepted Best Offer prices are hidden by eBay. Those items carry best_offer_price_known: false, show the list price, and are left out of stats.
  • You never send us an eBay login or cookie. If eBay blocks a fetch we return 502 upstream_unavailable, never an empty 200.
  • SaleHistory is independent and not affiliated with eBay.