CompSniper
API Reference

One endpoint for real eBay sold prices

Everything you need to integrate CompSniper: authentication, limits, error handling, and the complete 26-field response schema. Every route is a single GET request that returns clean JSON. No OAuth, no XML, no SDK required.

Base URLhttps://api.compsniper.comVersioned under /v1
Introduction

Overview

CompSniper turns any keyword into up to 240 completed eBay sales in a single request. Each listing carries the sold price, sale date, condition, shipping, and seller reputation across 26 fields of real transaction data, not estimates or asking prices.

All requests go to https://api.compsniper.com and are versioned under /v1. Responses are always JSON. Prices are returned as decimal strings to avoid floating-point rounding.

Quickstart

Pull the last 10 sold iPhone 15 Pro listings. Swap in your key and you are done. Pick your language:

curl -H "Authorization: Bearer cs_YOUR_KEY_HERE" \
  "https://api.compsniper.com/v1/scrape?keyword=iphone+15+pro&count=10"

8 marketplaces

US, UK, DE, FR, IT, ES, CA, AU

240 items / request

One page per call, up to 240 listings each.

90 days of history

The completed-sales window eBay exposes.

Introduction

Authentication

Every request is authenticated with a bearer token. Send your key in the Authorization header. CompSniper keys always start with cs_ and are created in your dashboard.

The free Basic plan includes 100 requests per month with no credit card. Treat your key like a password: it grants full access to your quota, so keep it server-side and never commit it to a public repository.

Authenticated request
curl -H "Authorization: Bearer cs_live_9f2c...a71b" \
  "https://api.compsniper.com/v1/scrape?keyword=stanley+tumbler"

Where do keys come from?

Create a free account to get an instant key, then rotate or revoke it anytime from the dashboard. Requests without a valid key return 401 unauthorized.

Introduction

Rate limits

Two independent limits apply to every key. The first is a per-minute rate limit (60 requests per minute on standard plans). The second is your monthly request quota, set by your plan. Hitting either one returns 429, but with a different code so you can tell them apart.

Exceeding the per-minute limit returns rate_limited and is temporary: retry after the Retry-After header (in seconds). Exhausting your monthly quota returns quota_exceeded and blocks further requests until your billing cycle resets.

Rate and usage headers ship on every response (including successful ones), so you can meter without waiting for a 429:

Response headers
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1765843200
X-Usage-Limit: 10000
X-Usage-Remaining: 8412
X-RateLimit-Limit / -Remaining

Requests allowed and left in the current per-minute window.

X-RateLimit-Reset

Unix epoch (seconds) when the per-minute window resets.

X-Usage-Limit / -Remaining

Requests allowed and left in your monthly plan quota.

Retry-After

Seconds to wait before retrying. Present on 429 responses.

Introduction

Errors

CompSniper uses conventional HTTP status codes. Every error body is JSON with a human-readable error string and a stable machine-readable code. Rate and quota errors add retry_after or reset_at so you know when to try again.

StatusCodeMeaningWhat to do
400invalid_paramsA query parameter is missing or malformed.Check the parameter table below. Most often keyword is missing or count is outside 1-240.
401unauthorizedThe API key is missing, malformed, or revoked.Send a valid Authorization: Bearer header. Keys start with cs_ and live in your dashboard.
429rate_limitedYou exceeded your per-minute request limit.Back off and retry after the Retry-After header (seconds). Standard plans allow 60 requests per minute.
429quota_exceededYou used every request in your monthly plan.Wait for the reset_at date or upgrade your plan. This limit is independent of the per-minute limit.
500server_errorAn unexpected error occurred on our side.Retry with backoff. If it persists, email support@compsniper.com.
502upstream_blockedeBay blocked or refused the upstream fetch.Transient. Retry with backoff. We rotate infrastructure automatically, so most retries succeed.
503server_busyConcurrency limit reached for your key.Reduce parallel requests and retry after a short pause.

429 · rate_limited

Error · JSON
{
  "error": "Rate limit exceeded. Retry after 12 seconds.",
  "code": "rate_limited",
  "retry_after": 12
}

429 · quota_exceeded

Error · JSON
{
  "error": "Monthly request quota exceeded. Resets 2026-09-01.",
  "code": "quota_exceeded",
  "reset_at": "2026-09-01T00: 00: 00.000Z"
}
Introduction

Pagination

Walk through results with the page parameter, starting at 1. Each response reports whether more pages exist via hasNextPage. Keep incrementing page until it is false. Each page you fetch debits one request from your quota.

Do not confuse the two count fields. totalItems is the number of listings on the current page (up to 240), while totalResults is eBay’s own reported match count as a string (for example "14,000+"), and is null when eBay does not report one.

Page 2 · JSON
{
  "keyword": "iphone 15 pro",
  "page": 2,
  "totalItems": 240,
  "totalResults": "14,000+",
  "hasNextPage": true,
  "autoSelectedCategory": { "id": "9355", "name": "Cell Phones & Smartphones" },
  "items": [ /* ... */ ]
}
eBay

Keyword sold search

The core endpoint. Pass a keyword and get back completed eBay sales. Every other parameter is optional and maps directly to an eBay search filter, so you can narrow 240 results down to exactly the comps you need.

GET/v1/scrape

Query parameters

keywordstring·required
Search terms, exactly as you would type them into eBay. Supports the eBay minus-sign exclusion (for example: iphone 15 -case) to drop unwanted results.
pageinteger·1
Result page to return. Combine with hasNextPage to walk through the full result set.
countinteger·240
Number of listings to return, from 1 to 240. One request returns up to one page regardless of count.
ebaySiteenum·ebay.com
Which of the 8 eBay marketplaces to search. One of ebay.com, ebay.co.uk, ebay.de, ebay.fr, ebay.it, ebay.es, ebay.ca, ebay.com.au.
categoryIdstring·0
eBay category id (the _sacat value). 0 searches all categories. Browse the full list of 17,000+ ids at /ebay-categories.
sortOrderenum·endedRecently
Result ordering. One of endedRecently, timeNewlyListed, pricePlusPostageLowest, pricePlusPostageHighest, distanceNearest.
minPricenumber·null
Lower bound on total price (item plus shipping), in the marketplace currency.
maxPricenumber·null
Upper bound on total price (item plus shipping), in the marketplace currency.
itemLocationenum·default
Seller location filter. One of default, domestic, worldwide.
itemConditionenum·any
High-level condition filter. One of any, new, used.
conditionIdinteger·null
Numeric eBay condition id (for example 1000 for New, 3000 for Used). Overrides itemCondition when set.
buyingFormatenum·all
Listing format filter. One of all, auction, buyItNow, acceptsOffers.
sellerTypeenum·null
Filter by private or business sellers. Available on EU marketplaces only.
includeCompleteListingboolean·true
When true, restricts to completed listings (LH_Complete=1) and enables the bestOfferAccepted signal on each item.
soldboolean·true
When true, returns completed sales. Set false to return currently active listings (swaps the sold fields for the active fields).
soldAfterstring·null
Keep only sales on or after this date (YYYY-MM-DD). Applied as a post-parse filter, so scrapedCount appears in the envelope.
soldBeforestring·null
Keep only sales on or before this date (YYYY-MM-DD). Applied as a post-parse filter.
aspectFilterstring·null
URL-encoded JSON of eBay sidebar facet names (for example brand or storage size) to narrow results the way the eBay left rail does.

Response envelope

The top-level object wraps the result set with pagination metadata and eBay’s auto-selected category. Listings live in the items array.

Response · JSON
{
  "keyword": "iphone 15 pro",
  "page": 1,
  "totalItems": 240,
  "totalResults": "14,000+",
  "hasNextPage": true,
  "autoSelectedCategory": {
    "id": "9355",
    "name": "Cell Phones & Smartphones"
  },
  "items": [
    {
      "itemId": "256123456789",
      "url": "https://www.ebay.com/itm/256123456789?nordt=true",
      "thumbnailUrl": "https://i.ebayimg.com/images/g/3nkAAeSw/s-l500.webp",
      "epid": "20049285656",
      "title": "Apple iPhone 15 Pro 256GB Natural Titanium - Unlocked",
      "condition": "Pre-Owned",
      "conditionId": 3000,
      "buyingFormat": "buyItNow",
      "bestOfferAccepted": false,
      "bidCount": null,
      "categoryId": "9355",
      "listingType": "sold",
      "endedAt": "2026-03-10",
      "soldPrice": "899.99",
      "soldCurrency": "USD",
      "shippingPrice": "0.00",
      "shippingCurrency": "USD",
      "shippingType": "free",
      "totalPrice": "899.99",
      "sellerUsername": "top-deals-store",
      "sellerPositivePercent": 99.8,
      "sellerFeedbackScore": 14200,
      "itemLocation": "United States",
      "scrapedAt": "2026-03-14T21: 00: 00.000Z"
    }
    // ... 239 more items
  ]
}
keywordThe keyword you searched, echoed back.
pageThe page number returned.
totalItemsListings on this page (up to 240).
totalResultseBay’s reported match count as a string, or null.
hasNextPageWhether another page is available.
autoSelectedCategoryThe category eBay auto-picked, or null.
scrapedCountPresent only when date-filtering with soldAfter or soldBefore.
itemsArray of listing objects (schema below).

Item schema (26 fields, sold mode)

Each object in items when sold=true (the default). Prices are decimal strings. On Best Offer sales, soldPrice is an upper bound because eBay never discloses the accepted offer amount.

itemIdstring
eBay item id.
urlstring
Canonical listing URL (appends ?nordt=true).
thumbnailUrlstring | null
Standard resolution image (s-l500).
fullResThumbnailUrlstring | null
Full resolution image (s-l1600).
epidstring | null
eBay product identifier, when the listing is catalog-matched.
titlestring | null
Listing title as shown on eBay.
conditionstring | null
Localized condition label (for example Pre-Owned).
conditionIdnumber | null
Numeric eBay condition id.
sellerTypestring | null
private or business (EU marketplaces).
buyingFormatstring | null
auction, buyItNow, auctionWithBIN, or null.
bestOfferAcceptedboolean
True when the sale closed via an accepted Best Offer.
bidCountnumber | null
Number of bids (auctions only).
categoryIdstring | null
eBay category id the listing sold under.
listingTypestring
sold or active.
shippingPricestring | null
Shipping cost as a decimal string.
shippingCurrencystring | null
ISO 4217 currency for shipping.
shippingTypestring | null
free, paid, pickup, or unknown.
totalPricestring | null
Sold price plus shipping, as a decimal string.
sellerUsernamestring | null
Seller handle.
sellerPositivePercentnumber | null
Seller positive feedback percentage.
sellerFeedbackScorenumber | null
Seller total feedback score.
itemLocationstring | null
Seller location. Null when domestic to the marketplace.
scrapedAtstring
ISO 8601 timestamp of when the data was fetched.
endedAtstring | null
Sale date (YYYY-MM-DD).
soldPricestring | null
Sale price as a decimal string. On Best Offer sales this is an upper bound.
soldCurrencystring | null
ISO 4217 currency for the sale price.

Active mode (sold=false)

Set sold=false to return currently active listings instead. The shared fields stay the same, but the sold fields (endedAt, soldPrice, soldCurrency) are replaced by these:

currentPricestring | null
Current asking price (or lower bound of a range).
currentPriceMaxstring | null
Upper bound when the listing shows a price range.
currentCurrencystring | null
ISO 4217 currency for the current price.
watcherCountnumber | null
Number of watchers on the listing.
unitsSoldnumber | null
Units already sold on a multi-quantity listing.
acceptsOffersboolean
True when the listing accepts Best Offers.
timeLeftstring | null
Raw localized time-remaining string from eBay.
eBay

Category browse

Browse an entire eBay category without a keyword. Same request shape and same response envelope as /v1/scrape, except categoryId is required and keyword is omitted. Every other filter (minPrice, itemCondition, sortOrder, and the rest) works identically.

Find category ids at /ebay-categories, which lists all 17,000+ of them.

GET/v1/scrape/category
Terminal
curl -H "Authorization: Bearer cs_YOUR_KEY_HERE" \
  "https://api.compsniper.com/v1/scrape/category?categoryId=9355&count=100"

Required parameter

categoryId (string) is required. All other parameters from the GET /v1/scrape table are supported, with the exception of keyword.

More

Max Mode & RapidAPI

Max Mode (async sweeps)

For large pulls, Max Mode runs server-side pagination as a background job so you do not have to loop through pages yourself. Submit once, poll for progress, then read the items inline or download a CSV. Each scraped page debits one request from your quota. One job runs at a time per account (a second submit returns 409 with the active job). Pass maxPages (up to 100) to cap it.

  • POST /v1/scrape/max — enqueue, returns jobId
  • GET /v1/scrape/max/results/:jobId — poll (5s); terminal: done / maxPages_reached / cancelled / failed
  • DELETE /v1/scrape/max/:jobId — cancel
  • GET /v1/scrape/max/:jobId/download.csv?token= — signed CSV

RapidAPI channel

Prefer to bill through RapidAPI? The same engine is available there with an identical response shape. Instead of the bearer token, authenticate with X-RapidAPI-Key and X-RapidAPI-Host. Everything else in this reference applies unchanged.

Machine-readable spec

A full OpenAPI document is available at https://api.compsniper.com/openapi.json for generating typed clients.