# eBay active listings

> GET /v1/ebay/listings searches eBay active listings in the US, UK, Canada, Australia, Germany, France, Italy or Spain, with price, condition and sort filters.

```text
GET https://api.soldgraph.com/v1/ebay/listings
```

Search eBay active listings by keyword on eBay US or seven other countries' sites. Each call returns one page, in the order you pick with `sort`. Promoted listings are included, and `promoted` flags them (null on eBay UK page 2 and later, where eBay does not mark them).

Coming from the eBay Browse API? See [eBay Browse API vs Soldgraph](https://soldgraph.com/docs/compare/ebay-browse-api.md).

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `q` | string | Required | Search keywords, 1–200 characters, as you'd type them into the marketplace's search box. Be specific: model, size, grade, edition. |
| `page` | integer, 1–100 | `1` | Source page to fetch. Where an endpoint has `cursor`, pages after 1 also need it. |
| `min_price` | integer, 0–1000000 |  | Lowest price, in whole units of the country's currency (US dollars for `us`). Optional. Must not be more than `max_price`. You can send it without `max_price`. |
| `max_price` | integer, 0–1000000 |  | Highest price, in whole units of the country's currency (US dollars for `us`). Optional. You can send it without `min_price`. |
| `marketplace` | `ebay` | `ebay` | Optional. If sent, it must be `ebay`. |
| `country` | `us`, `uk`, `ca`, `au`, `de`, `fr`, `it` or `es` | `us` | Which eBay site to search: `us` (ebay.com), `uk` (ebay.co.uk), `ca` (ebay.ca), `au` (ebay.com.au), `de` (ebay.de), `fr` (ebay.fr), `it` (ebay.it) or `es` (ebay.es). Results, prices, `min_price` and `max_price` use that site's currency. Optional. |
| `sort` | `best_match`, `newest`, `price_asc` or `ending_soon` | `best_match` | eBay's listing order. Promoted listings are included and flagged. |
| `condition` | One or more of `new`, `open_box`, `refurbished`, `used`, `for_parts`, comma-separated |  | eBay's own condition groups. Send one or more, separated by commas, like `new,open_box`. `new` is Brand New, `open_box` is Open Box or New (Other), `refurbished` is every refurbished grade, `used` is Pre-Owned and `for_parts` is Parts Only. eBay applies the filter. |
| `item_location` | `domestic` or `worldwide` |  | Where sellers are. `domestic` keeps sellers in the country you search; `worldwide` includes every country. Leave it out for the eBay site's own default. On `fr` the default is narrow: send `worldwide` for far more results. |
| `buying_format` | `auction`, `buy_it_now` or `best_offer` |  | Only one kind of listing: `auction`, `buy_it_now` (fixed price, including listings that also take offers) or `best_offer` (listings that take offers). eBay applies the filter. |
| `count` | `40`, `60`, `120` or `200` |  | Rows per page: `200`, `120`, `60` or `40`. Send `200` for the most eBay gives; leaving it out means 40. A search costs one request at any size. Optional. |
| `category_id` | integer, 1–2147483647 |  | eBay numeric category ID, such as `27386` for graphics cards. Keeps only listings in that category. Optional. |

```bash title="cURL"
curl -G https://api.soldgraph.com/v1/ebay/listings \
  -H "Authorization: Bearer $SOLDGRAPH_KEY" \
  --data-urlencode "q=canon ae-1 program" \
  -d page=1 \
  -d count=200
```

```typescript title="TypeScript"
const params = new URLSearchParams({
  q: "canon ae-1 program",
  page: "1",
  count: "200",
});

const res = await fetch(`https://api.soldgraph.com/v1/ebay/listings?${params}`, {
  headers: { Authorization: `Bearer ${process.env.SOLDGRAPH_KEY}` },
});
const data = await res.json();
```

```python title="Python"
import os, requests

res = requests.get(
    "https://api.soldgraph.com/v1/ebay/listings",
    params={"q": "canon ae-1 program", "page": 1, "count": 200},
    headers={"Authorization": f"Bearer {os.environ['SOLDGRAPH_KEY']}"},
)
data = res.json()
```

The first call usually returns **202** and a job to poll. [Search jobs](https://soldgraph.com/docs/api/overview.md#search-jobs) covers polling, retries and pagination.

## Filters

- `condition` takes one or more of eBay's condition groups, separated by commas, like `new,open_box`. The groups are `new` (Brand New), `open_box` (Open Box or New (Other)), `refurbished` (every refurbished grade), `used` (Pre-Owned) and `for_parts` (Parts Only).
- `min_price` and `max_price` are whole units of the site's currency, like dollars on `us` or pounds on `uk`. You can send either one alone.
- `item_location` picks where sellers are: `domestic` for sellers in the country you search, or `worldwide`. Leave it out for the eBay site's own default.
- `buying_format` keeps one kind of listing: `auction`, `buy_it_now` (fixed price, including listings that also take offers) or `best_offer` (listings that take offers).
- `category_id` keeps one eBay category, by its numeric ID, like `27386` for graphics cards.
- To leave a word out, put a minus sign in front of it in `q`, like `q=RX 580 -8GB`.

eBay applies the filters, so `reported_total` counts only matching listings.

## Countries

`country` picks the eBay site. Leave it out for eBay US.

| `country` | eBay site | Currency |
| --- | --- | --- |
| `us` | ebay.com | USD |
| `uk` | ebay.co.uk | GBP |
| `ca` | ebay.ca | CAD |
| `au` | ebay.com.au | AUD |
| `de` | ebay.de | EUR |
| `fr` | ebay.fr | EUR |
| `it` | ebay.it | EUR |
| `es` | ebay.es | EUR |

- Prices, shipping, `min_price` and `max_price` are in that site's currency.
- `link` points to the listing on that site.
- Results are what that eBay site shows its own buyers. They can include listings from sellers in other countries. Send `item_location=domestic` to keep only local sellers.
- eBay France's default seller locations are narrow, so searches there return far fewer results than other sites. Send `item_location=worldwide` for more.
- Text fields are as the site shows them. `condition` and `shipping_text` can be in the local language, like `Gebraucht` or `+ €10.49 de envío`. The `condition` filter works the same way on every site.
- Each country is its own search and costs one request.

## Pages

Start with `page=1`. For the next page, send the same search with `page` set to `next_page` from the last result. eBay pages by number, so there's no cursor.

- When `next_page` is null, you're on the last page. You can request at most 100 pages. A page past the last one comes back complete with no rows and `next_page: null`, and isn't charged.
- A page has 40 regular rows unless you send `count`, plus any promoted listings eBay places among them. `count` can be `40`, `60`, `120` or `200`. A bigger page is still one search and costs one request.
- Keep `count` the same while you page.
- `page_size` is the page size eBay reports. With promoted listings a page can hold a few more rows than that: we saw 214 rows at `count=200`.

## Price summary

`summary` is plain maths over the rows on the page you got: how many show one price, the median asking price, the lowest and the highest.

- Nothing is removed from `data`. Promoted listings are counted like any other row.
- Rows that show a price range, or no readable price, are left out of the maths. `priced_count` says how many rows were used.
- It covers one page. Send a bigger `count` to summarize more rows in one search.

## Example response

```json title="Response"
{
  "request_id": "00000000-0000-4000-8000-000000000001",
  "status": "complete",
  "credits": 1,
  "cached": false,
  "result": {
    "provider": "ebay",
    "country": "us",
    "query": "canon ae-1 program",
    "page": 1,
    "page_size": 200,
    "count": 1,
    "reported_total": 1,
    "next_page": null,
    "next_cursor": null,
    "collected_at": "2026-09-23T14:02:11Z",
    "schema_version": 2,
    "completeness": "provider_page_only",
    "summary": {
      "priced_count": 1,
      "currency": "USD",
      "median": 189,
      "low": 189,
      "high": 189,
      "p25": 189,
      "p75": 189
    },
    "data": [
      {
        "id": "123456789012",
        "title": "Example eBay listing",
        "link": "https://www.ebay.com/itm/123456789012",
        "promoted": false,
        "format": "fixed_price",
        "displayed_price": {
          "amount": 189,
          "currency": "USD"
        },
        "displayed_price_text": "$189.00",
        "displayed_price_range": null,
        "displayed_shipping": {
          "amount": 0,
          "currency": "USD"
        },
        "shipping_text": "Free delivery",
        "condition": "Pre-Owned",
        "bid_count": null,
        "ends_at": null,
        "best_offer": false,
        "seller_text": "filmcamerashop (1,204) 100%",
        "location_text": null,
        "image": "https://i.ebayimg.com/images/g/example/s-l500.jpg"
      }
    ],
    "field_notes": "Listings are in the marketplace's order; promoted listings are included and flagged. Fields that could not be read are null."
  }
}
```

| Field | Type | Description |
| --- | --- | --- |
| `request_id` | string | ID of this request. Poll it at `/v1/jobs/{request_id}`. |
| `status` | string | `pending`, `complete` or `failed`. Always check it, even on HTTP 200. |
| `credits` | integer | Requests charged: 1 when complete, 0 for a page past the last one, while pending, or when failed. |
| `cached` | boolean | True when the result came from the 15-minute cache. |
| `poll_url` | string | Only while pending. A path like `/v1/jobs/{id}`: join it to `https://api.soldgraph.com`, not to the `/v1` base URL. |
| `error.code` | string | Only when failed. See [failed job codes](https://soldgraph.com/docs/api/errors.md#failed-job-codes). |
| `error.message` | string | Only when failed. What the code means, in plain words. |
| `result` | object | Only when complete. One source page from the marketplace. |
| `result.provider` | string | Marketplace ID, like `ebay` or `poshmark`. |
| `result.country` | string | The country searched: `us`, or on eBay the country you sent. |
| `result.query` | string | The `q` you sent, with extra spaces removed. |
| `result.page` | integer | The page you asked for. |
| `result.count` | integer | Rows in `result.data` on this page. |
| `result.reported_total` | integer | Total matches the marketplace reports for the search. It may be rounded or capped. |
| `result.next_page` | integer \| null | Send this as `page` to get the next page. Null on the last page, and on page 100, the deepest page served. |
| `result.collected_at` | string | When we collected the page, as an ISO 8601 timestamp. |
| `result.schema_version` | integer | Version of the result's shape for that marketplace: `1` or `2`. It only rises when a field changes meaning. |
| `result.completeness` | string | `provider_page_only`: one page as the marketplace served it, not a full history. TCGplayer recent sales say `recent_sample_only`. |
| `result.field_notes` | string | Plain-text notes on how to read this page's fields. |
| `result.next_cursor` | null | Always null. eBay pages by number: send `page=next_page` for the next page. |
| `result.page_size` | integer | Rows per page, as eBay reports it. |
| `result.summary` | object | Price maths over the rows on this page: `priced_count`, `currency`, `median`, `low`, `high`. No row is removed from `data`. Rows with a price range or an unread price are left out of the maths. |
| `result.data[].id` | string | The marketplace's listing ID. |
| `result.data[].title` | string \| null | Listing title as shown. |
| `result.data[].link` | string | URL of the listing on the eBay site you searched, like `https://www.ebay.co.uk/itm/…`. |
| `result.data[].promoted` | boolean | True for a sponsored placement. |
| `result.data[].format` | string | `auction` when the listing shows bids or an end time, otherwise `fixed_price`. |
| `result.data[].displayed_price` | object \| null | `{ amount, currency }` parsed from the price shown: the asking price or current bid. Null if it couldn't be read. Null when eBay shows a price range for a multi-variation listing ("$247.00 to $911.00"): the amount wouldn't say which variant. The range is in `displayed_price_range` and `displayed_price_text`. |
| `result.data[].displayed_price_text` | string \| null | The price text as shown, like `$189.00`, `£124.46` or `€230.00`. |
| `result.data[].displayed_price_range` | object \| null | `{ low, high, currency }` when eBay shows a price range for a multi-variation listing ("$247.00 to $911.00"). Null otherwise. `displayed_price` is null for these rows, so they stay out of the summary maths. |
| `result.data[].displayed_shipping` | object \| null | `{ amount, currency }` read from exact shipping text, in the site's currency, like `+$9.99 delivery`, `+£3.92 delivery` or `+€6.99 Lieferung`. Free shipping is 0, in every country's wording. Estimates and `Shipping not specified` are null. |
| `result.data[].shipping_text` | string \| null | Shipping text as shown, like `+$9.99 delivery`, `Free delivery` or `+ €10.49 de envío`. |
| `result.data[].condition` | string \| null | eBay's condition text as shown, in the site's language, like `Pre-Owned`, `Pre-owned` or `Gebraucht`. To filter by condition in any language, use `condition`. |
| `result.data[].bid_count` | integer \| null | Number of bids, for auctions. |
| `result.data[].ends_at` | string \| null | Auction end time, ISO 8601 UTC. |
| `result.data[].best_offer` | boolean | True when the seller accepts Best Offers. |
| `result.data[].seller_text` | string \| null | Seller text as eBay shows it: username, feedback count and positive percentage, e.g. `clutch_supply (1,325) 99.7%`. |
| `result.data[].location_text` | string \| null | Item location text as shown. |
| `result.data[].image` | string \| null | Image URL on `i.ebayimg.com`. |

`displayed_price` is the asking price or current bid that eBay shows. Fields we can't read are null.

- `displayed_shipping` is read only from exact text like `+$9.99 delivery` or `+£3.92 delivery`, in the site's currency. Free shipping is 0, however the site words it. Estimates and `Shipping not specified` are null.
- `condition` is eBay's own text in the site's language, like `Pre-Owned` or `Gebraucht`.
