I want to start this post with the single most important thing to understand about eBay data APIs before you write a line of code.

A search request and a product record are not the same thing.

This sounds obvious, but it's responsible for more eBay API budget surprises than almost any other mistake. I'll explain the distinction, then show you how to use each of the six operations Serpent API's eBay endpoint exposes — with real code for each one.

The Data Model

eBay's public data has a natural hierarchy:

Search query └── Listing page (contains N listing cards) └── Listing card (title, price, condition, seller, item link) └── Item detail (images, specifics, availability, description) └── Seller profile (identity, feedback score, positive rate) └── Seller listings (inventory, page by page) └── Seller feedback (buyer comments, ratings) └── Product reviews (review text, rating, author) 

Each layer is a separate API call. Each has its own rate. The mistake teams make is assuming that a "search" returns all of this. It doesn't — search returns the top level only. Enrichment requires additional calls per item.

This isn't a flaw — it's correct data architecture. You shouldn't pay for description data on items you're not interested in. But it means your cost model needs to account for every layer your application touches.

Setup

pip install requests python-dotenv 
# .env SERPENT_API_KEY=your_key_here 
# ebay_client.py import requests import os API_KEY = os.getenv("SERPENT_API_KEY") BASE = "https://apiserpent.com/api/ebay" HEADERS = {"X-API-Key": API_KEY} def get(endpoint, params): r = requests.get(f"{BASE}{endpoint}", params=params, headers=HEADERS, timeout=30) r.raise_for_status() return r.json() 

Operation 1 — Search Listings

GET /api/ebay/search returns a page of listings for a keyword on a specified marketplace.

def search_listings(query, marketplace="EBAY_US", locale="en-US", page=1): """ Returns listing cards: title, price, condition, shipping, seller identity, item link. 10 supported marketplace/locale pairs: EBAY_US/en-US EBAY_GB/en-GB EBAY_DE/de-DE EBAY_AU/en-AU EBAY_IT/it-IT EBAY_FR/fr-FR EBAY_CA/en-CA EBAY_ES/es-ES EBAY_NL/nl-NL EBAY_PL/pl-PL Rate: $0.40/1K calls at Default tier """ return get("/search", { "q": query, "marketplace_id": marketplace, "locale": locale, "page": page }) # Example results = search_listings("vintage camera", "EBAY_DE", "de-DE") for listing in results.get("listings", []): print(listing["title"], listing["price"], listing["currency"]) 

What the response contains:

  • title — listing title as displayed
  • price / currency — displayed price in the marketplace's currency
  • condition — New, Used, Refurbished, For parts, etc.
  • shipping — shipping cost and type if displayed
  • seller — seller username
  • item_url — full item URL (use as item ID for subsequent calls)
  • item_id — eBay item ID

The page trap: a search returns one page. If eBay shows 48 listings on page 1, you get 48 rows. If 12 are sponsored/promoted and you filter them, you have 36. Cost is per page request, not per usable listing. Always measure yield on your actual keywords before budgeting at scale.

Operation 2 — Item Details

GET /api/ebay/item returns structured data for a specific item by ID or URL.

def get_item(item_id, include_description=False): """ Returns price, images, item specifics, availability, seller. Add include_description=1 to get the full seller HTML description. Description calls: $1.50/1K (3.75x the standard rate). If description unavailable but core item exists, standard rate applies. Use include_description only when your pipeline needs it — most price monitoring workflows don't. """ params = {"item_id": item_id} if include_description: params["include_description"] = 1 return get("/item", params) # Price check without description (standard rate) item = get_item("v1|123456789012|0") print(item["price"], item["currency"], item["condition"]) # With full description (description rate) item_full = get_item("v1|123456789012|0", include_description=True) print(item_full.get("description", "")[:200]) 

When to use include_description:

  • Product detail pages that show the seller's own copy
  • Condition verification that requires reading the description text
  • Content analysis pipelines

When NOT to use it:

  • Price monitoring (price is in the core item)
  • Stock tracking (availability is in the core item)
  • Search enrichment loops (you'd pay 3.75× for data you don't use)
  • Operation 3 — Seller Profile

GET /api/ebay/seller returns identity and reputation data for a seller username.

def get_seller_profile(seller_username): """ Returns: seller identity, feedback score, positive feedback rate, profile link. Useful for: trust scoring, seller monitoring, marketplace research, fraud detection signals. Rate: $0.40/1K calls """ return get("/seller", {"seller": seller_username}) profile = get_seller_profile("vintage_camera_shop") print( profile["feedback_score"], profile["positive_feedback_rate"], profile["member_since"] ) 

Operation 4 — Seller Inventory

GET /api/ebay/seller/items reads a seller's public listings, one page at a time.

def get_seller_inventory(seller_username, page=1): """ Returns structured item cards from a seller's active listings. Paginate to collect the full inventory. For large inventories (100+ pages), use a background job when listed in the API catalog — only served pages are charged. Rate: $0.40/1K calls or served pages """ return get("/seller/items", { "seller": seller_username, "page": page }) def collect_all_seller_items(seller_username, max_pages=10): """Collect a seller's full inventory page by page.""" items = [] for page in range(1, max_pages + 1): data = get_seller_inventory(seller_username, page) page_items = data.get("items", []) if not page_items: break items.extend(page_items) print(f"Page {page}: {len(page_items)} items") return items 

Direct calls vs. background jobs: For a seller with 400 listings across 16 pages, a direct loop makes 16 synchronous calls. A background job submits once, handles retries internally, and charges only for pages that complete. If pages 15–16 don't complete, you're not charged for them. For large inventories, background jobs are both cheaper and more reliable.

Operation 5 — Product Reviews

GET /api/ebay/product/reviews returns buyer reviews for an eBay catalog product ID.

def get_product_reviews(product_id): """ Returns: review text, star rating, author username, date. Note: requires an eBay catalog product_id (e-pid), not a listing item_id. These are different identifiers. Rate: $0.40/1K calls """ return get("/product/reviews", {"product_id": product_id}) reviews = get_product_reviews("235190997") for review in reviews.get("reviews", []): print(review["rating"], review["title"], review["date"]) 

The product_id vs item_id distinction: eBay has two identifier systems. An item_id identifies a specific listing from a specific seller. A catalog product ID (often called e-pid or epid) identifies a standardized product in eBay's catalog — the same physical product sold by many sellers. Reviews are attached to the catalog product, not to individual listings. If your workflow starts from search results, you'll need to extract the product ID from the item detail before calling reviews.

Operation 6 — Seller Feedback

GET /api/ebay/seller/feedback returns feedback entries left by buyers.

def get_seller_feedback(seller_username, page=1): """ Returns: feedback entries with buyer username, positive/negative/neutral rating, comment text, date. Useful for: sentiment analysis, seller trust scoring, fraud signals, marketplace research. Rate: $0.40/1K calls """ return get("/seller/feedback", { "seller": seller_username, "page": page }) feedback = get_seller_feedback("vintage_camera_shop") for entry in feedback.get("feedback", []): print(entry["rating"], entry["comment"][:80]) 

A Complete Price Monitoring Pipeline

Here's how the operations compose into a real workflow:

import time from datetime import datetime def run_price_monitor(keywords, marketplaces, output_file="prices.jsonl"): """ For each keyword × marketplace pair: 1. Search listings (discovery) 2. Get item detail for top N results (enrichment) 3. Log price, condition, seller, timestamp Cost at Default tier ($0.40/1K): - 1 search call + N item calls per keyword/market pair - For 10 keywords × 3 markets × top-5 items: 30 search calls + 150 item calls = 180 calls total 180 / 1000 × $0.40 = $0.072 per run """ import json results = [] for keyword in keywords: for marketplace_id, locale in marketplaces: # Layer 1: Search search_data = search_listings(keyword, marketplace_id, locale) listings = search_data.get("listings", [])[:5] # top 5 only for listing in listings: item_id = listing.get("item_id") if not item_id: continue # Layer 2: Item detail (no description — not needed for price monitoring) try: item = get_item(item_id) record = { "timestamp": datetime.utcnow().isoformat(), "keyword": keyword, "marketplace": marketplace_id, "item_id": item_id, "title": listing["title"], "search_price": listing.get("price"), "item_price": item.get("price"), "currency": item.get("currency"), "condition": item.get("condition"), "seller": listing.get("seller"), "availability": item.get("availability"), } results.append(record) # Write incrementally so partial runs aren't lost with open(output_file, "a") as f: f.write(json.dumps(record) + "\n") except Exception as e: print(f"Item {item_id} failed: {e}") time.sleep(0.1) # gentle rate limiting return results # Run it KEYWORDS = ["vintage camera", "film camera", "polaroid camera"] MARKETS = [ ("EBAY_US", "en-US"), ("EBAY_GB", "en-GB"), ("EBAY_DE", "de-DE"), ] data = run_price_monitor(KEYWORDS, MARKETS) print(f"Collected {len(data)} price records") 

Cost Reality Check

At the Default tier ($0.40/1K calls):


For price monitoring at meaningful scale — 100 keywords × 10 markets × 20 items daily — that's roughly 21,000 calls/day, $8.40/day at Default tier, $0.84/day at Scale tier ($0.03/1K after the $500 one-time deposit).

Start free: apiserpent.com/ebay-api — 10 calls, no card, covers the search + item workflow for initial testing.

Full endpoint reference: apiserpent.com/docs#ebay-api

eBay is a trademark of eBay Inc. Serpent API is not affiliated with or endorsed by eBay Inc.