eBay sold listings in Python: a complete example
Pull eBay sold listings into Python with requests, compute a clean median price, handle retries, run batch jobs, and load everything into pandas. Copy-paste code.
This is a complete, production-ready Python workflow for eBay sold data: one search, a clean price, retries that survive busy moments, batch jobs for many keywords, and a pandas DataFrame at the end.
1. Setup
pip install requests pandas
export EBAY_SOLD_API_KEY="eb_..." # from your dashboard2. One search with retries
import os, time, requests
API = "https://api.ebaysoldlistingsapi.com"
HEADERS = {"Authorization": f"Bearer {os.environ['EBAY_SOLD_API_KEY']}"}
RETRY = {429, 502, 503, 504}
def sold(keyword, **params):
for attempt in range(4):
r = requests.get(f"{API}/scrape", params={"keyword": keyword, **params},
headers=HEADERS, timeout=90)
if r.status_code not in RETRY:
r.raise_for_status()
return r.json()["results"]
time.sleep(int(r.headers.get("Retry-After", 2 ** attempt)))
r.raise_for_status()
rows = sold("shure sm7b", itemCondition="used")
print(len(rows), "sales")Failed requests are never billed, so retrying 429, 502, 503, and 504 costs nothing. Do not retry 400 (bad parameter) or 402 (quota).
3. A price you can trust
Use the median, and trim the extremes that come from parts-only units and big bundles:
import statistics
def fair_price(rows, trim=0.1):
prices = sorted(float(r["soldPrice"]) for r in rows if r.get("soldPrice"))
k = int(len(prices) * trim)
core = prices[k:len(prices) - k] or prices
return {
"n": len(prices),
"median": statistics.median(core),
"p25": core[len(core) // 4],
"p75": core[(3 * len(core)) // 4],
}
print(fair_price(rows))4. Into pandas
import pandas as pd
df = pd.DataFrame(rows)
df["soldPrice"] = df["soldPrice"].astype(float)
df["endedAt"] = pd.to_datetime(df["endedAt"])
print(df.groupby("condition")["soldPrice"].agg(["count", "median"]))
weekly = df.set_index("endedAt")["soldPrice"].resample("W").median()Prefer a file? Add format=csv and load it straight in: pd.read_csv(io.StringIO(r.text)).
5. Many keywords: batch jobs
job = requests.post(f"{API}/scrape/batch", headers=HEADERS, json={
"keywords": ["shure sm7b", "steam deck oled", "ps5 slim"],
"ebaySite": "ebay.com",
}).json()
while True:
status = requests.get(f"{API}/scrape/batch/{job['jobId']}", headers=HEADERS).json()
if status["status"] == "complete":
break
time.sleep(5)
for r in status["results"]:
print(r["keyword"], r["status"], r["count"])Each keyword counts as one request, and failed keywords are not charged. Download the whole job as one CSV from downloadUrl.
Is there a Python SDK?
You do not need one. The API is a single REST endpoint, so requests (or httpx) is all it takes. The examples above are complete.
What timeout should I use?
At least 90 seconds. Most searches return in a few seconds, but hard searches can take longer while the API retries on your behalf.
How do I get other countries?
Pass ebaySite, for example sold('barbour jacket', ebaySite='ebay.co.uk'). Prices return in the local currency.
Try it with real data
Get completed eBay sales as JSON. Fifty free requests a month, no card required.
Get your API key