eBay findCompletedItems alternative

eBay retired findCompletedItems in February 2025. The findCompletedItems alternative for sold prices is GET /ebay/v1/sold. One short script sends the old request there and answers in the old field names.

What findCompletedItems was

findCompletedItems was a call of the eBay Finding API. It searched completed listings by keyword and category, with a filter for the ones that sold. eBay restricted the call in October 2020 and decommissioned the Finding API in February 2025. A program that calls it today gets an error.

eBay's replacements do not cover it. The Browse API searches live listings only, see Does eBay API return sold listings? The Marketplace Insights API returns sales, but eBay grants it to few applicants. The Trawl vs the eBay Marketplace Insights API page has that comparison.

For sold prices as data, create a free account and do the steps below. The eBay Sold Listings API takes the same keywords, category and condition, and answers with completed sales.

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.

prompt
Read https://trawl.dev/llms.txt?from=/guides/findcompleteditems-alternative and help me integrate this API into my project.
  1. Set your API key. Get a key from the free tier.
    terminal
    export TRAWL_API_KEY=your_key
  2. 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.
the script
# findcompleteditems_to_sold.py  (pip install requests)
import os
import requests

# The request your code sent to findCompletedItems.
legacy = {
    "keywords": "iphone 15 pro 256gb",
    "categoryId": "9355",
    "itemFilter": [
        {"name": "SoldItemsOnly", "value": "true"},
        {"name": "Condition", "value": "3000"},  # 3000 was Used
    ],
    "paginationInput": {"entriesPerPage": 100, "pageNumber": 1},
}
# The same request on GET /sold. Every result sold, so SoldItemsOnly goes.
CONDITION = {"1000": "new", "1500": "new", "1750": "new", "7000": "parts"}
for used in ("2000", "2010", "2020", "2030", "2500", "2750", "3000", "4000", "5000", "6000"):
    CONDITION[used] = "used"
r = requests.get("https://api.trawl.dev/ebay/v1/sold", timeout=30, headers={"x-api-key": os.environ["TRAWL_API_KEY"]}, params={
    "query": legacy["keywords"],
    "category": legacy["categoryId"],
    "condition": ",".join(CONDITION[f["value"]] for f in legacy["itemFilter"] if f["name"] == "Condition"),
    "max_pages": legacy["paginationInput"]["pageNumber"],  # a page is 100 results
})
r.raise_for_status()
sold = r.json()

# The answer in findCompletedItems' own field names.
items = [
    {
        "itemId": s["item_id"], "title": s["title"],
        "sellingStatus": {"currentPrice": {"value": s["sale_price"], "currencyId": sold["currency"]}},
        "listingInfo": {"endTime": s["date_sold"], "listingType": s["buying_format"]},
        "condition": {"conditionDisplayName": s["condition_raw"]},
    }
    for s in sold["results"]
]
print(f"{sold['count']} sold listings, {sold['credits_charged']} credit")
for it in items[:5]:
    price = it["sellingStatus"]["currentPrice"]
    print(f"{price['currencyId']} {price['value']:>7.2f}  {it['listingInfo']['endTime'][:10]}  {it['title'][:58]}")
terminal · printed 2026-10-07
100 sold listings, 1 credit
USD  420.00  2026-10-07  Apple iPhone 15 Pro Max - 256GB - Blue Titanium - Unlocked
USD  549.99  2026-10-07  Apple iPhone 15 Pro 256GB Blue Unlocked Worldwide Excellen
USD  570.00  2026-10-07  Apple iPhone 15 Pro Max 256GB Unlocked Used Good Condition
USD  550.00  2026-10-07  Apple iPhone 15 Pro 256GB Unlocked - White
USD  450.00  2026-10-07  Apple iPhone 15 Pro 256GB unlocked gray

How the request maps

keywords becomes query. Each word must be in the listing title, as before. categoryId becomes category, the same leaf id. Find one with the eBay Category IDs API. The condition ids become the words new, used and parts. SoldItemsOnly has no counterpart. Every result of the eBay Sold Listings API sold.

pageNumber becomes max_pages. A page holds 100 results. max_pages returns pages 1 to N in one response, 20 at most. Drop the old paging loop. EndTimeFrom and EndTimeTo become date_from and date_to, as calendar dates. GLOBAL-ID becomes site.

How the response maps

The Python and Node scripts build one object per result. The old names are outside and the new names are inside. The Go script reads the answer into a struct whose fields carry the old names. currentPrice is sale_price, and the currency is stated once at the top of the response. endTime is date_sold. listingType is buying_format. conditionDisplayName is condition_raw. There is no totalEntries. A count of 100 means older sales may exist.

Open one listing

Each result has an item_id. Pass it to the eBay Sold Item Details API to open that listing. You get the item specifics, the images, the seller and the recorded sales. findCompletedItems never returned the specifics or the sales.