# Seller Finder

Source: https://env.7xmtools.com/api-docs/seller-finder.html

Search for Amazon marketplace sellers in the Keepa database that match your specified criteria — by name and business details, rating history, fulfilment activity, storefront size, Buy Box performance or catalogue profile. The request returns seller ID lists.

GET / POST · 10 + 1 per 100 seller IDs

This request is the seller counterpart of the [Product Finder](https://env.7xmtools.com/api-docs/product-finder.html). It uses the same request grammar — the same paging rules, the same `_gte` / `_lte` range syntax, the same array/exclusion semantics — but it searches the merchant database instead of the product database.

- The request returns only seller ID lists, not [seller objects](https://env.7xmtools.com/api-docs/seller-object.html). Use the [Seller Information](https://env.7xmtools.com/api-docs/seller.html) request to resolve the returned IDs into seller objects (up to 100 per request).
- Each request consumes 10 tokens plus an additional token per 100 seller IDs in the result set.
- A query can return up to 10,000 seller IDs using paging, with a minimum page size of 50. If using paging, initial search results are not cached, so the order of results may be inconsistent between individual pages if there is a delay between consecutive page requests.
- Filters are joined by an **AND** condition.
- For filters allowing multiple entries (all arrays), each specified entry is considered with an **OR** condition, supporting a maximum of 50 entries.
- At least one filter must be specified. A query without any filter criteria is rejected, since it would match the entire merchant database.
- Seller data constantly changes. Running the same query twice may yield different results, as sellers may be misplaced due to recent changes or updates during the query execution.

> **Note:** Unlike the [Product Finder](https://env.7xmtools.com/api-docs/product-finder.html), this request has no `stats` parameter and never returns a [Search Insights Object](https://env.7xmtools.com/api-docs/search-insights-object.html).

> **Note:** All API requests execute regardless of your current token balance, as long as it's positive. Requesting large result sets may cause your token balance to go negative. Use with caution!

## Endpoint

You can choose between an HTTP GET or POST request.

### GET format

```
GET https://api.keepa.com/sellerquery?key=<yourAccessKey>&domain=<domainId>&selection=<sellerQueryJSON>
```

The `<sellerQueryJSON>` must be **URL-encoded** if the GET format is used.

### POST format

```
POST https://api.keepa.com/sellerquery?domain=<domainId>&key=<yourAccessKey>
```

The POST payload must contain the `<sellerQueryJSON>`.

## Parameters

| Parameter | Required | Description |
| --- | --- | --- |
| `key` | required | Your private API key. |
| `domain` | required | Integer value for the Amazon locale you want to access. See the [valid domain IDs](https://env.7xmtools.com/api-docs/seller-finder.html#domain-ids) below. Can be overridden per query with the `domainId` filter, which is the only way to search several marketplaces at once. |
| `selection` | required | The seller query JSON containing all request parameters (see [below](https://env.7xmtools.com/api-docs/seller-finder.html#the-query-json)). URL-encoded as GET parameter, or sent as the POST body. |

### Valid domain IDs

| Domain ID | Locale |
| --- | --- |
| **1** | com |
| **2** | co.uk |
| **3** | de |
| **4** | fr |
| **5** | co.jp |
| **6** | ca |
| **8** | it |
| **9** | es |
| **10** | in |
| **11** | com.mx |
| **12** | com.br |

## Token Cost

- **Base cost:** 10 tokens per request + 1 token per 100 seller IDs in the result set (rounded up).
- A query that matches nothing still costs the 10 base tokens.
- A request rejected as a bad request (invalid or missing query JSON, a rejected paging combination, a filter array that is too large, or a query without filter criteria) does not run and consumes no result-based tokens.

> **Important:** Requesting large lists may consume more tokens than are available in your bucket, causing your balance to go negative. Use with caution.

## The seller query JSON

The `selection` JSON combines paging, sorting and filters. All filters are optional individually, but the query must contain at least one of them.

```json
{
    "page": Integer,
    "perPage": Integer,
    "sort": [ [String, String] ],
    "minMatch": { String: Integer },

    "search": String,
    "activeOnly": Boolean,

    "domainId": Byte[],
    "sellerId": String[],
    "sellerName": String,
    "businessName": String,
    "isAmazon": Boolean,

    "businessType": String[],
    "representative": String[],
    "vatID": String[],
    "tradeNumber": String[],
    "phoneNumber": String[],
    "email": String[],
    "address": String,
    "addressCountry": String[],
    "customerServicesAddressCountry": String[],
    "hasBusinessDetails": Boolean,

    "currentRating_lte": Integer, "currentRating_gte": Integer,
    "currentRatingCount_lte": Integer, "currentRatingCount_gte": Integer,
    "ratingCount30_lte": Integer, "ratingCount30_gte": Integer,
    "ratingCount90_lte": Integer, "ratingCount90_gte": Integer,
    "ratingCount365_lte": Integer, "ratingCount365_gte": Integer,
    "ratingCountLifetime_lte": Integer, "ratingCountLifetime_gte": Integer,
    "positiveRating30_lte": Integer, "positiveRating30_gte": Integer,
    "positiveRating90_lte": Integer, "positiveRating90_gte": Integer,
    "positiveRating365_lte": Integer, "positiveRating365_gte": Integer,
    "positiveRatingLifetime_lte": Integer, "positiveRatingLifetime_gte": Integer,
    "neutralRating30_lte": Integer, "neutralRating30_gte": Integer,
    "neutralRating90_lte": Integer, "neutralRating90_gte": Integer,
    "neutralRating365_lte": Integer, "neutralRating365_gte": Integer,
    "neutralRatingLifetime_lte": Integer, "neutralRatingLifetime_gte": Integer,
    "negativeRating30_lte": Integer, "negativeRating30_gte": Integer,
    "negativeRating90_lte": Integer, "negativeRating90_gte": Integer,
    "negativeRating365_lte": Integer, "negativeRating365_gte": Integer,
    "negativeRatingLifetime_lte": Integer, "negativeRatingLifetime_gte": Integer,
    "ratingCountDelta30_lte": Integer, "ratingCountDelta30_gte": Integer,
    "ratingCountDelta90_lte": Integer, "ratingCountDelta90_gte": Integer,
    "ratingCountDelta365_lte": Integer, "ratingCountDelta365_gte": Integer,
    "ratingDelta30_lte": Integer, "ratingDelta30_gte": Integer,
    "ratingDelta90_lte": Integer, "ratingDelta90_gte": Integer,
    "ratingDelta365_lte": Integer, "ratingDelta365_gte": Integer,
    "lastRatingUpdate_lte": Integer, "lastRatingUpdate_gte": Integer,
    "lastFeedbackDate_lte": Integer, "lastFeedbackDate_gte": Integer,

    "hasFBA": Boolean,
    "isNotFound": Boolean,
    "lastSeenOffer_lte": Integer, "lastSeenOffer_gte": Integer,
    "lastSeenFbaOffer_lte": Integer, "lastSeenFbaOffer_gte": Integer,

    "totalStorefrontAsins_lte": Integer, "totalStorefrontAsins_gte": Integer,

    "avgBuyBoxCompetitors_lte": Integer, "avgBuyBoxCompetitors_gte": Integer,
    "buyBoxNewOwnershipRate_lte": Integer, "buyBoxNewOwnershipRate_gte": Integer,
    "buyBoxUsedOwnershipRate_lte": Integer, "buyBoxUsedOwnershipRate_gte": Integer,

    "rootCategories_include": Long[],
    "rootCategories_exclude": Long[],
    "primaryRootCategory": Long[],
    "brands": String[],
    "primaryBrand": String[],
    "competitorSellerIds": String[],
    "topCompetitorSellerId": String[],
    "primaryRootCategoryProductCount_lte": Integer, "primaryRootCategoryProductCount_gte": Integer,
    "primaryBrandProductCount_lte": Integer, "primaryBrandProductCount_gte": Integer,
    "topCompetitorPercent_lte": Integer, "topCompetitorPercent_gte": Integer,
    "productCountWithAmazonOffer_lte": Integer, "productCountWithAmazonOffer_gte": Integer,
    "avg30SalesRank_lte": Integer, "avg30SalesRank_gte": Integer,

    "trackedSince_lte": Integer, "trackedSince_gte": Integer
}
```

### Paging

*Paging is optional; by default, up to 50 results are provided.*

| Field | Description |
| --- | --- |
| `page` | Most queries have more than 50 results (the minimum page size). To retrieve additional results, iterate the `page` parameter while keeping all other parameters identical. Start with `page` 0 and stop when the response contains fewer than `perPage` results. Each response also includes the `totalResults` field, indicating the number of matched sellers. When requesting a `page` other than 0, `perPage` × `page` must stay below 10,000. Example: `0` |
| `perPage` | Specifies the number of results to retrieve per page. The default is 50 and the minimum is 50; an explicitly supplied `0` is treated as 100. If `page` is **0**, `perPage` can be as large as 10,000. If a `page` other than 0 is requested, the combination of `page` and `perPage` must not exceed 10,000 results; a page whose window would reach past 10,000 is shortened, so ask for the exact page size you want rather than relying on the last page. |

### Sorting

*Sorting is optional; by default, results are sorted descending by `currentRatingCount` — the largest sellers first. If the query contains a `search` term, results are sorted by relevance first and by `currentRatingCount` only as a tie-breaker.*

`sort` can include up to three sorting criteria. Use a two-dimensional array where each entry is in the format `[fieldName, sortDirection]`:

- **fieldName**: any filter field from the lists below. The `fieldName` must not include `_lte` or `_gte`.
- **sortDirection**: use `"asc"` for ascending or `"desc"` for descending. Any other value is treated as `"desc"`.
- Sellers for which the sort field has no value are always placed last, in both directions.

```json
"sort": [ ["currentRatingCount", "desc"] ]
```

> **Note:** An unrecognised sort field does **not** produce an error — the whole `sort` is discarded and the default sort applies instead. The free-text fields `address` and `customerServicesAddress` cannot be sorted on and fall back the same way; `sellerName` and `businessName` can be sorted on and are ordered by their exact (unanalyzed, lowercased) value.

### Filter basics

The following fields act as filters. Only sellers that **exactly** match all filters will be returned by the query. All string filters are case insensitive — every term is lowercased before it is matched, and the stored values are lowercase too. Filters ending in `_gte` restrict the output to values "Greater than or equal" to the specified value, while `_lte` means "Less than or equal". Supplying the same value for both bounds of a field turns it into an exact match.

String array filters can be used as exclusion filters by prefixing an entry with `-` or `✜`. Excluded and included entries can be mixed within one array.

```json
"addressCountry": ["cn", "hk", "-de"]
```

Boolean filters match sellers that carry the flag when set to `true`, and sellers that do *not* carry it when set to `false`.

> **Note on missing values:** A seller for which Keepa has no value for a field is not indexed for that field at all, so it never matches a filter on it — not even a wide range. This is deliberate: "no rating yet" and "a rating of 0%" must not answer the same query.

#### minMatch — K-of-N matching on array filters

Entries within one array filter are normally joined by **OR**: any one of them may match. `minMatch` raises that bar per field, as a map of filter name to the number of entries that must match. Setting it equal to the number of entries turns that filter into an **AND**.

```json
"minMatch": { "brands": 2 }
```

Here a seller must carry at least two of the listed `brands`. Values are clamped to the number of entries actually supplied for that filter, and exclusion entries do not count towards it.

### Free-text search

`search` takes a single free-text term and matches it against every merchant field a human would type into a lookup box. It is what backs the seller lookup on the Keepa website. A seller is a hit if **any one** of the following matches:

| Matched field | How it is matched |
| --- | --- |
| `sellerName`, `businessName`, `address` | As analyzed text, type-ahead style: every word of the term but the last must match a whole word, and the last word matches as a prefix. All words must match, and all of them must land in the *same* field. The words need not be adjacent or in order. |
| `sellerId`, `vatID`, `tradeNumber`, `email`, `representative` | As an exact term — these hold identifiers, and half a VAT ID is not a VAT ID. Partial matches do not work here. |

Because all words must land in the same field, a term that mixes a word from the seller name with a word from the business name finds nothing. Typing more narrows the result set rather than widening it. Terms longer than 300 characters are truncated rather than rejected.

`search` combines with the other filters by **AND**: `"search"` together with `"hasFBA": true` requires both.

```json
{ "search": "thrift", "hasFBA": true }
```

### Restricting to active sellers

`activeOnly` (Boolean) restricts the result to merchants that were seen offering something recently. The cutoff is resolved on the server at request time — currently the last **31 days** — so that this filter cannot drift apart from the active-seller counts shown elsewhere, and so a stale client cannot pin an old cutoff.

It is equivalent to setting `lastSeenOffer_gte` to that cutoff yourself. Both may be set at the same time; they constrain the same field, so the tighter bound wins. Setting `activeOnly` to `false` has no effect.

### Identity

| Filter | Description |
| --- | --- |
| `domainId` | Byte array. An explicit list of Amazon locales to search. When set, it **overrides** the `domain` request parameter and is the only way to search several marketplaces in one request. The same merchant is a separate seller per locale. Example: `[1, 2, 3]` |
| `sellerId` | String array. Seller IDs. Example: `["A2L77EE7U53NWQ"]` |
| `sellerName` | Free text over the seller's public display name. Works on a keyword basis: all specified keywords must be contained, in any order. Wrap the value in double quotes for a phrase match. Values longer than 300 characters are truncated. Example: `"warehouse deals"` |
| `businessName` | Free text over the legal business name from the seller information block, which is often unrelated to `sellerName`. Same keyword/phrase behaviour as `sellerName`. |
| `isAmazon` | Boolean. Whether the seller is the marketplace's own Amazon seller account. Example: `false` |

### Business & legal details

These come from the seller information block Amazon publishes on the seller profile page. They are only available for sellers where Keepa was able to parse that block.

| Filter | Description |
| --- | --- |
| `businessType` | String array. The declared legal form of the business. Example: `["privately owned"]` |
| `representative` | String array. The named legal representative of the business. |
| `vatID` | String array. VAT identification numbers. |
| `tradeNumber` | String array. Trade register / company registration numbers. |
| `phoneNumber` | String array. Business phone numbers. |
| `email` | String array. Business e-mail addresses. |
| `address` | Free text over the seller's business address, with all address lines joined into one string. Same keyword/phrase behaviour as `sellerName`. Example: `shenzhen` |
| `addressCountry` | String array. Country of the business address as an ISO 3166 alpha-2 code. Example: `["cn", "hk"]` |
| `customerServicesAddressCountry` | String array. Country of the separate customer services address, where the seller declares one. Same format as `addressCountry`. |
| `hasBusinessDetails` | Boolean. Whether any part of the seller information block could be parsed at all. A cheap way to restrict a query to sellers with legal details on file. |

### Ratings & feedback

| Filter | Description |
| --- | --- |
| `currentRating` `[_lte, _gte]` | The seller's current feedback percentage, 0 to 100. Example: `95` |
| `currentRatingCount` `[_lte, _gte]` | The seller's current lifetime feedback count. Example: `1000` |
| `ratingCount` `[30, 90, 365, Lifetime]` `[_lte, _gte]` | Number of ratings the seller received in the last 30 / 90 / 365 days, or over their lifetime, as reported by Amazon. Example: `ratingCount90_gte` `50` |
| `positiveRating` `[30, 90, 365, Lifetime]` `[_lte, _gte]` | Percentage of positive ratings over the respective window, 0 to 100. |
| `neutralRating` `[30, 90, 365, Lifetime]` `[_lte, _gte]` | Percentage of neutral ratings over the respective window, 0 to 100. |
| `negativeRating` `[30, 90, 365, Lifetime]` `[_lte, _gte]` | Percentage of negative ratings over the respective window, 0 to 100. |
| `ratingCountDelta` `[30, 90, 365]` `[_lte, _gte]` | Growth of the lifetime feedback count over the last 30 / 90 / 365 days, derived from the seller's rating count history. A seller whose history does not reach back over the full window has no value here, so a young seller is never reported as having gained its entire feedback count in the window. Example: `ratingCountDelta30_gte` `100` |
| `ratingDelta` `[30, 90, 365]` `[_lte, _gte]` | Change of the current feedback percentage over the last 30 / 90 / 365 days, in percentage points. Negative values are drops. Same "not enough history" rule as `ratingCountDelta`. Example: `ratingDelta90_lte` `-5` |
| `lastRatingUpdate` `[_lte, _gte]` | When Keepa last updated this seller's rating data, in [Keepa Time minutes](https://env.7xmtools.com/api-docs/seller-finder.html#keepa-time-minutes). |
| `lastFeedbackDate` `[_lte, _gte]` | Date of the newest feedback entry Keepa has recorded for this seller — the last time a buyer actually rated them, in [Keepa Time minutes](https://env.7xmtools.com/api-docs/seller-finder.html#keepa-time-minutes). |

### Fulfilment & offer activity

| Filter | Description |
| --- | --- |
| `hasFBA` | Boolean. Whether the seller was seen using Fulfillment by Amazon. Example: `true` |
| `lastSeenOffer` `[_lte, _gte]` | The last time Keepa saw any offer of this seller, in [Keepa Time minutes](https://env.7xmtools.com/api-docs/seller-finder.html#keepa-time-minutes). See also [`activeOnly`](https://env.7xmtools.com/api-docs/seller-finder.html#active-only). |
| `lastSeenFbaOffer` `[_lte, _gte]` | The last time Keepa saw an FBA offer of this seller, in [Keepa Time minutes](https://env.7xmtools.com/api-docs/seller-finder.html#keepa-time-minutes). |
| `isNotFound` | Boolean. Whether Amazon returns a 404 for the seller's profile page — the seller is tracked but no longer exists. **Such sellers are excluded from every query by default.** Set this filter explicitly (to `true` to search only them, or to `false` to keep the default exclusion in a query that documents it) to take control of that. |

### Storefront scale

| Filter | Description |
| --- | --- |
| `totalStorefrontAsins` `[_lte, _gte]` | The number of verified listings of this seller — the same value the "Verified Listings" column of a seller export reports. Where Keepa has no verified count it falls back to the sum over the seller's tracked root categories, which is bounded by their top 10 categories and therefore understates sellers with a very broad catalogue. Example: `1000` |

### Buy Box performance

| Filter | Description |
| --- | --- |
| `avgBuyBoxCompetitors` `[_lte, _gte]` | The average number of sellers this merchant competes with for the Buy Box across their listings. Example: `3` |
| `buyBoxNewOwnershipRate` `[_lte, _gte]` | Percentage of the time the seller holds the New Buy Box across their listings, 0 to 100. Example: `50` |
| `buyBoxUsedOwnershipRate` `[_lte, _gte]` | Percentage of the time the seller holds the Used Buy Box across their listings, 0 to 100. |

### Catalogue profile

These describe what a seller sells, derived from the products Keepa has seen them offer. Categories and brands are tracked for the seller's top 10 by product count; competitors for the top 10 by listing overlap.

| Filter | Description |
| --- | --- |
| `rootCategories_include` | Only include sellers active in these root categories. Array with up to 50 [category node ids](https://env.7xmtools.com/api-docs/category-object.html). Example: `[3167641]` |
| `rootCategories_exclude` | Exclude sellers active in these root categories. Array with up to 50 [category node ids](https://env.7xmtools.com/api-docs/category-object.html). |
| `primaryRootCategory` | Array with up to 50 [category node ids](https://env.7xmtools.com/api-docs/category-object.html). The seller's single largest root category by product count. |
| `primaryRootCategoryProductCount` `[_lte, _gte]` | How many products the seller lists in that primary root category. |
| `brands` | String array. Brands the seller carries. Example: `["canon"]` |
| `primaryBrand` | String array. The seller's single largest brand by product count. |
| `primaryBrandProductCount` `[_lte, _gte]` | How many products the seller lists under that primary brand. |
| `competitorSellerIds` | String array. Seller IDs that share the most listings with this seller. Use it to find the competitors of a given merchant. Example: `["A2L77EE7U53NWQ"]` |
| `topCompetitorSellerId` | String array. The single seller ID with the largest listing overlap. |
| `topCompetitorPercent` `[_lte, _gte]` | Share of the seller's listings that the top competitor also offers, 0 to 100. |
| `productCountWithAmazonOffer` `[_lte, _gte]` | How many of the seller's tracked products also carry an Amazon offer — how much this seller competes with Amazon directly. |
| `avg30SalesRank` `[_lte, _gte]` | The product-count weighted mean 30-day sales rank across the seller's tracked categories. Lower is better selling. Example: `50000` |

### Tracking time

| Filter | Description |
| --- | --- |
| `trackedSince` `[_lte, _gte]` | When Keepa started tracking this seller, in [Keepa Time minutes](https://env.7xmtools.com/api-docs/seller-finder.html#keepa-time-minutes). Example: `3411319` |

## Keepa Time Minutes

Time format used for all timestamps. To convert to an uncompressed Unix epoch time:

- **For milliseconds:** `(keepaTime + 21564000) * 60000`
- **For seconds:** `(keepaTime + 21564000) * 60`

## Errors

A rejected request answers with HTTP **400** and an `error` field. The possible messages are:

| Message | Cause |
| --- | --- |
| `The sellerQueryJSON is missing or invalid.` | No `selection` parameter and no request body, or the payload does not parse as a seller query JSON. |
| `combination of perPage and page exeeds limit or is too small` | `perPage` below 50, a negative `page`, or a `perPage`/`page` combination that reaches past 10,000 results. |
| `too many sort directions, limit is 3.` | More than three entries in `sort`. |
| `too many filters. maximum of 50 entries per filter are supported.` | More than 50 category node ids in `rootCategories_include`, `rootCategories_exclude` or `primaryRootCategory`. |
| `too many entries in filter string array, limit is 50 per array.` | More than 50 entries in any string array filter. |
| `the query has no filter criteria.` | The query contains no usable filter, or the `domain` parameter is not a valid marketplace and the query carries no `domainId` of its own. An unconstrained query would return the entire merchant database and is rejected rather than executed. |

```json
{
  "timestamp": 1783382461000,
  "tokensLeft": 248,
  "refillIn": 31000,
  "refillRate": 5,
  "tokenFlowReduction": 0.0,
  "tokensConsumed": 0,
  "processingTimeInMs": 3,
  "error": {
    "type": "invalidParameter",
    "message": "the query has no filter criteria."
  }
}
```

## Response

```json
{
    "sellerIdList": String array,
    "totalResults": Integer
}
```

| Field | Description |
| --- | --- |
| `sellerIdList` | Ordered array with the result seller IDs. Pass them to the [Seller Information](https://env.7xmtools.com/api-docs/seller.html) request (up to 100 per call) to retrieve the matching [seller objects](https://env.7xmtools.com/api-docs/seller-object.html). |
| `totalResults` | Count of all matched sellers, across all pages. |

## Examples

### Example query

Find sellers on amazon.de with a business address in China or Hong Kong, at least 1,000 lifetime ratings, that were seen offering something recently — largest first, 100 results per page:

```json
{
  "addressCountry": ["cn", "hk"],
  "currentRatingCount_gte": 1000,
  "activeOnly": true,
  "sort": [["currentRatingCount", "desc"]],
  "perPage": 100,
  "page": 0
}
```

> **Tip:** The returned `sellerIdList` contains IDs only. Feed them to the [Seller Information](https://env.7xmtools.com/api-docs/seller.html) request in batches of up to 100 to get the full [seller objects](https://env.7xmtools.com/api-docs/seller-object.html).

**Java**

```java
KeepaAPI api = new KeepaAPI("YOUR_API_KEY");
SellerFinderRequest finder = new SellerFinderRequest();
finder.addressCountry = new String[]{"cn", "hk"};
finder.currentRatingCount_gte = 1000;
finder.activeOnly = true;
finder.sort = new String[][]{{"currentRatingCount", "desc"}};
finder.perPage = 100;
finder.page = 0;
api.sendRequest(Request.getSellerFinderRequest(AmazonLocale.DE, finder))
    .done(result -> {
        System.out.println(result.sellerIdList.length + " seller IDs on this page");
    })
    .fail(failure -> System.out.println(failure));
```

**PHP**

```php
<?php
$selection = [
    "addressCountry" => ["cn", "hk"],
    "currentRatingCount_gte" => 1000,
    "activeOnly" => true,
    "sort" => [["currentRatingCount", "desc"]],
    "perPage" => 100,
    "page" => 0,
];
$url = "https://api.keepa.com/sellerquery?key=YOUR_API_KEY&domain=3";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($selection));
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $data["totalResults"] . " matches";
print_r($data["sellerIdList"]);
```

**Python**

```python
import requests

selection = {
    "addressCountry": ["cn", "hk"],
    "currentRatingCount_gte": 1000,
    "activeOnly": True,
    "sort": [["currentRatingCount", "desc"]],
    "perPage": 100,
    "page": 0,
}
r = requests.post(
    "https://api.keepa.com/sellerquery",
    params={"domain": 3, "key": "YOUR_API_KEY"},
    json=selection,
)
data = r.json()
print(data["totalResults"], "matches")
print(data["sellerIdList"][:10])
```

**Node.js**

```javascript
const selection = {
  addressCountry: ["cn", "hk"],
  currentRatingCount_gte: 1000,
  activeOnly: true,
  sort: [["currentRatingCount", "desc"]],
  perPage: 100,
  page: 0,
};
const res = await fetch("https://api.keepa.com/sellerquery?domain=3&key=YOUR_API_KEY", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(selection),
});
const data = await res.json();
console.log(data.totalResults, "matches");
console.log(data.sellerIdList.slice(0, 10));
```

**cURL (GET)**

```bash
# GET: the selection JSON must be URL-encoded (--data-urlencode does this)
curl -s -G "https://api.keepa.com/sellerquery" \
  --data-urlencode "key=YOUR_API_KEY" \
  --data-urlencode "domain=3" \
  --data-urlencode 'selection={"addressCountry":["cn","hk"],"currentRatingCount_gte":1000,"activeOnly":true,"perPage":100,"page":0}'
```

**cURL (POST)**

```bash
# POST: the selection JSON is the request body
curl -s -X POST "https://api.keepa.com/sellerquery?domain=3&key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"addressCountry":["cn","hk"],"currentRatingCount_gte":1000,"activeOnly":true,"perPage":100,"page":0}'
```

### Example: free-text lookup

Look a seller up the way the website's seller search does — one term across name, business name, address and the identifier fields, best match first:

```bash
curl -s -X POST "https://api.keepa.com/sellerquery?domain=1&key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"search":"thriftbooks","activeOnly":true,"perPage":50}'
```

### Example: a seller's competitors

Find the merchants whose catalogue overlaps most with a given seller, restricted to those still active:

```bash
curl -s -X POST "https://api.keepa.com/sellerquery?domain=1&key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"competitorSellerIds":["A2L77EE7U53NWQ"],"activeOnly":true,"sort":[["totalStorefrontAsins","desc"]],"perPage":50}'
```

### Example response

```json
{
  "timestamp": 1783382461000,
  "tokensLeft": 238,
  "refillIn": 31000,
  "refillRate": 5,
  "tokenFlowReduction": 0.0,
  "tokensConsumed": 11,
  "processingTimeInMs": 128,
  "sellerIdList": [
    "A2L77EE7U53NWQ",
    "A3EX3RPFGJNC29",
    "A1X6FK5RDHNB96",
    "AN1VRQENFRJN5",
    "A3DWYIK6Y9EEQB"
  ],
  "totalResults": 4821
}
```

*Response shortened for readability; illustrative values.* The response contains no seller objects and no `searchInsights` field — resolve the IDs through the [Seller Information](https://env.7xmtools.com/api-docs/seller.html) request.
