Resale Comps API
Sold and active listings from resale marketplaces, normalized to one schema, with summary statistics. Base URL: https://api.resalecomps.com
Quickstart
- Create an account and make a key in your dashboard. The free plan includes 100 requests a month.
- Call the API with the key in the Authorization header.
curl "https://api.resalecomps.com/v1/sold?q=carhartt+detroit+jacket&days=90" \ -H "Authorization: Bearer $RESALECOMPS_KEY"
const res = await fetch(
"https://api.resalecomps.com/v1/sold?" + new URLSearchParams({ q: "carhartt detroit jacket", days: "90" }),
{ headers: { Authorization: `Bearer ${process.env.RESALECOMPS_KEY}` } },
);
if (!res.ok) throw new Error((await res.json()).error.message);
const { summary, results } = await res.json();
console.log(summary.median, results.length);import os, requests
r = requests.get(
"https://api.resalecomps.com/v1/sold",
params={"q": "carhartt detroit jacket", "days": 90},
headers={"Authorization": f"Bearer {os.environ['RESALECOMPS_KEY']}"},
timeout=30,
)
r.raise_for_status()
data = r.json()
print(data["summary"]["median"], len(data["results"]))Authentication
Send Authorization: Bearer rc_live_… on every request (X-API-Key also works). Keys can be created, named and revoked in the dashboard. Keep keys server-side.
Freshness and history
Data is kept up to date automatically, and every search refreshes what's needed. The freshness array in each response gives, per marketplace, when its data for your query was last updated (updated_at) and a status: current (updated within the last day), updating (newer data for a new search is on its way, usually within a minute, so repeat the request shortly after) or stale.
History is kept, so it grows beyond what each marketplace shows. Sold date precision varies and is returned as sold_at_precision.
GET /v1/sold
Sold listings matching a query, with summary statistics. Metered: 1 request.
| Param | Type | Default | Notes |
|---|---|---|---|
q | string | required | Keyword query. Use quotes for phrases and a minus sign to exclude: "detroit jacket" -kids |
platforms | comma list | all on your plan | e.g. poshmark,vinted. See /v1/platforms |
market | comma list | us | Country market: us, ca, uk, de, fr, it, es, au, nl, be, pl. Each platform covers the markets it operates in |
condition | comma list | any | new_with_tags, new, like_new, good, fair, poor |
size | string | any | Exact normalized size, e.g. L, 10, W32 |
brand | string | any | Brand name (case-insensitive) |
min_price, max_price | number | none | In the output currency |
days | integer | 90 (sold), 30 (active) | Lookback window. Capped by your plan's history |
sort | enum | sold_at_desc | sold_at_desc, price_asc, price_desc. For /v1/active: newest, price_asc, price_desc |
limit | integer | 100 | Results per page, max 240 |
page | integer | 1 | Increment until has_next_page is false |
currency | string | USD | Output currency for summary and price: USD, CAD, GBP, EUR, AUD |
Response
{
"query": "carhartt detroit jacket",
"filters": { "platforms": ["poshmark", "vinted"], "regions": ["poshmark_us", "vinted_us"],
"days": 90, "currency": "USD", "sort": "sold_at_desc" },
"summary": {
"count": 187, "median": 92.0, "mean": 98.4, "p25": 74.0, "p75": 118.0,
"min": 35.0, "max": 260.0,
"by_platform": { "poshmark": { "count": 154, "median": 95.0 },
"vinted": { "count": 33, "median": 81.0 } }
},
"page": 1,
"has_next_page": true,
"results": [
{
"id": "poshmark:6ad2b3d01b53fe8f05e4f955",
"platform": "poshmark",
"marketplace_region": "poshmark_us",
"title": "Vintage Carhartt Detroit Jacket Blanket Lined",
"brand": "Carhartt",
"category": "Men / Jackets & Coats",
"size": "L",
"condition": "good",
"sold_price": 110.0,
"shipping_price": null,
"currency": "USD",
"price_usd": 110.0,
"price": 110.0,
"sold_at": "2026-10-11T18:22:00.000Z",
"sold_at_precision": "exact",
"url": "https://poshmark.com/listing/6ad2b3d01b53fe8f05e4f955",
"image_url": "https://di2ponv0v5otw.cloudfront.net/posts/..."
}
],
"freshness": [
{ "platform": "poshmark", "region": "poshmark_us",
"updated_at": "2026-10-17T03:12:09.120Z", "status": "current" }
],
"usage": { "requests_used": 1203, "requests_limit": 10000, "period_end": "2026-11-01T00:00:00.000Z" }
}GET /v1/summary
Same params as /v1/sold; returns only summary and freshness. Metered: 1 request.
GET /v1/active
Listings currently for sale, seen within days (default 30). Same params as /v1/sold; results have list_price, listed_at and last_seen_at instead of sold fields. Metered: 1 request.
GET /v1/fees
Seller fees and payout for a sale price on a platform. Params: platform, price, shipping (default 0), region (default us), category (eBay). Returns each fee line, the total and the payout. Free.
GET /v1/best-platform
Per-platform median sold price, the fees on that price and the net payout, sorted by payout. Same filters as /v1/sold. Metered: 1 request.
GET /v1/usage
Your plan, requests used and remaining this period, and limits. Free and not metered. Usage also comes back on every response in the X-Usage-Limit, X-Usage-Used and X-Usage-Reset headers.
GET /v1/platforms
Platforms available now, with their regions and whether they support sold and active searches. Free.
Result fields
id | {platform}:{platform_item_id}, stable across requests |
marketplace_region | e.g. poshmark_us, vinted_fr, ebay_uk |
condition | Normalized: new_with_tags, new, like_new, good, fair, poor (null when the seller didn't say) |
sold_price / list_price | In the listing's original currency |
price_usd | Converted at the ECB rate on the sale date |
price | price_usd in your requested currency |
shipping_price | Buyer-paid shipping when the platform shows it, else null |
sold_at_precision | exact (to the second), day (date only), approximate (detected when we saw it sell) |
Errors
Errors return JSON: {"error": {"code": "...", "message": "..."}}. Failed requests are not metered.
| 400 | invalid_params | Bad or missing parameters |
| 401 | missing_key / invalid_key | No key, or the key is invalid or revoked |
| 403 | platform_not_on_plan / history_not_on_plan | Upgrade to use that platform or lookback; includes upgrade_url |
| 429 | rate_limited / quota_exceeded | Includes Retry-After (seconds) and, for quota, upgrade_url |
| 503 | data_unavailable | No data is available for this search right now. Retry shortly |
| 500 | server_error | Retry with backoff |
Rate limits and quota
60 requests per minute per key. Headers on every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (Unix seconds). The monthly quota resets at the start of your billing period (calendar month on Free). Free stops at the quota; paid plans continue and extra requests are billed at $5 per 1,000.