CompSniper Docs

3-Year eBay Sold History API

Search up to 3 years of eBay sold history by keyword with GET /v1/research/sold, on every CompSniper plan including free.

GET /v1/research/sold returns eBay sold history going back up to 3 years, across all eight eBay sites, with the same API key you already use for /v1/scrape. It is available on every plan, including free.

Use it when 90 days is not enough: slow-moving items, seasonal trends, price changes after a release, or a sale you remember from last year. For the most recent individual sales with full listing fields and AI cleanup, keep using /v1/scrape.

How far back it goes

Up to 3 years before today. Any startDate from 3 years ago up to today works.

Make a request

curl --fail-with-body \
  -H "Authorization: Bearer cs_live_REPLACEWITHYOURKEY" \
  "https://api.compsniper.com/v1/research/sold?keyword=nintendo+switch+oled&startDate=2023-10-11&endDate=2026-10-10&sort=lastSoldDescending&limit=50"
Python
import requests

response = requests.get(
    "https://api.compsniper.com/v1/research/sold",
    headers={"Authorization": "Bearer cs_live_REPLACEWITHYOURKEY"},
    params={
        "keyword": "nintendo switch oled",
        "startDate": "2023-10-11",
        "endDate": "2026-10-10",
        "sort": "lastSoldDescending",
        "limit": 50,
    },
    timeout=60,
)
response.raise_for_status()
data = response.json()
for row in data["results"]:
    print(row["lastSoldDate"], row["soldUnits"], row["averageSoldPrice"]["amount"], row["title"])

Parameters

ParameterValuesDefault
keyword1 to 200 charactersRequired
startDateYYYY-MM-DD, no earlier than 3 years before todayRequired
endDateYYYY-MM-DD, on or after startDate, no later than today (UTC)Required
ebaySiteebay.com, ebay.co.uk, ebay.com.au, ebay.ca, ebay.de, ebay.fr, ebay.it, ebay.esebay.com
sortlastSoldDescending (newest sale first) or quantityAscending (eBay's units-sold order)quantityAscending
limit10, 20, or 50 rows per page50
page1 to 2001
singleUnitOnlytrue returns only listings that sold exactly one unitfalse
relevancetrue removes rows that are not the searched product (see Cleanup)false

Unknown or repeated parameters are rejected with 400 invalid_params, so a typo never silently changes your results.

Response

Response (shortened)
{
  "source": "ebay_product_research",
  "ebaySite": "ebay.com",
  "displayCurrency": "USD",
  "startDate": "2023-10-11",
  "endDate": "2026-10-10",
  "page": 1,
  "limit": 50,
  "sourceResultCount": 50,
  "resultCount": 50,
  "hasNextPage": true,
  "nextPage": 2,
  "relevanceApplied": false,
  "totals": {
    "totalSold": 491,
    "totalSellers": 147,
    "averageSoldPrice": { "amount": "382.74", "currency": "USD", "display": "$ 382.74" },
    "minSoldPrice": { "amount": "24.99", "currency": "USD", "display": "$ 24.99" },
    "maxSoldPrice": { "amount": "10500.00", "currency": "USD", "display": "$ 10,500.00" },
    "averageShipping": { "amount": "18.53", "currency": "USD", "display": "$ 18.53" },
    "freeShippingPercent": "43",
    "sellThroughPercent": "28.86",
    "totalSales": { "amount": "187925.34", "currency": "USD", "display": "$ 187,925.34" }
  },
  "warnings": [
    "Listing-level records, not a transaction feed. Multi-unit rows contain averages.",
    "USD is the research display currency, not necessarily the listing's original currency.",
    "Older listing titles, links, images and conditions may be unavailable."
  ],
  "results": [
    {
      "itemId": "267809186741",
      "title": "Nintendo Switch OLED Console White Joy-Con Dock AC Adapter + 2 Games Included!",
      "itemUrl": "https://www.ebay.com/itm/267809186741",
      "imageUrl": "https://i.ebayimg.com/images/g/L3IAAeSwLcZqyUSi/s-l1200.png",
      "recordType": "single_unit_listing",
      "soldUnits": 1,
      "averageSoldPrice": { "amount": "184.00", "currency": "USD", "display": "$ 184.00" },
      "totalSales": { "amount": "184.00", "currency": "USD", "display": "$ 184.00" },
      "averageShipping": { "amount": "10.00", "currency": "USD", "display": "$ 10.00" },
      "soldPrice": { "amount": "184.00", "currency": "USD", "display": "$ 184.00" },
      "soldDate": "2026-10-09",
      "lastSoldDate": "2026-10-09",
      "listingFormat": "Fixed price",
      "condition": null
    }
  ],
  "requestId": "20fca48c-c1d6-4096-8f39-73a65d1cb9af"
}

Rows are listings, not single transactions

Each row is one eBay listing and everything it sold inside your date range:

  • recordType: "single_unit_listing": the listing sold one unit. soldPrice and soldDate are that sale.
  • recordType: "listing_aggregate": the listing sold several units (common for multi-quantity fixed-price listings). soldUnits is how many, averageSoldPrice and totalSales describe them, lastSoldDate is the most recent one, and soldPrice and soldDate are null.

Use singleUnitOnly=true when you want one-off sales only, for example graded cards or used electronics.

Other things to know

  • Prices are always USD, on every eBay site.
  • Cleanup is opt-in. By default rows are eBay's results for your keyword exactly as listed, so accessories, other graders and lots can appear (relevanceApplied: false). Add relevance=true to clean them.
  • Condition is not available in this data (condition is null). Older listings can also be missing a title, link, or image.

Cleanup

Add relevance=true to remove rows that are not the product you searched for: accessories, parts, lots and bundles, other models, and, for graded cards, other graders or grades and ungraded "PSA 10 candidate" copies. It uses the same cleanup as the standard sold search, then drops prices far from the cleaned median. The response then has relevanceApplied: true and rawResultCount (rows before cleanup). It still costs one request per page and adds about a second.

curl -H "Authorization: Bearer cs_live_REPLACEWITHYOURKEY" \
  "https://api.compsniper.com/v1/research/sold?keyword=charizard+4+celebrations+psa+10&startDate=2023-10-15&endDate=2026-10-14&sort=lastSoldDescending&relevance=true"

In a test on October 14, 2026, the newest 50 rows for that search went from a $25 to $20,000 price range (CGC and SGC slabs, raw copies, reprints, lots) to 24 PSA 10 copies between $387 and $551. For "nintendo switch oled" the page median went from $31 (cases and accessories) to $180.

If cleanup is ever unavailable, the request still succeeds with uncleaned rows, relevanceApplied: false and a warning, so your code can tell the difference.

Getting more results

Most empty or short answers come from the request, not from missing data. Check these three things first.

1. Keep the keyword short. eBay's research search only returns listings whose title contains every word you send. A whole listing title, or extra words like a color, a seller note or a location, usually matches nothing.

Returns little or nothingWorks
CyberPower PDU81001G switched metered by outlet PDU 8 outlet 1U (0)CyberPower PDU81001 (12)
TOTO SW4724AT40 S7A round (0)TOTO WASHLET S7A (50 on page 1)
prada sunglasses tortoiseshell. there are some scratch marks on lenses (0)prada sunglasses spr 16y (2 in Australia over 3 years)

Start with brand plus model or set number, then add one word at a time if the results are too broad. If a long search returns 0, retry it shorter before treating the item as unsold.

2. Widen the dates. A few days of history often holds only a handful of sales, or none. The same One Piece card code returned 13 rows for the last 30 days and a full page of 50 for the last 90 days. Use the full 3 years when you are pricing something rare.

3. Ask for the next page. One page holds at most 50 rows. A resultCount of exactly 50 with hasNextPage: true means there is more: send the same request with page=2, page=3 and so on (see Pagination).

totals describes the whole search for your date range, not just the current page, and is the same on every page. It is null when the search has no sales.

  • totalSold: units sold across every row. Each row is at least one sold unit, so the number of rows is never higher than totalSold. Pages needed are at most totalSold divided by your limit, rounded up. One call to page 1 is enough to size a backfill.
  • totalSellers, averageSoldPrice, minSoldPrice, maxSoldPrice, averageShipping and totalSales cover the same window. Percent fields (freeShippingPercent, sellThroughPercent) are strings such as "28.86".
  • Totals are for eBay's full result set before relevance=true cleanup or singleUnitOnly. Any value that is not available comes back as null.

The exact number of rows is not available, so totalSold is an upper bound, not an exact page count.

Pagination

Each page holds up to 50 rows. Follow nextPage while hasNextPage is true, up to page 200 (10,000 rows for one search). Each page is a separate request.

Billing and limits

  • One page = one request from your normal monthly allowance (or purchased credits). There is no separate plan.
  • Failed requests are free. A timeout, upstream error, or cancelled request is never charged.
  • History has its own per-minute cap: 20 searches per minute per account, in addition to your plan's normal per-minute limit. Every response carries X-History-RateLimit-Limit and X-History-RateLimit-Remaining. Need more? Contact support.

Errors

StatusCodeMeaningWhat to do
400invalid_paramsMissing keyword, bad date, date older than 3 years, unknown parameterFix the request; do not retry as is
429history_rate_limitedMore than your history searches per minuteWait for Retry-After, then retry
429rate_limitedYour plan's per-minute limitWait for Retry-After, then retry
429quota_exceededMonthly allowance and credits used upUpgrade, buy credits, or wait for reset
502, 503historical_unavailableeBay's research source did not answer this timeRetry after a few seconds, with a bound

All error bodies include code, error, and requestId. See Errors and Rate limits for the shared rules.

On this page