SoldCompsdocs

Docs update in progress

We recently updated the API to adapt to changes on eBay, and some details on this page may be out of date while we revise it. Questions? Email [email protected].

API Reference · v1

SoldComps API

Real sold listings — price, condition, date, seller — from a single request. No scraping setup, no stale cache, no OAuth dance. eBay endpoints: /v1/scrape for one page at a time, async Max Mode for server-side pagination. Plus Mercari and Poshmark sold listings.

Machine-readable spec: openapi.json

New to eBay sold data? See how we compare →

Quickstart

curl -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  "https://api.sold-comps.com/v1/scrape?keyword=iphone+15+pro&count=60"

Authentication

All requests to the SoldComps API — /v1/scrape, /v1/scrape/category, and Max Mode — require a bearer token, with one exception (the RapidAPI channel, below):

Authorization: Bearer sc_YOUR_KEY_HERE

API keys start with sc_. Get one from the dashboard. The free plan includes 100 requests/month, no credit card required.

The /rapidapi/scrape-ebay endpoint authenticates through the RapidAPI marketplace headers instead — see the RapidAPI section.

Optional

Authenticated requests

Optionally forward your own eBay session cookies on /v1/scrape, /v1/scrape/category, /v1/scrape/max, /api/bulk-search, and /rapidapi/scrape-ebay via the X-eBay-Cookies header.

How to get your cookies

  1. Sign in to eBay in your browser, on the same marketplace you plan to query. A cookie from ebay.com will not work for an ebay.co.uk request.
  2. Open developer tools (F12, or Cmd + Option + I on Mac) and switch to the Network tab.
  3. Reload the page, then click the first document request to ebay.com in the list.
  4. Under Request Headers, find the cookie header and copy the entire value — a long string of name=value pairs separated by semicolons.
  5. Send that string as the X-eBay-Cookies header on your request. No encoding needed — paste it as-is.

Example

curl -H "Authorization: Bearer sc_YOUR_KEY" \
     -H "X-eBay-Cookies: nonsession=BAQ...; ebaysid=p2...; dp1=bu1p/QEBf..." \
     "https://api.sold-comps.com/v1/scrape?keyword=iphone"

The header is optional — every endpoint works without it. Cookies you send are used only to run your requests, and are ignored for active-listing searches (sold=false).

If eBay keeps rejecting your cookies (several blocked requests in a row), the API returns 400 with code: "cookies_expired" for requests that include the header, for up to 24 hours. Refresh your cookies (or omit the header) and retry.

Pacing matters

Cookie-authenticated requests are more sensitive to request rate than standard requests. eBay associates your session cookie with a single browsing identity — rapid-fire requests from that identity trigger bot detection and block the session. Space cookie requests at least 2-3 seconds apart. Hammering at sub-second intervals will burn the session and result in high block rates.

Note: Use cookies from the same eBay site you are scraping — e.g. an ebay.co.uk request needs cookies from a UK eBay account logged into ebay.co.uk.

Rate limits

Two independent limits apply, scoped per account (one shared budget across all API keys on the account). Both return 429, but the body's code field tells you which one was hit.

Per-minute rate limit (code: "rate_limited") — scales with your plan. Standard plans (free, starter, growth, scale) get 60 requests/minute; mid-tier custom plans (100k–500k) get 120 requests/minute; and high-volume custom plans (1M, 2M, 4M) get 240 requests/minute. A purchasable rate-limit add-on raises any key to 500 requests/minute.

Monthly quota (code: "quota_exceeded") — enforced separately from the per-minute bucket, reset at your billing cycle anchor (not calendar UTC). If you have purchased credits, they kick in automatically when your subscription quota runs out — the 429 only fires when both are exhausted. See current plan limits at /dashboard/subscription.

Every 429 carries a Retry-After header (seconds). Rate-limit responses also set X-RateLimit-* headers; quota responses set X-Usage-* headers — the same families present on a 200. These numbers are also available without spending a request from GET /usage. X-RateLimit-Reset is a Unix epoch timestamp (seconds since 1970-01-01 UTC) marking when the current rate-limit window resets.

Handling 429s

if response.status == 429:
  if body.code == "quota_exceeded":
    stop retrying, alert ops, wait until body.reset_at
  else:
    wait body.retry_after seconds, then retry

Optional

Credits (pay-as-you-go)

Buy one-time API request credits at $3 per 1,000 requests — no subscription required. Credits never expire and work on any plan, including free. Purchase from the dashboard in any amount from 100 to 1,000,000 per purchase.

Automatic overflow. By default, requests debit your subscription quota first. When your monthly quota runs out, purchased credits are consumed automatically — no code change needed. The 429 quota_exceeded response only fires when both subscription quota and credits are exhausted.

Credit-only mode. To skip your subscription quota entirely and pay exclusively from credits, pass the X-Credit-Source header:

curl -H "Authorization: Bearer sc_YOUR_KEY" \
     -H "X-Credit-Source: credits" \
     "https://api.sold-comps.com/v1/scrape?keyword=iphone"

Subscription-only mode. To enforce a hard budget and never touch purchased credits — useful for scheduled batch jobs that should stop cleanly when the monthly allowance runs out — pass X-Credit-Source: subscription-only. Requests return 429 quota_exceeded as soon as the monthly cap is hit, with no credit fallback.

Refunds on failure. Credits are reserved before the scrape runs. If the request fails (any non-200 response), the credit is refunded automatically — you only pay for successful scrapes.

When credits are used, the response includes X-Credit-Source: credits and X-Credit-Balance: <n> headers so your integration can track the remaining balance.

Errors

StatusMeaningWhat to do
400Invalid paramsCheck the error body — usually a missing keyword or out-of-range number.
401Missing or invalid API keyVerify the Authorization header. Keys start with sc_.
429 (code: rate_limited)Per-minute rate limitBack off for the duration in Retry-After (seconds), then retry. Limits are 60/min on standard plans, 120/min on mid-tier custom (100k–500k), and 240/min on high-volume custom (1M/2M/4M); the rate-limit add-on raises any key to 500/min.
429 (code: quota_exceeded)Monthly quota exhaustedStop retrying — Retry-After can be days long. Upgrade or wait until reset_at / your next billing cycle. Resets follow your subscription anchor, not calendar UTC.
503 (code: upstream_blocked)Marketplace fetch failedThe marketplace blocked or failed the request. Transient — retry after a few seconds. Not charged on direct plans.
503 (code: at_capacity)Temporarily at capacityRetry shortly. Not charged on direct plans.
500Server errorUnexpected internal error. Retry with exponential backoff.

Pagination

Each /v1/scrape request returns one page of sold listings (up to 240 items). Increment the page parameter until hasNextPage is false.

eBay caps how deep a search goes. If you request a page past the last one, you get a 200 with an empty items array, hasNextPage: false, code: "past_last_page", a message, and lastPage (also sent as the X-Past-Last-Page header). The request still counts as 1 request, because the page is fetched before we know it's past the end.

Running the pagination loop client-side is fine for small sweeps. For larger jobs (50+ pages), use Max Mode instead — the server paginates, handles retries, and delivers results inline, via email, or as a signed CSV.

totalItems in the response is the count of items returned on the current page, not a grand total. It can also be lower than the count you requested — count is a page size (60, 120 or 240; other values round up), and items eBay renders without a parseable price or sold date are dropped.

totalResults is different — it's eBay's own reported total result count for your search query (e.g. "14,000+"), independent of pagination. It's a string because eBay's counts are approximate on broad searches. null when unavailable.

# Increment page until hasNextPage is false
curl -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  "https://api.sold-comps.com/v1/scrape?keyword=iphone+15+pro&page=1"
# then page=2, page=3, ... while hasNextPage == true
GET/v1/scrape

Search sold listings

One keyword search returns up to 240 real completed eBay sales. Filters narrow by site, category, price range, condition, and seller type.

Query parameters

Note: the buyingFormat query parameter (below) filters which listings are returned by format. It shares a name with the buyingFormat field on each item in the response, which instead classifies how that listing was actually listed. The two use different enums and serve different purposes.

keywordstringrequired
Passed directly to eBay's search bar. Supports eBay's minus-sign syntax to exclude terms — e.g. "iphone 15 pro -case -screen -lot" drops listings containing case, screen, or lot from results.
pageintegeroptionaldefault: 1
Page number of eBay results to fetch. Increment until hasNextPage is false.
countinteger (60, 120, 240)optionaldefault: 240
Items per page: 60, 120 or 240, for sold and active listings (sold=false). Other values are rounded up to the next size, so a request can return more items than count. Each page is one full eBay results page — the last page may contain fewer items.
ebaySiteenumoptionaldefault: ebay.com
eBay domain to scrape.
ebay.comebay.co.ukebay.deebay.frebay.itebay.esebay.caebay.com.au
categoryIdstringoptionaldefault: 0
eBay category ID (_sacat). Browse all 17,000+ IDs at sold-comps.com/ebay-categories. Use "0" for all categories.
sortOrderenumoptionaldefault: endedRecently
Sort order for results.
endedRecentlytimeNewlyListedpricePlusPostageLowestpricePlusPostageHighestdistanceNearest
minPricenumberoptional
Minimum price filter, in listing currency.
maxPricenumberoptional
Maximum price filter, in listing currency.
itemLocationenumoptionaldefault: default
Item location filter.
defaultdomesticworldwide
itemConditionenumoptionaldefault: any
Item condition filter applied as a request filter on eBay.
anynewused
conditionIdnumberoptional
eBay numeric condition ID filter. Common IDs: 3 (New), 4 (Used), 1000 (Brand New), 1500 (Open box), 2750 (Like New), 3000 (Used), 7000 (For parts). Valid IDs vary by eBay category. When set, overrides itemCondition. When omitted, no condition filter is applied.
buyingFormatenumoptionaldefault: all
Filter by listing format (request filter — distinct from the per-item buyingFormat response field, which classifies how a listing was actually listed and uses a different enum). "auction" = auction-only, "buyItNow" = fixed-price / Buy It Now, "acceptsOffers" = listings with Best Offer enabled. Default "all" (no format filter).
allauctionbuyItNowacceptsOffers
sellerTypeenumoptional
Filter results by seller type. Only effective on EU sites (ebay.de, .fr, .it, .es). On non-EU sites the filter is silently ignored.
privatebusiness
includeCompleteListingbooleanoptionaldefault: true
Include eBay completed-listing metadata (LH_Complete=1). This is what enables accurate bestOfferAccepted detection — without it, eBay does not render the "Best offer accepted" signal and bestOfferAccepted is false for nearly all items. Does not change which listings are returned: results stay sold-only (LH_Sold=1 takes precedence). Set to false only to match pre-July-2026 behavior.
soldbooleanoptionaldefault: true
When true (default), returns completed/sold listings. When false, returns ACTIVE (currently-listed) results instead. Active responses swap the sold-only fields (soldPrice, soldCurrency, endedAt, bestOfferAccepted) for active-only ones: listingType="active", the asking price in currentPrice/currentPriceMax/currentCurrency, plus watcherCount, unitsSold, acceptsOffers, and timeLeft.
soldAfterstring (YYYY-MM-DD)optional
Inclusive lower bound on endedAt. Applied after the page is scraped — sold-only, silently ignored when sold=false. See scrapedCount in the response for how to tell whether more pages will help.
soldBeforestring (YYYY-MM-DD)optional
Inclusive upper bound on endedAt. Applied after the page is scraped — sold-only, silently ignored when sold=false.
aspectFilterstring (JSON)optional
JSON object of eBay item-aspect facet filters — your HTTP client handles URL encoding automatically. Keys and values are the human-readable facet names exactly as shown in eBay's sidebar refinements (e.g. {"Brand":"Apple","Storage Capacity":"256 GB"}). Multi-select values use pipe as separator: {"Network":"Unlocked|AT&T"}. Facet names are dynamic per eBay category and vary by site language. Invalid or unrecognized facets are silently ignored by eBay.
exactMatchbooleanoptionaldefault: true
When true (default), strips eBay's loosened-match results ("Results matching fewer words") so only items closely matching your keyword are returned. Set to false to include all results eBay returns — useful when you want maximum volume over keyword precision.
hydrateBoabooleanoptionaldefault: false
When true, items sold via Best Offer have their soldPrice updated to the actual accepted offer amount using eBay's Price Guide. Primarily useful for trading card categories where Best Offer is common (~50% hit rate on ebay.com cards). Non-card categories silently skip hydration. eBay has Price Guide data only for items listed on ebay.com, ebay.co.uk and ebay.de. On an ebay.co.uk or ebay.de search, items listed on that site get the accepted amount in the listing currency; on every site, items listed on ebay.com get it in USD. When the hydrated price is in a different currency than the listing, boaAcceptedPrice and boaAcceptedCurrency are returned instead of overwriting soldPrice. Sold-only; ignored when sold=false. Costs 1 extra request against your quota, but only when hydration actually finds at least one match — a miss (or a keyword with no Best Offer items) costs nothing extra.
Date range filtering is post-processing. Each request still scrapes one full page from eBay (up to count items), then filters by endedAt using soldAfter/soldBefore. A page may return fewer items than count after filtering, and hasNextPage still reflects eBay's pagination, not the filtered set — a next page may exist but return 0 items after filtering. To pull every sold item in a date range, paginate until hasNextPage is false, or until scrapedCount is lower than the page size (you've reached the end of eBay's results).
Best Offer price hydration costs 1 extra request. With hydrateBoa=true, a successful hydration (at least one item's accepted offer price resolved) debits 1 additional request from your quota — at most 1 extra per request, regardless of how many items were hydrated. If no Best Offer items are found, or all hydration attempts miss, no extra request is charged. Primarily useful for trading card categories.
Aspect filters narrow by eBay sidebar facets. Pass aspectFilter as a JSON object whose keys and values match the facet names in eBay's sidebar refinements. Your HTTP client handles the URL encoding automatically.
aspectFilter={"Brand":"Apple","Storage Capacity":"256 GB"}

For trading cards, filter by grade and card manufacturer:

aspectFilter={"Professional Grader":"PSA","Grade":"10","Manufacturer":"Topps"}

Multi-select values use pipe: {"Grade":"9|10"}. Facet names are dynamic per category and vary by site language. Unrecognized facets are silently ignored by eBay.

Response fields (each item)

itemIdstring
eBay listing item ID.
urlstring
Canonical listing URL with ?nordt=true to bypass eBay's catalog redirect.
thumbnailUrlstring | null
Listing thumbnail (500px) from i.ebayimg.com. null when the listing has no product image.
fullResThumbnailUrlstring | null
Full-resolution version of thumbnailUrl (~1600px), derived by replacing the size suffix (s-l500, s-l140, etc.) with s-l1600. null when thumbnailUrl is null.
epidstring | null
eBay catalog product ID. Stable across sellers for the same variant. null when the listing has no catalog match.
titlestring | null
Listing title.
conditionstring | null
eBay's own localized condition label (e.g. "Pre-Owned", "Gebraucht"), when it resolves to a known value. null when the listing shows no condition, or when the label eBay displayed does not match a known value (rare — the field is dropped rather than surfaced verbatim).
conditionIdnumber | null
eBay numeric condition ID (best-effort lookup from the localized label). Common: 1000 New, 3000 Used, 7000 For parts.
sellerType"private" | "business" | null
EU sites only (ebay.de, .fr, .it, .es). null on all non-EU sites. May also be null on EU sites served via eBay's newer card layout, pending mapping.
buyingFormat"auction" | "buyItNow" | "auctionWithBIN" | null
How the item was listed. "auction" = competitive bidding, "buyItNow" = fixed price (includes Best Offer listings), "auctionWithBIN" = auction that also had a Buy It Now option. null when the listing type could not be determined. Distinct from the buyingFormat query parameter, which filters results by listing format (different enum, different concern).
bidCountnumber | null
Number of bids received. Present for auction listings, null for fixed-price (Buy It Now) listings.
categoryIdstring
eBay category ID.
listingType"sold" | "active"
Whether this is a completed sale ("sold", the default) or a currently-listed item ("active", returned when sold=false).
shippingPricestring | null
Shipping cost; "0.00" when free, null when unknown.
shippingType"free" | "paid" | "pickup" | "unknown" | null
Shipping category.
totalPricestring | null
Listing price (soldPrice or currentPrice) + shippingPrice when both known.
sellerUsernamestring | null
eBay seller username.
sellerPositivePercentnumber | null
Seller positive feedback percentage.
sellerFeedbackScorenumber | null
Seller total feedback count.
itemLocationstring | null
Seller's country as shown on the eBay search results page. null when the seller is domestic (same country as the eBay domain) — eBay only displays a location label for international sellers. Use null to identify domestic listings and non-null for international ones. Localized per site language (e.g., "United States" on ebay.com, "Großbritannien" on ebay.de).
scrapedAtstring
ISO 8601 timestamp of when SoldComps fetched the listing.

Sold-listing fields (sold=true)

endedAtstring | null
Date the sale completed, as YYYY-MM-DD (date only — eBay never exposes a time of day). For active listings use timeLeft instead.
soldPricestring | null
The listing price at time of sale, as a decimal string. On Best Offer sales (bestOfferAccepted=true), this is normally the asking price (an upper bound), not the realized price — unless hydrateBoa=true, in which case soldPrice is updated to the actual accepted offer amount when a match is found and its currency matches soldCurrency. For active listings the asking price is in currentPrice.
soldCurrencystring | null
ISO 4217 currency of soldPrice. Active listings use currentCurrency.
bestOfferAcceptedboolean
true when the seller accepted a best offer rather than the listing selling at the listed price. With hydrateBoa=true, the accepted amount is returned in boaAcceptedPrice, and soldPrice is updated to it when the currencies match. Requires includeCompleteListing=true (the default). For active listings, whether the listing accepts offers is in acceptsOffers.
boaHydratedbooleanoptional
Only present with hydrateBoa=true, on items where bestOfferAccepted is true (omitted on all other items). true when the accepted offer was found in eBay's Price Guide; false when the lookup found no match — soldPrice then still holds the listing price.
boaAcceptedPricestring | nulloptional
The actual accepted Best Offer amount from eBay's Price Guide. Set whenever boaHydrated is true; null when boaHydrated is false. When boaAcceptedCurrency matches soldCurrency, soldPrice (and totalPrice) are also replaced with this amount; when the currencies differ, soldPrice keeps the listing price in the site currency.
boaAcceptedCurrencystring | nulloptional
ISO 4217 currency of boaAcceptedPrice. Set whenever boaHydrated is true; null when boaHydrated is false.
boaOriginalPricestring | nulloptional
The listing (asking) price before hydration — useful for computing the Best Offer discount. Set whenever boaHydrated is true; null when boaHydrated is false.

Active-listing fields (sold=false)

currentPricestring | null
Current asking price — the from/low bound of a multi-variant range. The active-mode counterpart to soldPrice.
currentPriceMaxstring | null
The to/high bound when a listing spans a price range (e.g. "$899.99 to $1099.99"). null for single-price listings; currentPrice is always the low bound.
currentCurrencystring | null
ISO 4217 currency code for currentPrice/currentPriceMax (e.g. "USD", "GBP"). The active-mode counterpart to soldCurrency.
watcherCountnumber | null
Number of eBay users watching this listing — a live demand signal. When eBay shows an approximate count ("N+"), this is N as a floor (at least N). null when none shown.
unitsSoldnumber | null
Units already sold on this currently-listed multi-quantity listing — a live sales-velocity signal. When eBay shows an approximate count ("N+" / "Más de N"), this is N as a floor. null when none shown.
acceptsOffersboolean
true when the listing accepts Best Offers ("or Best Offer"). The active-mode analogue of bestOfferAccepted.
timeLeftstring | null
Auction time remaining as a raw, localized, relative string exactly as eBay renders it, including the locale suffix ("6d 4h left", "Noch 5 Std 47 Min", "1g 6h rimasti"). A snapshot at scrape time — not an absolute end timestamp. null for fixed-price / Buy It Now listings.

Example active response (sold=false)

With sold=false, items drop the sold-only fields and return the asking price plus live signals instead. The default (sold) response is shown at the top of this endpoint.

{
  "keyword": "iphone 15 pro",
  "page": 1,
  "totalItems": 60,
  "totalResults": "14,000+",
  "hasNextPage": true,
  "autoSelectedCategory": { "id": "9355", "name": "Cell Phones & Smartphones" },
  "items": [
    {
      "itemId": "256987654321",
      "url": "https://www.ebay.com/itm/256987654321?nordt=true",
      "thumbnailUrl": "https://i.ebayimg.com/images/g/9QwAAeSwABCqGLiR/s-l500.webp",
      "fullResThumbnailUrl": "https://i.ebayimg.com/images/g/9QwAAeSwABCqGLiR/s-l1600.webp",
      "epid": "20049285656",
      "title": "Apple iPhone 15 Pro 256GB Natural Titanium - Unlocked",
      "condition": "Pre-Owned",
      "conditionId": 3000,
      "sellerType": null,
      "buyingFormat": "buyItNow",
      "bidCount": null,
      "categoryId": "9355",
      "listingType": "active",
      "shippingPrice": "0.00",
      "shippingCurrency": "USD",
      "shippingType": "free",
      "totalPrice": "849.99",
      "sellerUsername": "top-deals-store",
      "sellerPositivePercent": 99.8,
      "sellerFeedbackScore": 14200,
      "itemLocation": "United States",
      "scrapedAt": "2026-03-14T21:00:00.000Z",
      "currentPrice": "849.99",
      "currentPriceMax": null,
      "currentCurrency": "USD",
      "watcherCount": 31,
      "unitsSold": 12,
      "acceptsOffers": true,
      "timeLeft": null
    }
  ]
}

Request

curl -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  "https://api.sold-comps.com/v1/scrape\
?keyword=iphone+15+pro\
&ebaySite=ebay.com\
&page=1\
&count=60\
&sortOrder=endedRecently"

Response

{
  "keyword": "iphone 15 pro",
  "page": 1,
  "totalItems": 60,
  "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/3nkAAeSwCitqGLiR/s-l500.webp",
      "fullResThumbnailUrl": "https://i.ebayimg.com/images/g/3nkAAeSwCitqGLiR/s-l1600.webp",
      "epid": "20049285656",
      "title": "Apple iPhone 15 Pro 256GB Natural Titanium - Unlocked",
      "condition": "Pre-Owned",
      "conditionId": 3000,
      "sellerType": null,
      "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"
    }
  ]
}

Async sweeps

Max Mode

Max Mode auto-paginates server-side. Submit once, then poll for progress, get the result by email, or stream a signed CSV. Unlike /v1/scrape, a Max Mode submission is not 1 credit — each successfully scraped page debits 1 request from your monthly quota. A 50-page sweep can cost up to 50 requests. Failed pages don't debit. maxPages caps blast radius (max 100).

One job per user can be active at a time. A second submit while one is running returns 409 with the existing jobId.

POST/v1/scrape/max

Submit

Enqueue an async sweep. Returns a jobId you can poll, cancel, or wait for the worker to deliver via email / signed download URL. Pass Idempotency-Key to dedupe re-submits over a 24h window.

Request body

keywordstringrequired
eBay search term.
maxPagesinteger (1–100)optionaldefault: 50
Upper bound on how many pages the worker will fetch. Each successful page debits 1 request from your monthly quota.
resultTypeenumoptionaldefault: inline
How to deliver the result: inline (poll the results endpoint), email (CSV attached or signed link), download (signed CSV stream URL).
inlineemaildownload
emailTostringoptional
Recipient address when resultType=email. Falls back to the account email on file.
daysToScrapeinteger (1–365)optionaldefault: 90
History window in days. Currently has no effect on the scrape — the value is accepted and stored with the job, but is not yet applied to the fetch.
ebaySiteenumoptionaldefault: ebay.com
eBay domain to scrape.
ebay.comebay.co.ukebay.deebay.frebay.itebay.esebay.caebay.com.au
categoryIdstringoptionaldefault: 0
eBay category ID (_sacat).
sortOrderenumoptionaldefault: endedRecently
Sort order.
endedRecentlytimeNewlyListedpricePlusPostageLowestpricePlusPostageHighestdistanceNearest
minPricenumberoptional
Minimum price filter.
maxPricenumberoptional
Maximum price filter.
itemLocationenumoptionaldefault: default
Item location filter.
defaultdomesticworldwide
itemConditionenumoptionaldefault: any
Item condition filter.
anynewused
conditionIdnumberoptional
eBay numeric condition ID filter. Common IDs: 3 (New), 4 (Used), 1000 (Brand New), 1500 (Open box), 2750 (Like New), 3000 (Used), 7000 (For parts). Valid IDs vary by eBay category. When set, overrides itemCondition.
buyingFormatenumoptionaldefault: all
Filter by listing format (request filter — distinct from the per-item buyingFormat response field, which classifies how a listing was actually listed and uses a different enum). "auction" = auction-only, "buyItNow" = fixed-price / Buy It Now, "acceptsOffers" = listings with Best Offer enabled. Default "all" (no format filter).
allauctionbuyItNowacceptsOffers
sellerTypeenumoptional
EU sites only.
privatebusiness
includeCompleteListingbooleanoptionaldefault: true
Include eBay completed-listing metadata (LH_Complete=1) so bestOfferAccepted is detected accurately. Does not change which listings are returned. Set to false only to match pre-July-2026 behavior.
aspectFilterobjectoptional
eBay item-aspect facet filters. Keys and values are the human-readable facet names exactly as shown in eBay's sidebar refinements. Multi-select values use pipe as separator: {"Network":"Unlocked|AT&T"}. Invalid or unrecognized facets are silently ignored by eBay.
exactMatchbooleanoptionaldefault: true
When true (default), strips eBay's loosened-match results ("Results matching fewer words") so only items closely matching your keyword are returned. Set to false to include all results eBay returns.

Request

curl -X POST https://api.sold-comps.com/v1/scrape/max \
  -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: rtx-4090-march-sweep" \
  -d '{
    "keyword": "rtx 4090",
    "maxPages": 50,
    "resultType": "email",
    "emailTo": "[email protected]",
    "ebaySite": "ebay.com",
    "daysToScrape": 90
  }'

Response

{
  "jobId": "8c2f1a3e-3b54-4f6b-9c2a-1d6e2b9a0d31",
  "status": "queued",
  "resultsUrl": "/v1/scrape/max/results/8c2f1a3e-3b54-4f6b-9c2a-1d6e2b9a0d31",
  "estimatedSeconds": 150
}
GET/v1/scrape/max/results/:jobId

Poll

Returns progress while the job is running, or a summary + delivery info once terminal. Recommended poll interval is 5 seconds. The job retains results for 30 days, then 410 Gone.

Terminal statuses: done, failed, cancelled, quota_exhausted, upstream_unhealthy.

terminationReason: natural_end (no more pages), maxPages_reached, quota_exhausted, upstream_unhealthy (5 consecutive page failures), cancelled, or terminal_error (page 1 failed).

Running response

{
  "jobId": "8c2f1a3e-3b54-4f6b-9c2a-1d6e2b9a0d31",
  "status": "running",
  "keyword": "rtx 4090",
  "ebaySite": "ebay.com",
  "createdAt": "2026-06-13T20:01:14.000Z",
  "startedAt": "2026-06-13T20:01:14.000Z",
  "progress": {
    "currentPage": 12,
    "pagesAttempted": 12,
    "pagesSucceeded": 12,
    "pagesFailed": 0,
    "failedPages": [],
    "itemsCollected": 2880,
    "consecutiveFailures": 0
  }
}

Request

curl -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  https://api.sold-comps.com/v1/scrape/max/results/8c2f1a3e-3b54-4f6b-9c2a-1d6e2b9a0d31

Response

{
  "jobId": "8c2f1a3e-3b54-4f6b-9c2a-1d6e2b9a0d31",
  "status": "done",
  "keyword": "rtx 4090",
  "ebaySite": "ebay.com",
  "createdAt": "2026-06-13T20:01:13.000Z",
  "startedAt": "2026-06-13T20:01:14.000Z",
  "completedAt": "2026-06-13T20:04:09.000Z",
  "expiresAt": "2026-07-13T20:04:09.000Z",
  "summary": {
    "pagesAttempted": 42,
    "pagesSucceeded": 42,
    "pagesFailed": 0,
    "failedPages": [],
    "totalItems": 9870,
    "partial": false,
    "terminationReason": "natural_end"
  },
  "error": null,
  "delivery": {
    "method": "email",
    "status": "delivered",
    "lastError": null
  }
}
DELETE/v1/scrape/max/:jobId

Cancel

Marks a queued or running job for cancellation. The worker checks between pages, so a job mid-page can take a few seconds to settle. Cancelling a job that has already finished returns 409. Pages already scraped are not refunded.

Returns 200 with the updated job status. A cancelled job keeps the pages it collected: inline jobs return them as items, download jobs get a downloadUrl, and email jobs are emailed the partial CSV.

Request

curl -X DELETE \
  -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  https://api.sold-comps.com/v1/scrape/max/8c2f1a3e-3b54-4f6b-9c2a-1d6e2b9a0d31
GET/v1/scrape/max/:jobId/download.csv

Download CSV

Streams the full result as CSV. Authenticated with a signed token in the ?token= query parameter, not a Bearer header — the URL is safe to share in email. Tokens expire 24 hours after the job completes.

The download URL is returned at the top level of the poll response as downloadUrl (when resultType=download) or attached directly to completion emails. Do not append your API key — the signed token is the auth.

CSV columns: every field on the per-item response, one row per listing.

Request

# The download URL is returned in the poll response when
# resultType=download. The token is in the URL — do NOT add a Bearer header.

curl -o results.csv \
  "https://api.sold-comps.com/v1/scrape/max/8c2f1a3e.../download.csv?token=eyJhb..."
GET/rapidapi/scrape-ebay

RapidAPI - Scrape eBay

Identical response shape to /v1/scrape, but callable only through the SoldComps RapidAPI listing. Auth is via RapidAPI's marketplace headers — X-RapidAPI-Key + X-RapidAPI-Host — not Bearer tokens. Quotas and billing run through your RapidAPI subscription.

Query parameters

keywordstringrequired
Passed directly to eBay's search bar. Supports eBay's minus-sign syntax to exclude terms — e.g. "iphone 15 pro -case -screen -lot" drops listings containing case, screen, or lot from results.
pageintegeroptionaldefault: 1
Page number of eBay results to fetch. Increment until hasNextPage is false.
countinteger (60, 120, 240)optionaldefault: 240
Items per page: 60, 120 or 240, for sold and active listings (sold=false). Other values are rounded up to the next size, so a request can return more items than count. Each page is one full eBay results page — the last page may contain fewer items.
ebaySiteenumoptionaldefault: ebay.com
eBay domain to scrape.
ebay.comebay.co.ukebay.deebay.frebay.itebay.esebay.caebay.com.au
categoryIdstringoptionaldefault: 0
eBay category ID (_sacat). Browse all 17,000+ IDs at sold-comps.com/ebay-categories. Use "0" for all categories.
sortOrderenumoptionaldefault: endedRecently
Sort order for results.
endedRecentlytimeNewlyListedpricePlusPostageLowestpricePlusPostageHighestdistanceNearest
minPricenumberoptional
Minimum price filter, in listing currency.
maxPricenumberoptional
Maximum price filter, in listing currency.
itemLocationenumoptionaldefault: default
Item location filter.
defaultdomesticworldwide
itemConditionenumoptionaldefault: any
Item condition filter applied as a request filter on eBay.
anynewused
conditionIdnumberoptional
eBay numeric condition ID filter. Common IDs: 3 (New), 4 (Used), 1000 (Brand New), 1500 (Open box), 2750 (Like New), 3000 (Used), 7000 (For parts). Valid IDs vary by eBay category. When set, overrides itemCondition. When omitted, no condition filter is applied.
buyingFormatenumoptionaldefault: all
Filter by listing format (request filter — distinct from the per-item buyingFormat response field, which classifies how a listing was actually listed and uses a different enum). "auction" = auction-only, "buyItNow" = fixed-price / Buy It Now, "acceptsOffers" = listings with Best Offer enabled. Default "all" (no format filter).
allauctionbuyItNowacceptsOffers
sellerTypeenumoptional
Filter results by seller type. Only effective on EU sites (ebay.de, .fr, .it, .es). On non-EU sites the filter is silently ignored.
privatebusiness
includeCompleteListingbooleanoptionaldefault: true
Include eBay completed-listing metadata (LH_Complete=1). This is what enables accurate bestOfferAccepted detection — without it, eBay does not render the "Best offer accepted" signal and bestOfferAccepted is false for nearly all items. Does not change which listings are returned: results stay sold-only (LH_Sold=1 takes precedence). Set to false only to match pre-July-2026 behavior.
soldbooleanoptionaldefault: true
When true (default), returns completed/sold listings. When false, returns ACTIVE (currently-listed) results instead. Active responses swap the sold-only fields (soldPrice, soldCurrency, endedAt, bestOfferAccepted) for active-only ones: listingType="active", the asking price in currentPrice/currentPriceMax/currentCurrency, plus watcherCount, unitsSold, acceptsOffers, and timeLeft.
soldAfterstring (YYYY-MM-DD)optional
Inclusive lower bound on endedAt. Applied after the page is scraped — sold-only, silently ignored when sold=false. See scrapedCount in the response for how to tell whether more pages will help.
soldBeforestring (YYYY-MM-DD)optional
Inclusive upper bound on endedAt. Applied after the page is scraped — sold-only, silently ignored when sold=false.
aspectFilterstring (JSON)optional
JSON object of eBay item-aspect facet filters — your HTTP client handles URL encoding automatically. Keys and values are the human-readable facet names exactly as shown in eBay's sidebar refinements (e.g. {"Brand":"Apple","Storage Capacity":"256 GB"}). Multi-select values use pipe as separator: {"Network":"Unlocked|AT&T"}. Facet names are dynamic per eBay category and vary by site language. Invalid or unrecognized facets are silently ignored by eBay.
exactMatchbooleanoptionaldefault: true
When true (default), strips eBay's loosened-match results ("Results matching fewer words") so only items closely matching your keyword are returned. Set to false to include all results eBay returns — useful when you want maximum volume over keyword precision.
hydrateBoabooleanoptionaldefault: false
When true, items sold via Best Offer have their soldPrice updated to the actual accepted offer amount using eBay's Price Guide. Primarily useful for trading card categories where Best Offer is common (~50% hit rate on ebay.com cards). Non-card categories silently skip hydration. eBay has Price Guide data only for items listed on ebay.com, ebay.co.uk and ebay.de. On an ebay.co.uk or ebay.de search, items listed on that site get the accepted amount in the listing currency; on every site, items listed on ebay.com get it in USD. When the hydrated price is in a different currency than the listing, boaAcceptedPrice and boaAcceptedCurrency are returned instead of overwriting soldPrice. Sold-only; ignored when sold=false. Costs 1 extra request against your quota, but only when hydration actually finds at least one match — a miss (or a keyword with no Best Offer items) costs nothing extra.

Response fields (each item)

itemIdstring
eBay listing item ID.
urlstring
Canonical listing URL with ?nordt=true to bypass eBay's catalog redirect.
thumbnailUrlstring | null
Listing thumbnail (500px) from i.ebayimg.com. null when the listing has no product image.
fullResThumbnailUrlstring | null
Full-resolution version of thumbnailUrl (~1600px), derived by replacing the size suffix (s-l500, s-l140, etc.) with s-l1600. null when thumbnailUrl is null.
epidstring | null
eBay catalog product ID. Stable across sellers for the same variant. null when the listing has no catalog match.
titlestring | null
Listing title.
conditionstring | null
eBay's own localized condition label (e.g. "Pre-Owned", "Gebraucht"), when it resolves to a known value. null when the listing shows no condition, or when the label eBay displayed does not match a known value (rare — the field is dropped rather than surfaced verbatim).
conditionIdnumber | null
eBay numeric condition ID (best-effort lookup from the localized label). Common: 1000 New, 3000 Used, 7000 For parts.
sellerType"private" | "business" | null
EU sites only (ebay.de, .fr, .it, .es). null on all non-EU sites. May also be null on EU sites served via eBay's newer card layout, pending mapping.
buyingFormat"auction" | "buyItNow" | "auctionWithBIN" | null
How the item was listed. "auction" = competitive bidding, "buyItNow" = fixed price (includes Best Offer listings), "auctionWithBIN" = auction that also had a Buy It Now option. null when the listing type could not be determined. Distinct from the buyingFormat query parameter, which filters results by listing format (different enum, different concern).
bidCountnumber | null
Number of bids received. Present for auction listings, null for fixed-price (Buy It Now) listings.
categoryIdstring
eBay category ID.
listingType"sold" | "active"
Whether this is a completed sale ("sold", the default) or a currently-listed item ("active", returned when sold=false).
shippingPricestring | null
Shipping cost; "0.00" when free, null when unknown.
shippingType"free" | "paid" | "pickup" | "unknown" | null
Shipping category.
totalPricestring | null
Listing price (soldPrice or currentPrice) + shippingPrice when both known.
sellerUsernamestring | null
eBay seller username.
sellerPositivePercentnumber | null
Seller positive feedback percentage.
sellerFeedbackScorenumber | null
Seller total feedback count.
itemLocationstring | null
Seller's country as shown on the eBay search results page. null when the seller is domestic (same country as the eBay domain) — eBay only displays a location label for international sellers. Use null to identify domestic listings and non-null for international ones. Localized per site language (e.g., "United States" on ebay.com, "Großbritannien" on ebay.de).
scrapedAtstring
ISO 8601 timestamp of when SoldComps fetched the listing.

Sold-listing fields (sold=true)

endedAtstring | null
Date the sale completed, as YYYY-MM-DD (date only — eBay never exposes a time of day). For active listings use timeLeft instead.
soldPricestring | null
The listing price at time of sale, as a decimal string. On Best Offer sales (bestOfferAccepted=true), this is normally the asking price (an upper bound), not the realized price — unless hydrateBoa=true, in which case soldPrice is updated to the actual accepted offer amount when a match is found and its currency matches soldCurrency. For active listings the asking price is in currentPrice.
soldCurrencystring | null
ISO 4217 currency of soldPrice. Active listings use currentCurrency.
bestOfferAcceptedboolean
true when the seller accepted a best offer rather than the listing selling at the listed price. With hydrateBoa=true, the accepted amount is returned in boaAcceptedPrice, and soldPrice is updated to it when the currencies match. Requires includeCompleteListing=true (the default). For active listings, whether the listing accepts offers is in acceptsOffers.
boaHydratedbooleanoptional
Only present with hydrateBoa=true, on items where bestOfferAccepted is true (omitted on all other items). true when the accepted offer was found in eBay's Price Guide; false when the lookup found no match — soldPrice then still holds the listing price.
boaAcceptedPricestring | nulloptional
The actual accepted Best Offer amount from eBay's Price Guide. Set whenever boaHydrated is true; null when boaHydrated is false. When boaAcceptedCurrency matches soldCurrency, soldPrice (and totalPrice) are also replaced with this amount; when the currencies differ, soldPrice keeps the listing price in the site currency.
boaAcceptedCurrencystring | nulloptional
ISO 4217 currency of boaAcceptedPrice. Set whenever boaHydrated is true; null when boaHydrated is false.
boaOriginalPricestring | nulloptional
The listing (asking) price before hydration — useful for computing the Best Offer discount. Set whenever boaHydrated is true; null when boaHydrated is false.

Request

curl --request GET \
  --url 'https://sold-comps.p.rapidapi.com/rapidapi/scrape-ebay?keyword=iphone+15+pro&count=60' \
  --header 'X-RapidAPI-Key: YOUR_RAPIDAPI_KEY' \
  --header 'X-RapidAPI-Host: sold-comps.p.rapidapi.com'

Response

{
  "keyword": "iphone 15 pro",
  "page": 1,
  "totalItems": 60,
  "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/3nkAAeSwCitqGLiR/s-l500.webp",
      "fullResThumbnailUrl": "https://i.ebayimg.com/images/g/3nkAAeSwCitqGLiR/s-l1600.webp",
      "epid": "20049285656",
      "title": "Apple iPhone 15 Pro 256GB Natural Titanium - Unlocked",
      "condition": "Pre-Owned",
      "conditionId": 3000,
      "sellerType": null,
      "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"
    }
  ]
}
GET/v1/item/{itemId}

Item detail lookup

Look up any eBay listing by item ID and get the full detail page data: item specifics, all images, seller info, condition, shipping, location, category, ended date, and bid count. Works for both sold and active listings. Each call costs 1 request. Pass includeDescription=true to also fetch the seller's item description (~200ms extra latency, no additional quota cost).

Parameters

itemIdstringrequired
eBay item number (10-15 digits), e.g. 168647489856. Also accepts a full eBay item URL — the handler extracts the numeric ID.
ebaySitestringoptionaldefault: ebay.com
eBay domain. Determines the currency of the returned price and shipping (e.g. USD on ebay.com, GBP on ebay.co.uk).
ebay.comebay.co.ukebay.deebay.frebay.itebay.esebay.caebay.com.au
includeDescriptionbooleanoptionaldefault: false
When true, fetches the seller's item description as sanitized plain text. Adds ~200ms latency, no additional quota cost.

Response fields

itemIdstring
eBay item number.
urlstring
Canonical item URL.
titlestring | null
Full listing title.
pricestring | null
Current or sold price as a numeric string (e.g. "799.99"). On a sale with an accepted Best Offer this is the accepted amount, not the asking price.
originalPricestring | null
The list price eBay shows struck through next to the sold price — the asking price before an accepted Best Offer or a markdown. null when the page shows none.
currencystring | null
ISO currency code (e.g. "USD", "GBP"). Depends on ebaySite.
conditionstring | null
Item condition label (e.g. "Pre-Owned", "Graded - PSA 10").
conditionDescriptionstring | null
Seller's condition notes, if provided.
endedboolean
Whether the listing has ended (sold or expired).
endedDatestring | null
When the listing ended (e.g. "Sep 03, 2026 15:43:00 PDT"). Localized on non-English sites. null for active listings.
soldBannerstring | null
Sold banner text (e.g. "Item sold on Thu, Sep 3 at 3:43 PM"). English sites only; null on non-English sites and active listings.
bestOfferAcceptedboolean
true when the price shown is the asking price on a sold Best Offer listing, not the actual accepted amount (eBay never discloses it). false for auctions, Buy It Now sales, and active listings.
bidCountnumber | null
Number of bids on auction listings. null for Buy It Now / Best Offer.
itemSpecificsRecord<string, string>
All item specifics as key-value pairs (e.g. {"Brand": "Apple", "Model": "iPhone 15 Pro", "Storage Capacity": "256 GB"}). Typically 10-30 fields per listing.
imagesstring[]
All listing image URLs at full resolution (1600px). Primary image first.
sellerobject | null
Seller details: username (string), feedbackPercent (number, e.g. 99.8), itemsSold (string — localized, e.g. "4.7K items sold" on English sites, "88 Artikel verkauft" on ebay.de), joinedDate (string — localized, e.g. "Joined Jun 2026" on English sites, "Mitglied seit Jun 2026" on ebay.de).
shippingstring | null
Shipping cost text (e.g. "Free shipping", "US $9.99").
locationstring | null
Item location (e.g. "San Jose, California, United States").
returnPolicystring | null
Return policy text.
descriptionstring | null
Seller's item description as plain text. null when the description has not been fetched — pass includeDescription=true to fetch it.
categoryPathstring | null
Breadcrumb path (e.g. "Cell Phones & Accessories > Cell Phones & Smartphones").
categoryIdstring | null
Leaf category ID from the breadcrumb.
scrapedAtstring
ISO 8601 timestamp of when the data was fetched.

Request

curl -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  "https://api.sold-comps.com/v1/item/168647489856"

Response

{
  "itemId": "168647489856",
  "url": "https://www.ebay.com/itm/168647489856",
  "title": "2022 Pokemon Card 2022 S-Chinese Mimikyu CSM1.5C 014/060 Grade 10",
  "price": "4.99",
  "originalPrice": null,
  "currency": "USD",
  "condition": "Graded - Other 10",
  "conditionDescription": null,
  "ended": true,
  "endedDate": "Sep 03, 2026 15:43:00 PDT",
  "soldBanner": "Item sold on Thu, Sep 3 at 3:43 PM",
  "bestOfferAccepted": false,
  "bidCount": 1,
  "itemSpecifics": {
    "Condition": "Graded - Other 10: Professionally graded",
    "Game": "Pokémon TCG",
    "Language": "Chinese",
    "Manufacturer": "The Pokémon Company",
    "Card Type": "Pokémon",
    "Finish": "Holo",
    "Card Size": "Standard",
    "Material": "Card Stock",
    "Vintage": "No",
    "Country of Origin": "China"
  },
  "images": [
    "https://i.ebayimg.com/images/g/PWcAAeSwRYJqdpUE/s-l1600.jpg",
    "https://i.ebayimg.com/images/g/EaMAAeSwYPFqdpPo/s-l1600.jpg"
  ],
  "seller": {
    "username": "ptcg-Pokémon",
    "feedbackPercent": 100,
    "itemsSold": "4.7K items sold",
    "joinedDate": "Joined Jun 2026"
  },
  "shipping": "US $9.99",
  "location": "Fuzhou City, Fujian, China",
  "returnPolicy": "Seller does not accept returns. If the item you received doesn't match the listing description, your purchase may be eligible for eBay Money Back Guarantee if the return request is made within 3 days from delivery.",
  "description": null,
  "categoryPath": "Toys & Hobbies > Collectible Card Games > Single Cards",
  "categoryId": "1893526",
  "scrapedAt": "2026-09-03T18:30:00.000Z"
}
GET/v1/poshmark/sold

Search Poshmark sold listings

Returns one page of real Poshmark sold listing data for a given keyword. Each page returns up to 48 items (Poshmark's native page size). Same auth and middleware stack as the eBay endpoints — rate limited per plan, monthly quota enforced per billing period. Each request costs 1 quota slot. With enrich=true, each request costs 2 quota slots — the extra slot covers the per-listing detail API call that adds sold date, days to sell, seller location, and other enrichment fields.

Query parameters

keywordstringrequired
Poshmark search term.
pageintegeroptionaldefault: 1
Page number. Each page returns up to 48 items (Poshmark's native page size). Increment until hasNextPage is false.
minPricenumberoptional
Minimum price filter (USD).
maxPricenumberoptional
Maximum price filter (USD).
departmentenumoptionaldefault: all
Poshmark department filter.
allwomenmenkidshomepetselectronics
conditionenumoptionaldefault: all
Condition filter. "nwt" = New With Tags only.
allnwt
brandstringoptional
Filter by brand name (e.g. "Louis Vuitton").
sortByenumoptionaldefault: sold_recently
Sort order for results.
sold_recentlyprice_ascprice_desclikes
enrichbooleanoptionaldefault: false
When true, each listing is enriched via Poshmark's detail API, adding soldAt, listedAt, daysToSell, colors, description, category, condition, commentsCount, shareCount, shippingCost, sellerLocation, sellerSoldCount, and sellerAvgShipTime. Costs 2 quota slots instead of 1. When false (default), only search-page fields are returned (faster, 1 slot).
Enrichment costs 2 quota slots. With enrich=true, each request consumes 2 slots from your monthly quota instead of 1. The extra slot covers the per-listing detail API call that populates soldAt, listedAt, daysToSell, category, condition, colors, description, shippingCost, commentsCount, shareCount, sellerLocation, sellerSoldCount, and sellerAvgShipTime. When enrich=false (the default), those fields are null and only 1 slot is consumed.

Response fields (each item)

listingIdstring
Poshmark listing ID (24-char hex).
urlstring
Canonical Poshmark listing URL.
titlestring
Listing title.
soldPricenumber | null
Sale price in USD.
originalPricenumber | null
Original listing price in USD.
brandstring | null
Brand name.
sizestring | null
Size label (e.g. "OS", "M", "10").
nwtboolean
New With Tags flag.
likesCountnumber | null
Number of likes on the listing.
sellerUsernamestring | null
Poshmark seller username.
thumbnailUrlstring | null
Listing thumbnail URL.
scrapedAtstring
ISO 8601 timestamp when the listing was scraped.

Enrichment fields (enrich=true only)

These fields are populated only when enrich=true. When enrichment is off or fails for a listing, they return null (or [] for colors).

soldAtstring | null
ISO timestamp when the item sold.
listedAtstring | null
ISO timestamp when the item was first published.
daysToSellnumber | null
Days between listedAt and soldAt.
categorystring | null
Department > Category path (e.g. "Women > Bags > Totes").
conditionstring | null
Item condition from Poshmark (e.g. "Pre-owned").
colorsstring[]
Color names. Empty array when not enriched.
descriptionstring | null
Full listing description text.
shippingCostnumber | null
Shipping cost in USD.
commentsCountnumber | null
Number of comments on the listing.
shareCountnumber | null
Number of shares.
sellerLocationstring | null
Seller city and state (e.g. "Los Angeles, CA").
sellerSoldCountnumber | null
Total listings the seller has sold.
sellerAvgShipTimenumber | null
Seller's average ship time in days.

Enriched response (enrich=true)

With enrich=true, each item includes the full set of enrichment fields. The default (enrich=false) response is shown at the top of this endpoint.

{
  "keyword": "louis vuitton neverfull",
  "page": 1,
  "totalItems": 48,
  "hasNextPage": true,
  "items": [
    {
      "listingId": "6478a1b2c3d4e5f6a7b8c9d0",
      "url": "https://poshmark.com/listing/Louis-Vuitton-Neverfull-6478a1b2c3d4e5f6a7b8c9d0",
      "title": "Louis Vuitton Neverfull MM Damier Ebene",
      "soldPrice": 1250,
      "originalPrice": 1960,
      "shippingCost": 7.97,
      "brand": "Louis Vuitton",
      "size": "OS",
      "category": "Women > Bags > Totes",
      "condition": "Pre-owned",
      "nwt": false,
      "colors": ["Brown"],
      "description": "Authentic Louis Vuitton Neverfull MM in Damier Ebene...",
      "soldAt": "2026-07-15T18:30:00.000Z",
      "listedAt": "2026-06-01T12:00:00.000Z",
      "daysToSell": 44.27,
      "likesCount": 23,
      "commentsCount": 4,
      "shareCount": 12,
      "sellerUsername": "luxurycloset",
      "sellerLocation": "Los Angeles, CA",
      "sellerSoldCount": 847,
      "sellerAvgShipTime": 1.5,
      "thumbnailUrl": "https://di2ponv0v5otw.cloudfront.net/posts/2026/07/15/...",
      "scrapedAt": "2026-08-09T14:30:00.000Z"
    }
  ]
}

Request

curl -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  "https://api.sold-comps.com/v1/poshmark/sold\
?keyword=louis+vuitton+neverfull\
&page=1\
&department=women\
&sortBy=sold_recently"

Response

{
  "keyword": "louis vuitton neverfull",
  "page": 1,
  "totalItems": 48,
  "hasNextPage": true,
  "items": [
    {
      "listingId": "6478a1b2c3d4e5f6a7b8c9d0",
      "url": "https://poshmark.com/listing/Louis-Vuitton-Neverfull-6478a1b2c3d4e5f6a7b8c9d0",
      "title": "Louis Vuitton Neverfull MM Damier Ebene",
      "soldPrice": 1250,
      "originalPrice": 1960,
      "shippingCost": null,
      "brand": "Louis Vuitton",
      "size": "OS",
      "category": null,
      "condition": null,
      "nwt": false,
      "colors": [],
      "description": null,
      "soldAt": null,
      "listedAt": null,
      "daysToSell": null,
      "likesCount": 23,
      "commentsCount": null,
      "shareCount": null,
      "sellerUsername": "luxurycloset",
      "sellerLocation": null,
      "sellerSoldCount": null,
      "sellerAvgShipTime": null,
      "thumbnailUrl": "https://di2ponv0v5otw.cloudfront.net/posts/2026/07/15/...",
      "scrapedAt": "2026-08-09T14:30:00.000Z"
    }
  ]
}
GET/v1/tcgplayer/sales

TCGPlayer sales history (Beta)

BetaReturns up to 5 of the most recent sales of a TCGPlayer product ID. This is the number TCGPlayer makes public, on every plan. Use the productId from search results. With condition, you get up to 5 of the most recent sales of that condition, so one request per condition gives more sales. Printing variant and language filter the returned sales. Same auth and middleware stack as the eBay endpoints. Each request costs 1 quota slot. This endpoint is in beta and may return errors under heavy load. Failed requests are not charged against your quota.

Query parameters

productIdintegerrequired
TCGPlayer product ID (from search results).
conditionenumoptional
Returns up to 5 of the most recent sales of this condition. Without it, up to 5 of the most recent sales of any condition.
nearMintlightlyPlayedmoderatelyPlayedheavilyPlayeddamaged
variantstringoptional
Filter the returned sales by printing variant (e.g. "Holofoil", "Normal"). Can return fewer than 5.
languagestringoptional
Filter the returned sales by card language (e.g. "English"). Can return fewer than 5.
listingTypeenumoptionaldefault: All
Filter by listing photo presence.
AllListingWithPhotosListingWithoutPhotos

Response fields (each item)

pricenumber
The price the card sold for (before shipping).
shippingPricenumber
Shipping cost paid.
totalPricenumber
price + shippingPrice — total transaction amount.
conditionstring | null
Condition of the card that sold.
variantstring | null
Printing variant (e.g. "Holofoil").
languagestring | null
Card language.
quantitynumber | null
How many cards in this transaction.
soldDatestring | null
ISO 8601 timestamp when the sale occurred.
listingTypestring | null
Listing type (e.g. "ListingWithoutPhotos", "ListingWithPhotos").
marketplacestring
Always "tcgplayer".

Request

curl -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  "https://api.sold-comps.com/v1/tcgplayer/sales\
?productId=274439"

Response

{
  "productId": 274439,
  "totalResults": 5,
  "hasNextPage": false,
  "items": [
    {
      "price": 4.66,
      "shippingPrice": 4.90,
      "totalPrice": 9.56,
      "condition": "Near Mint",
      "variant": "Holofoil",
      "language": "English",
      "quantity": 1,
      "soldDate": "2026-09-07T18:32:25.75+00:00",
      "listingType": "ListingWithoutPhotos",
      "marketplace": "tcgplayer"
    }
  ],
  "marketplace": "tcgplayer",
  "scrapedAt": "2026-09-07T20:00:00.000Z"
}
GET/usage

Usage and remaining requests

Returns your plan, the requests used and remaining in the current billing period, the reset time, your per-minute rate limit and your credit balance. Same Authorization: Bearer key as the search endpoints. This call is free: it does not count against your monthly quota, your credits, or the per-minute limit of the search endpoints. /usage and /requests share a limit of 60 calls per minute.

Response fields

planstring
Your current plan, e.g. starter. plan_label is its display name.
usage.limitnumber
Monthly request cap for your plan.
usage.usednumber
Requests counted in the current billing period.
usage.remainingnumber
limit minus used, never below 0.
usage.period_startstring
ISO 8601 start of the current billing period.
usage.reset_atstring
ISO 8601 time when the billing period resets.
rate_limit.rpmnumber
Your per-minute request cap on the search endpoints.
rate_limit.remainingnumber | null
Requests remaining in the current minute window. null if it cannot be read at the moment.
rate_limit.resetnumber | null
Unix epoch seconds when the minute window resets.
credits.balancenumber
Purchased pay-as-you-go credits left.

Request

curl -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  "https://api.sold-comps.com/usage"

Response

{
  "plan": "starter",
  "plan_label": "Starter",
  "usage": {
    "limit": 2000,
    "used": 1234,
    "remaining": 766,
    "period_start": "2026-09-04T16:20:11.000Z",
    "reset_at": "2026-10-04T16:20:11.000Z"
  },
  "rate_limit": {
    "rpm": 60,
    "remaining": 58,
    "reset": 1791217260
  },
  "credits": {
    "balance": 100
  }
}
GET/requests

Request history

Lists the requests made by your account, newest first, with the search parameters, result count, duration and success of each one. It includes API, dashboard and Max Mode requests. Requests rejected with 401 or 429 are not listed. A request usually appears within a few seconds of its response. This call is free and shares the 60 calls per minute limit of /usage. To page, call again with cursor set to next_cursor while has_more is true.

Query parameters

limitnumberoptionaldefault: 50
Rows per page, 1–100. Values outside the range are clamped.
cursorstringoptional
next_cursor from the previous page. Send the same from / to with it.
fromstringoptional
Date as YYYY-MM-DD (UTC). Only requests on or after this day. History goes back at most 90 days; an older date is moved to that limit.
tostringoptional
Date as YYYY-MM-DD (UTC). Only requests on or before this day; the whole day is included.

Response fields (each request)

request_idstring
ID of the request.
created_atstring
ISO 8601 time of the request, UTC.
endpointstring | null
The endpoint that was called, e.g. /v1/scrape or /api/bulk-search. null on old rows.
sourcestring
api = called with an API key, dashboard = a search in the dashboard, max-mode = one page of a Max Mode job (one row per page).
apidashboardmax-mode
marketplacestring
ebay, poshmark, mercari or tcgplayer.
listing_typestring | null
Sold or active listings. eBay requests only; null for other marketplaces.
soldactive
keywordstring
The search keyword. For /v1/item it is the item ID, for /v1/tcgplayer/sales the product ID.
page / count / sitenumber / number | null / string | null
The page, page size and eBay site of the request. site is null for other marketplaces.
filtersobject
The other search parameters as the API applied them, defaults included (category, sort order, price range, condition, dates, …). null where a parameter was not set or does not apply. marketplace_params holds the Poshmark, Mercari and TCGPlayer parameters.
result_countnumber | null
Number of items returned.
has_next_pageboolean | null
hasNextPage of the response.
duration_msnumber | null
How long the request took.
successboolean
true if the request returned 200.
errorstring | null
Why a failed request failed. null on success.
at_capacitytimeoutitem_not_foundpage_limitupstream_error
max_mode_job_idstring | null
The Max Mode job this page belongs to.

usage.used from /usage is the number your quota is measured with. A count of successful rows from /requests can differ from it: a request with hydrateBoa=true that finds a Best Offer price counts as 2, a Poshmark request with enrich=true counts as 2, requests paid with credits are not in used, and failed requests are not counted.

Request

curl -H "Authorization: Bearer sc_YOUR_KEY_HERE" \
  "https://api.sold-comps.com/requests?limit=50&from=2026-10-01"

Response

{
  "requests": [
    {
      "request_id": "0b9f6f0e-6f0c-4c62-9a43-7c1f0d1c2a11",
      "created_at": "2026-10-04T14:03:22.418Z",
      "endpoint": "/v1/scrape",
      "source": "api",
      "marketplace": "ebay",
      "listing_type": "sold",
      "keyword": "pokemon charizard psa 10",
      "page": 1,
      "count": 240,
      "site": "ebay.com",
      "filters": {
        "category_id": "0",
        "sort_order": "endedRecently",
        "min_price": null,
        "max_price": null,
        "item_location": "default",
        "item_condition": "any",
        "buying_format": null,
        "condition_id": null,
        "aspect_filter": null,
        "exact_match": true,
        "sold_after": null,
        "sold_before": null,
        "seller_type": null,
        "include_complete_listing": true,
        "marketplace_params": null
      },
      "result_count": 240,
      "has_next_page": true,
      "duration_ms": 2140,
      "success": true,
      "error": null,
      "max_mode_job_id": null
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMC0wNCAxNDowMzoyMi40MTgxMjd8NDgyMTE5MzQ"
}