# Browsing Deals

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

Find products that recently changed and match your search criteria. A deal query is a JSON object sent via GET or POST; each request returns up to 150 deals, and paging lets a single query provide up to 10,000 ASINs.

GET · POST · 5 tokens per request (up to 150 deals)

By accessing our [deals](https://env.7xmtools.com/deals), you can find products that recently changed and match your search criteria. A single request will return a maximum of **150** deals. A query can provide up to **10,000** ASINs using paging. We recommend trying out our [deals page](https://env.7xmtools.com/deals) first to familiarize yourself with the options and results before reading this documentation.

> **Note:** Our deals only provide products that were updated within the last **12 hours**.

## Endpoint

You can choose between an HTTP GET or POST request. Both take the same `queryJSON` object, described below.

### GET format

```
GET https://api.keepa.com/deal?key=<yourAccessKey>&selection=<queryJSON>
```

| Parameter | Required | Description |
| --- | --- | --- |
| `key` | required | Your private API key. |
| `selection` | required | The query JSON contains all request parameters. It must be **URL-encoded** if the GET format is used. |

### POST format

```
POST https://api.keepa.com/deal?key=<yourAccessKey>
```

| Parameter | Required | Description |
| --- | --- | --- |
| `key` | required | Your private API key. |
| POST payload | required | Must contain the `queryJSON` (no URL encoding needed). |

> **Tip:** To quickly get a valid `queryJSON`, there is a link on the [deals page](https://env.7xmtools.com/deals) below the filters that generates this JSON for the currently active selection.

## The queryJSON Object

The query JSON contains all request parameters. Its full structure:

```json
{
  "page": Integer,
  "domainId": Integer,
  "excludeCategories": [Long],
  "includeCategories": [Long],
  "priceTypes": [Integer],
  "deltaRange": [Integer],
  "deltaPercentRange": [Integer],
  "deltaLastRange": [Integer],
  "salesRankRange": [Integer],
  "currentRange": [Integer],
  "minRating": Integer,
  "isLowest": Boolean,
  "isLowest90": Boolean,
  "isLowestOffer": Boolean,
  "isHighest": Boolean,
  "isOutOfStock": Boolean,
  "isBackInStock": Boolean,
  "titleSearch": String,
  "isRangeEnabled": Boolean,
  "isFilterEnabled": Boolean,
  "hasReviews": Boolean,
  "filterErotic": Boolean,
  "singleVariation": Boolean,
  "isRisers": Boolean,
  "isPrimeExclusive": Boolean,
  "mustHaveAmazonOffer": Boolean,
  "mustNotHaveAmazonOffer": Boolean,
  "warehouseConditions": [Integer],
  "material": [String],
  "type": [String],
  "manufacturer": [String],
  "brand": [String],
  "model": [String],
  "color": [String],
  "size": [String],
  "unitType": [String],
  "scent": [String],
  "itemForm": [String],
  "pattern": [String],
  "style": [String],
  "itemTypeKeyword": [String],
  "targetAudienceKeyword": [String],
  "edition": [String],
  "format": [String],
  "author": [String],
  "binding": [String],
  "languages": [String],
  "brandStoreName": [String],
  "brandStoreUrlName": [String],
  "websiteDisplayGroup": [String],
  "websiteDisplayGroupName": [String],
  "salesRankDisplayGroup": [String],
  "sortType": Integer,
  "dateRange": Integer
}
```

## Parameters

### Core parameters

| Parameter | Required | Description |
| --- | --- | --- |
| `page` | optional | Most deal queries have more than 150 results (the maximum page size). To browse all deals found by a query (up to the limit of **10,000**), iterate the `page` parameter while keeping all other parameters identical. Start with `page=0` and stop when the response contains fewer than 150 results.<br>Example: `"page": 0` |
| `domainId` | required | The `domainId` of the Amazon locale to retrieve deals for. Not optional. See the domain ID table below for valid values. |
| `priceTypes` | required | Determines the deal type. Not optional: exactly one price type must be specified. Though it is an integer array, it can contain **only one entry** — multiple types per query are not supported. Only the price types listed below carry deal data; any other value is rejected as an invalid `priceTypes`.<br>Example: `"priceTypes": [0]` |
| `dateRange` | optional | Our deals are divided into different sets, determined by the time interval in which the product changed. The shorter the interval, the more recent the change, which is good for significant price drops but may miss slow incremental drops. See the interval table below for valid values.<br>Example: `"dateRange": 0` |

#### Valid `domainId` values

| 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 |

#### Valid `priceTypes` values

| Value | Price Type |
| --- | --- |
| **0** | AMAZON: Amazon price |
| **1** | NEW: Marketplace New price |
| **2** | USED: Marketplace Used price |
| **3** | SALES: Sales Rank |
| **5** | COLLECTIBLE: Collectible price |
| **6** | REFURBISHED: Refurbished price |
| **7** | NEW\_FBM\_SHIPPING: New FBM with shipping |
| **8** | LIGHTNING\_DEAL: Lightning Deal price |
| **9** | WAREHOUSE: Amazon Warehouse price |
| **10** | NEW\_FBA: New FBA price |
| **18** | BUY\_BOX\_SHIPPING: New Buy Box with shipping |
| **19** | USED\_NEW\_SHIPPING: Used - Like New with shipping |
| **20** | USED\_VERY\_GOOD\_SHIPPING: Used - Very Good with shipping |
| **21** | USED\_GOOD\_SHIPPING: Used - Good with shipping |
| **22** | USED\_ACCEPTABLE\_SHIPPING: Used - Acceptable with shipping |
| **27** | REFURBISHED\_SHIPPING: Refurbished with shipping |
| **32** | BUY\_BOX\_USED\_SHIPPING: Used Buy Box with shipping |
| **33** | PRIME\_EXCL: Prime Exclusive Price |

> **Note (Lightning Deals, Prime Exclusive, and Warehouse Deals):** The `deltaLast`, `delta` and `deltaPercent` entries for these price types are calculated with the Amazon or New price as the reference price (instead of the same price type’s previous price).

#### Valid `dateRange` values

| Value | Interval |
| --- | --- |
| **0** | Day (last 24 hours) |
| **1** | Week (last 7 days) |
| **2** | Month (last 31 days) |
| **3** | 3 Months (last 90 days) |

### Filter options

| Parameter | Required | Description |
| --- | --- | --- |
| `isFilterEnabled` | optional | Switch to enable the filter options.<br>Example: `"isFilterEnabled": true` |
| `excludeCategories` | optional | Used to exclude products listed in these categories. If it’s a subcategory, the product must be **directly** listed in this category; products in child categories of the specified ones will not be excluded unless it’s a root category. Array with up to **500** [category node IDs](https://env.7xmtools.com/api-docs/category-object.html).<br>Example: `"excludeCategories": [77028031, 186606]` |
| `includeCategories` | optional | Used to include only products listed in these categories. Same rules as `excludeCategories`.<br>Example: `"includeCategories": [3010075031, 12950651, 355007011]` |
| `minRating` | optional | Limit to products with a minimum rating. A rating is an integer from **0** to **50** (e.g. 45 = 4.5 stars). If `-1`, the filter is inactive.<br>Example: `"minRating": 20` (minimum rating of 2 stars) |
| `isLowest` | optional | Include only products for which the specified price type is at its lowest value (since tracking began).<br>Example: `"isLowest": true` |
| `isLowest90` | optional | Include only products for which the specified price type is at its lowest value in the past 90 days.<br>Example: `"isLowest90": true` |
| `isLowestOffer` | optional | Include only products if the selected price type is the lowest of all New offers (applicable to Amazon and Marketplace New).<br>Example: `"isLowestOffer": true` |
| `isHighest` | optional | Include only products for which the specified price type is at its highest value (since tracking began).<br>Example: `"isHighest": true` |
| `isOutOfStock` | optional | Include only products that were available to order within the last 24 hours and are now out of stock.<br>Example: `"isOutOfStock": true` |
| `isBackInStock` | optional | Include only products that were previously out of stock and have returned to stock within the last 24 hours.<br>Example: `"isBackInStock": true` |
| `hasReviews` | optional | If `true`, exclude all products with no reviews. If `false`, the filter is inactive.<br>Example: `"hasReviews": false` |
| `filterErotic` | optional | Exclude all products listed as adult items.<br>Example: `"filterErotic": false` |
| `singleVariation` | optional | Provide only a single variation if multiple match the query. The one provided is randomly selected.<br>Example: `"singleVariation": true` |
| `isRisers` | optional | Include only products whose price has been rising over the chosen `dateRange` interval.<br>Example: `"isRisers": true` |
| `isPrimeExclusive` | optional | Include only products flagged as Prime Exclusive.<br>Example: `"isPrimeExclusive": true` |
| `mustHaveAmazonOffer` | optional | Include only products that currently have an offer sold and fulfilled by Amazon.<br>Example: `"mustHaveAmazonOffer": true` |
| `mustNotHaveAmazonOffer` | optional | Include only products that currently have no offer sold and fulfilled by Amazon.<br>Example: `"mustNotHaveAmazonOffer": true` |
| `warehouseConditions` | optional | Include only products available under the specified Amazon Warehouse conditions. Use an array of integer condition codes (e.g. 1 = New, 2 = Used - Like New, 3 = Used - Very Good, 24 = Used - Good, 5 = Used - Acceptable).<br>Example: `"warehouseConditions": [1, 2]` |

#### Product attribute filters

These filters match products by their listing attributes. Each is an array of strings; the examples below show typical values.

| Parameter | Required | Description |
| --- | --- | --- |
| `material` | optional | Include only products made of the specified material (e.g. “cotton”).<br>Example: `"material": ["cotton"]` |
| `type` | optional | Include only products matching the specified type (e.g. “shirt”, “dress”). |
| `manufacturer` | optional | Include only products from the specified manufacturer. |
| `brand` | optional | Include only products from the specified brand. |
| `model` | optional | Include only products matching the specified model identifier. |
| `color` | optional | Include only products matching the specified color attribute. |
| `size` | optional | Include only products matching the specified size (e.g. “small”, “one size”). |
| `unitType` | optional | Include only products with the specified unit type (e.g. “count”, “ounce”). |
| `scent` | optional | Include only products with the specified scent (e.g. “lavender”, “citrus”). |
| `itemForm` | optional | Include only products matching the specified item form (e.g. “liquid”, “sheet”). |
| `pattern` | optional | Include only products matching the specified pattern (e.g. “striped”, “solid”). |
| `style` | optional | Include only products matching the specified style attribute (e.g. “modern”, “vintage”). |
| `itemTypeKeyword` | optional | Include only products matching the specified item type keyword (custom search term, e.g. “books”, “prints”). |
| `targetAudienceKeyword` | optional | Include only products targeting the specified audience (e.g. “kids”, “professional”). |
| `edition` | optional | Include only products matching the specified edition (e.g. “first edition”, “standard edition”). |
| `format` | optional | Include only products in the specified format (e.g. “kindle ebook”, “import”, “dvd”). |
| `author` | optional | Include only products by the specified author (applicable to books, music, etc.). |
| `binding` | optional | Include only products with the specified binding type (e.g. “paperback”). |
| `languages` | optional | Include only products available in the specified languages. Use an array of language names. |
| `brandStoreName` | optional | Include only products sold under the specified brand store name on Amazon. |
| `brandStoreUrlName` | optional | Include only products sold under the specified URL-friendly brand store identifier. |
| `websiteDisplayGroup` | optional | Include only products in the specified website display group. |
| `websiteDisplayGroupName` | optional | Include only products in the specified website display group name (a more user-friendly label). |
| `salesRankDisplayGroup` | optional | Include only products belonging to the specified sales rank display group (e.g. “fashion\_display\_on\_website”). |

### Range options

All range options are integer arrays with two entries: `[min, max]`.

| Parameter | Required | Description |
| --- | --- | --- |
| `isRangeEnabled` | optional | Switch to enable the range options.<br>Example: `"isRangeEnabled": true` |
| `currentRange` | optional | Limit the range of the current value of the price type.<br>Example: `"currentRange": [105, 50000]` (min price $1.05, max price $500) |
| `deltaRange` | optional | Limit the range of the difference between the weighted average value and the current value over the chosen `dateRange` interval.<br>Example: `"deltaRange": [0, 999]` (max difference of $9.99) |
| `deltaPercentRange` | optional | Same as `deltaRange`, but in percent. Minimum percent is **10%**; for Sales Rank, it is **80%**.<br>Example: `"deltaPercentRange": [30, 80]` (between 30% and 80%) |
| `deltaLastRange` | optional | Limit the range of the absolute difference between the previous value and the current one.<br>Example: `"deltaLastRange": [100, 500]` (last change between $1 and $5 price decrease) |
| `salesRankRange` | optional | Limit the Sales Rank range of the product. Identical to `currentRange` if the price type is set to Sales Rank. If you want to keep the upper bound open, you can specify `-1` (which translates to the maximum integer value).<br>**Important:** once this range option is used, all products with no Sales Rank will be excluded. Set it to `null` or leave it out to not use it.<br>Examples: `"salesRankRange": [0, 5000]` (Sales Rank between 0 and 5000), `"salesRankRange": [5000, -1]` (Sales Rank higher than 5000) |

### Search and sort options

| Parameter | Required | Description |
| --- | --- | --- |
| `titleSearch` | optional | Select deals by a keyword-based product title search. The search is case-insensitive and supports up to **50** keywords. If multiple keywords are specified (separated by a space), all must match.<br>Example: `"titleSearch": "samsung galaxy"` (matches products with both “samsung” AND “galaxy” in the title) |
| `sortType` | optional | Determines the sort order of the retrieved deals. To invert the sort order, use negative values. See the sort type table below for valid values. |

#### Valid `sortType` values

| Value | Sort By | Order |
| --- | --- | --- |
| **1** | Deal age | Newest deals first (not invertible) |
| **2** | Absolute delta | Highest delta to lowest |
| **3** | Sales Rank | Lowest rank to highest |
| **4** | Percentage delta | Highest percent to lowest |

## Token Cost

**5 tokens** per request, providing up to **150** deals. To retrieve more than 150 results, issue additional requests with an incremented `page` parameter (5 tokens each); a single query can provide up to 10,000 ASINs this way.

## Response

The response contains a `deals` field with the following content:

```json
{
  "dr": [deal objects],
  "categoryIds": [Long],
  "categoryNames": [String],
  "categoryCount": [Integer]
}
```

| Field | Description |
| --- | --- |
| `dr` | Ordered array of all [deal objects](https://env.7xmtools.com/api-docs/deal-object.html) matching your query. |
| `categoryIds` | Includes all root `categoryIds` of the matched deal products. The returned categories will update based on any filters used in your query, except for category filters. If category filters are applied, they will not affect the returned category information. |
| `categoryNames` | Includes all root category names of the matched deal products. The returned category names will update based on any filters used, other than category filters. If category filters are used, they will not affect the returned category information. |
| `categoryCount` | Indicates the number of deal products found in each respective root category. This count updates based on any filters used except for category filters. Applying category filters will not affect the returned category information. |

> **Note:** Each deal product is listed in a single root category. The arrays `categoryIds`, `categoryNames` and `categoryCount` are related by their index positions. If the root category of a product cannot be determined, it will be listed in the category with the name `"?"` and the ID `9223372036854775807`.

Example of one index: ID `165793011`, name `"Toys & Games"`, count `40`. For more information about categories, visit the [Category Object](https://env.7xmtools.com/api-docs/category-object.html) page.

## Examples

### Example queryJSON

A complete query selecting Amazon-price deals on amazon.com from one included root category, sorted by percentage delta over the last week:

```json
{
  "page": 0,
  "domainId": 1,
  "excludeCategories": [1064954, 11091801],
  "includeCategories": [16310101],
  "priceTypes": [0],
  "deltaRange": [0, 10000],
  "deltaPercentRange": [20, 100],
  "deltaLastRange": null,
  "salesRankRange": [0, 40000],
  "currentRange": [500, 40000],
  "minRating": -1,
  "isLowest": false,
  "isLowestOffer": false,
  "isOutOfStock": false,
  "titleSearch": null,
  "isRangeEnabled": true,
  "isFilterEnabled": false,
  "filterErotic": true,
  "hasReviews": false,
  "singleVariation": true,
  "sortType": 4,
  "dateRange": 1
}
```

### Example request

Using GET, the `queryJSON` must be URL-encoded and passed in the `selection` parameter. A minimal query `{"page":0,"domainId":1,"priceTypes":[0],"dateRange":1}` becomes:

```bash
curl -s "https://api.keepa.com/deal?key=YOUR_API_KEY&selection=%7B%22page%22%3A0%2C%22domainId%22%3A1%2C%22priceTypes%22%3A%5B0%5D%2C%22dateRange%22%3A1%7D"
```

Using POST, the query is sent as the request payload — usually the more convenient option for larger queries:

**Java**

```java
KeepaAPI api = new KeepaAPI("YOUR_API_KEY");
DealRequest dealQuery = new DealRequest();
dealQuery.page = 0;
dealQuery.domainId = 1;               // amazon.com
dealQuery.priceTypes = new int[]{0};  // AMAZON price type
dealQuery.dateRange = 1;              // interval: last week
dealQuery.isRangeEnabled = true;
dealQuery.currentRange = new int[]{500, 40000};
dealQuery.deltaPercentRange = new int[]{20, 100};
dealQuery.sortType = 4;
api.sendRequest(Request.getDealsRequest(dealQuery))
    .done(result -> {
        for (Deal deal : result.deals.dr) {
            System.out.println(deal.asin + "  " + deal.title);
        }
    })
    .fail(failure -> System.out.println(failure));
```

**PHP**

```php
<?php
use Keepa\KeepaAPI;
use Keepa\API\Request;
use Keepa\API\ResponseStatus;
use Keepa\objects\AmazonLocale;

use Keepa\API\DealRequest;
$api = new KeepaAPI("YOUR_API_KEY");
$dealQuery = new DealRequest();
$dealQuery->page = 0;
$dealQuery->domainId = 1;               // amazon.com
$dealQuery->priceTypes = [0];           // AMAZON price type
$dealQuery->dateRange = 1;              // interval: last week
$dealQuery->isRangeEnabled = true;
$dealQuery->currentRange = [500, 40000];
$dealQuery->deltaPercentRange = [20, 100];
$dealQuery->sortType = 4;
$response = $api->sendRequestWithRetry(Request::getDealsRequest($dealQuery));
if ($response->status == ResponseStatus::OK) {
    foreach ($response->deals->dr as $deal) {
        echo $deal->asin . "  " . $deal->title . PHP_EOL;
    }
}
```

**Python**

```python
import requests

query = {
    "page": 0,
    "domainId": 1,
    "priceTypes": [0],
    "dateRange": 1,
    "isRangeEnabled": True,
    "currentRange": [500, 40000],
    "deltaPercentRange": [20, 100],
    "sortType": 4,
}
r = requests.post("https://api.keepa.com/deal",
                  params={"key": "YOUR_API_KEY"}, json=query)
data = r.json()
for deal in data["deals"]["dr"]:
    print(deal["asin"], deal["title"])
```

**Node.js**

```javascript
const query = {
  page: 0,
  domainId: 1,
  priceTypes: [0],
  dateRange: 1,
  isRangeEnabled: true,
  currentRange: [500, 40000],
  deltaPercentRange: [20, 100],
  sortType: 4
};

const res = await fetch("https://api.keepa.com/deal?key=YOUR_API_KEY", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(query)
});
const data = await res.json();
for (const deal of data.deals.dr) console.log(deal.asin, deal.title);
```

**cURL**

```bash
curl -s -X POST "https://api.keepa.com/deal?key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"page":0,"domainId":1,"priceTypes":[0],"dateRange":1,"isRangeEnabled":true,"currentRange":[500,40000],"deltaPercentRange":[20,100],"sortType":4}'
```

### Paging through all results

Iterate `page` starting at 0, keeping all other parameters identical, and stop once a response contains fewer than 150 deals (5 tokens per request, up to 10,000 ASINs in total):

```python
page = 0
all_deals = []
while True:
    query["page"] = page
    r = requests.post("https://api.keepa.com/deal",
                      params={"key": "YOUR_API_KEY"}, json=query)
    dr = r.json()["deals"]["dr"]
    all_deals.extend(dr)
    if len(dr) < 150:
        break  # last page reached
    page += 1
```

### Example response

```json
{
  "timestamp": 1753651260000,
  "tokensLeft": 55,
  "refillIn": 42000,
  "refillRate": 5,
  "tokenFlowReduction": 0,
  "tokensConsumed": 5,
  "processingTimeInMs": 91,
  "deals": {
    "dr": [
      {
        "asin": "B0F3GWXLTS",
        "title": "Stainless Steel Insulated Water Bottle, 32 oz",
        "creationDate": 7663480,
        "categories": [16310101, 2251595011],
        "rootCat": 16310101,
        "current": [1999, 2499, -1, 4123],
        "currentSince": [7663480, 7660110, -1, 7663465],
        "delta": [[500, 350, -1, 1200], [780, 410, -1, 2050]],
        "deltaPercent": [[20, 12, -1, 23], [28, 14, -1, 33]],
        "deltaLast": [-500, 0, -1, 0],
        "avg": [[2499, 2849, -1, 5323], [2779, 2910, -1, 6173]],
        "lastUpdate": 7663510,
        "lightningEnd": 0,
        "image": [54, 49, 107, 51, 76, 97, 121, 55, 74, 85, 76, 46, 106, 112, 103]
      }
    ],
    "categoryIds": [16310101, 165793011],
    "categoryNames": ["Grocery & Gourmet Food", "Toys & Games"],
    "categoryCount": [97, 40]
  }
}
```

Response shortened for readability; illustrative values. Prices are integers in the smallest currency unit (e.g. `1999` = $19.99), timestamps like `creationDate` are in Keepa Time minutes, and `image` is an array of US-ASCII character codes (here decoding to `61k3Lay7JUL.jpg`). See the [Deal Object](https://env.7xmtools.com/api-docs/deal-object.html) page for the full structure of the entries in `dr`.
