Does eBay API return sold listings?
Does the eBay API return sold listings? The Browse API does not: it searches live listings only. One short script sends the same search to GET /ebay/v1/sold and prints sold prices.
What the Browse API returns
The Browse API searches listings that are for sale now. eBay's guide tells an app to drop an item whose end date has passed. The search filters select condition, price, buying format and the date a listing will end. No filter selects sold items.
Sold items were in the Finding API, as findCompletedItems. eBay decommissioned the Finding API in February 2025 and names the Browse API as its replacement. The Marketplace Insights API returns sold items. eBay marks it Limited Release, for approved partners. The Trawl vs the eBay Marketplace Insights API page compares the two.
For sold prices as data, create a free account and send the Browse search to the eBay Sold Listings API instead. It takes the same keywords, category, condition and price range. Every result is a completed sale.
Do these steps
Click the button to copy this prompt, then paste it into your coding agent. The link tells it which page you came from.
Read https://trawl.dev/llms.txt?from=/guides/does-ebay-api-return-sold-listings and help me integrate this API into my project.- Set your API key. Get a key from the free tier. terminal
export TRAWL_API_KEY=your_key - Run the script in your language. Python needs the requests package. Node 18 and Go 1.22 need nothing more. The search costs 1 credit.
# browse_to_sold.py (pip install requests)
import os
import requests
# A Browse API search: keywords, a category, and filters for condition and price.
browse = {
"q": "iphone 15 pro 256gb",
"category_ids": "9355",
"filter": "conditions:{USED},price:[300..700],priceCurrency:USD",
"limit": 50,
}
# The same search on GET /sold. Every result sold, so there is no sold filter to add.
filters = dict(f.split(":", 1) for f in browse["filter"].split(","))
low, high = filters["price"].strip("[]").split("..")
r = requests.get("https://api.trawl.dev/ebay/v1/sold", timeout=30, headers={"x-api-key": os.environ["TRAWL_API_KEY"]}, params={
"query": browse["q"],
"category": browse["category_ids"],
"condition": filters["conditions"].strip("{}").lower().replace("|", ","), # USED -> used
"min_price": low,
"max_price": high,
"max_pages": 1, # a page is 100 results
})
r.raise_for_status()
sold = r.json()
print(f"{sold['count']} sold items, {sold['credits_charged']} credit")
for s in sold["results"][:5]:
print(f"{s['date_sold'][:10]} {s['currency']} {s['sale_price']:>7.2f} {s['title'][:56]}")// browse_to_sold.mjs (Node 18 or newer, no package)
// A Browse API search: keywords, a category, and filters for condition and price.
const browse = {
q: "iphone 15 pro 256gb",
category_ids: "9355",
filter: "conditions:{USED},price:[300..700],priceCurrency:USD",
limit: 50,
};
// The same search on GET /sold. Every result sold, so there is no sold filter to add.
const filters = Object.fromEntries(browse.filter.split(",").map((f) => f.split(/:(.*)/s).slice(0, 2)));
const [low, high] = filters.price.replace(/[[\]]/g, "").split("..");
const params = new URLSearchParams({
query: browse.q,
category: browse.category_ids,
condition: filters.conditions.replace(/[{}]/g, "").toLowerCase().replaceAll("|", ","), // USED -> used
min_price: low,
max_price: high,
max_pages: 1, // a page is 100 results
});
const r = await fetch(`https://api.trawl.dev/ebay/v1/sold?${params}`, {
headers: { "x-api-key": process.env.TRAWL_API_KEY },
});
if (!r.ok) throw new Error(`${r.status} ${await r.text()}`);
const sold = await r.json();
console.log(`${sold.count} sold items, ${sold.credits_charged} credit`);
for (const s of sold.results.slice(0, 5)) {
console.log(`${s.date_sold.slice(0, 10)} ${s.currency} ${s.sale_price.toFixed(2).padStart(7)} ${s.title.slice(0, 56)}`);
}// browse_to_sold.go (Go 1.22 or newer, standard library only)
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
)
type sold struct {
Count int `json:"count"`
Credits int `json:"credits_charged"`
Results []struct {
Title string `json:"title"`
SalePrice float64 `json:"sale_price"`
Currency string `json:"currency"`
DateSold string `json:"date_sold"`
} `json:"results"`
}
func main() {
// A Browse API search: q=iphone 15 pro 256gb, category_ids=9355,
// filter=conditions:{USED},price:[300..700],priceCurrency:USD.
// The same search on GET /sold. Every result sold, so there is no sold filter to add.
q := url.Values{
"query": {"iphone 15 pro 256gb"}, // was q
"category": {"9355"}, // was category_ids
"condition": {"used"}, // was conditions:{USED}
"min_price": {"300"}, // was price:[300..700]
"max_price": {"700"},
"max_pages": {"1"}, // a page is 100 results
}
req, _ := http.NewRequest("GET", "https://api.trawl.dev/ebay/v1/sold?"+q.Encode(), nil)
req.Header.Set("x-api-key", os.Getenv("TRAWL_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil || res.StatusCode != 200 {
panic(fmt.Sprint(err, res))
}
var s sold
json.NewDecoder(res.Body).Decode(&s)
fmt.Printf("%d sold items, %d credit\n", s.Count, s.Credits)
for _, it := range s.Results[:5] {
fmt.Printf("%s %s %7.2f %.56s\n", it.DateSold[:10], it.Currency, it.SalePrice, it.Title)
}
}100 sold items, 1 credit
2026-10-08 $ 560.00 Apple iPhone 15 Pro Max 256GB Unlocked Used Good Conditi
2026-10-08 $ 450.00 iPhone 15 Pro Max Smartphone 256GB UNLOCKED CARRIER
2026-10-08 $ 400.00 Apple IPhone 15 Pro Max 256GB Blue Unlocked
2026-10-08 $ 575.00 Apple iPhone 15 Pro Max 256GB Silver Network Unlocked Wi
2026-10-08 $ 510.00 Apple iPhone 15 Pro Max Blue 256GB - Verizon100 sold items, 1 credit
2026-10-08 $ 560.00 Apple iPhone 15 Pro Max 256GB Unlocked Used Good Conditi
2026-10-08 $ 450.00 iPhone 15 Pro Max Smartphone 256GB UNLOCKED CARRIER
2026-10-08 $ 400.00 Apple IPhone 15 Pro Max 256GB Blue Unlocked
2026-10-08 $ 575.00 Apple iPhone 15 Pro Max 256GB Silver Network Unlocked Wi
2026-10-08 $ 510.00 Apple iPhone 15 Pro Max Blue 256GB - Verizon100 sold items, 1 credit
2026-10-08 $ 560.00 Apple iPhone 15 Pro Max 256GB Unlocked Used Good Conditi
2026-10-08 $ 450.00 iPhone 15 Pro Max Smartphone 256GB UNLOCKED CARRIER
2026-10-08 $ 400.00 Apple IPhone 15 Pro Max 256GB Blue Unlocked
2026-10-08 $ 575.00 Apple iPhone 15 Pro Max 256GB Silver Network Unlocked Wi
2026-10-08 $ 510.00 Apple iPhone 15 Pro Max Blue 256GB - VerizonHow the request maps
q becomes query. Each word must be in the listing title. category_ids becomes category, one leaf id. Find one with the eBay Category IDs API. The conditions filter becomes condition: new, used, parts or other. The price filter becomes min_price and max_price, in the marketplace's currency. aspect_filter becomes attr, one Key:Value per item specific.
limit and offset become max_pages. A page holds 100 results. The X-EBAY-C-MARKETPLACE-ID header becomes site. There is no filter for buying format. Each result states its buying_format. The itemEndDate filter has no counterpart. date_from and date_to select by the date the item sold.
What comes back
A Browse result is a live listing with its asking price. A sold result is one sale: sale_price, shipping_price, date_sold, the condition in eBay's words as condition_raw, buying_format and bids. A count of 100 means older sales may exist. The eBay sold listings history guide reads a year of them, one month per call. Pass a result's item_id to the eBay Sold Item Details API for the item specifics, the images and the seller.
Is the eBay API free
Membership of the eBay Developers Program is free. The Browse API allows 5,000 calls a day by default. eBay's call-limits page says the Buy APIs require an additional license. Production use of them is for eBay partners, by application through the eBay Partner Network, with no guarantee of approval. Any developer account can use them in the sandbox.
Trawl charges credits: 1 per page of 100 results, 0 for an empty result. The free tier has 250 credits a month. Paid plans start at $20 a month for 3,000. The eBay findCompletedItems alternative guide maps the old Finding API request to the same endpoint.