# Tracking API

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

Let Keepa track product changes and notify you — via webhook push or API pull. This page covers all tracking operations: adding, retrieving and removing trackings, named tracking lists, notifications and the webhook setup.

GET · varies per tracked product

Keepa can track product changes and notify you. Tracking through our API uses a separate list than your Keepa account. You can only view and manage the products you track through API calls.

> **Important:**
>
> - Each tracked product **decreases your token refill rate**. Once your refill rate reaches **0**, you will not be able to track any more products or make any API requests that require tokens.
> - If your API access is terminated, your tracking list will be deactivated and removed after **7 days**, unless access is restored.
> - If you switch to a lower-tier API plan that doesn't provide enough tokens for your current tracking list, the necessary amount of trackings will be deactivated and slated for removal after 7 days, unless they are reactivated in the interim.
> - To manage your tracking expenses separately from other API uses, consider operating two separate Keepa accounts, each with its own API subscription.

## Endpoint

All tracking operations use the `/tracking` endpoint. The `type` parameter selects the operation. [Add Tracking](https://env.7xmtools.com/api-docs/tracking.html#add-tracking) additionally supports HTTP POST.

```
GET https://api.keepa.com/tracking?key=<yourAccessKey>&type=<operation>
```

To manage your API tracking, use the following commands:

| Operation | `type` | Token cost | Purpose |
| --- | --- | --- | --- |
| [Add Tracking](https://env.7xmtools.com/api-docs/tracking.html#add-tracking) | `add` | 1 per tracking | Add a new tracking to your list. |
| [Remove Tracking](https://env.7xmtools.com/api-docs/tracking.html#remove-tracking) | `remove` / `removeAll` | 0 | Remove a tracking from your list or clear your entire list. |
| [Get Tracking](https://env.7xmtools.com/api-docs/tracking.html#get-tracking) | `get` / `list` | 0 | Retrieve tracking information for a product on your list or the whole list. |
| [Get Notifications](https://env.7xmtools.com/api-docs/tracking.html#get-notifications) | `notification` | 0 | Retrieve recent notifications. |
| [Get Named Lists](https://env.7xmtools.com/api-docs/tracking.html#get-named-lists) | `listNames` | 0 | Retrieve a list of all your named tracking lists. |
| [Set Webhook](https://env.7xmtools.com/api-docs/tracking.html#set-webhook) | `webhook` | 0 | Update your webhook URL to receive push notifications. |

## Types of Tracking

There are two types of tracking:

### 1. Regular Tracking

Allows tracking of the following price types:

- Amazon
- New
- Used
- List Price
- Collectible
- Refurbished
- Lightning Deal
- All offer counts
- Sales Rank

### 2. Marketplace Tracking

Includes all data covered by Regular Tracking. Additionally tracks:

- Warehouse Deals
- Buy Box New & Used
- New 3rd Party FBA & FBM
- Rating
- Prime Exclusive
- Review Counts
- All Used and Collectible conditions with shipping costs

The first 20 offers of a product will be used for the tracking.

## Token Cost

Each tracked ASIN can have notification rules for multiple Amazon locales and have a different update interval. These factors determine how much your token refill rate is reduced for each tracking:

| Tracking type | Refill rate reduction |
| --- | --- |
| Regular Tracking | **0.9 tokens** per update per locale tracked |
| Marketplace Tracking | **9 tokens** per update per locale tracked |

Since the token refill rate is an integer, the tracking reduction rate is rounded. Your current reduction rate is part of every API response in the `tokenFlowReduction` field alongside other token stats.

> **Note:** Your `tokenFlowReduction` will be updated every 5 minutes — not immediately after adding or removing trackings.

### Token cost examples

- **2000 Regular Trackings** on a single locale with an update interval of 1 hour:\
  2000 × 0.9 tokens/hour = 1800 tokens/hour = 30 tokens/minute → **decreased refill rate: 30 tokens**
- **700 Marketplace Trackings** on a single locale with an update interval of 12 hours:\
  700 × 9 tokens / 12 hours = 525 tokens/hour = 8.75 tokens/minute → **decreased refill rate: 9 tokens**

You can track as many products as your token rate allows.

Besides the refill rate reduction, the request itself costs tokens only for [Add Tracking](https://env.7xmtools.com/api-docs/tracking.html#add-tracking) (**1 token per tracking**); all other tracking operations cost **0** tokens.

## Named Tracking Lists

It is possible to use named tracking lists, which act as a logical separation of your tracking objects. This enables you to have multiple, different trackings for the same ASIN. By default, all trackings are managed in an unnamed list.

- All tracking requests (except [Set Webhook](https://env.7xmtools.com/api-docs/tracking.html#set-webhook)) support the additional parameter `list` to specify the name of the list the request should act on (e.g., `&list=user123`).
- A list name can be up to **64** characters long.
- You can manage up to **100,000** lists (contact us if you need more).
- Lists are created implicitly with the first added tracking and can be deleted by the [Remove All](https://env.7xmtools.com/api-docs/tracking.html#remove-tracking) request.
- If a tracking is added to a named list, the [tracking object](https://env.7xmtools.com/api-docs/tracking-object.html) will have the list name set in the `trackingListName` field. The same applies to [notification objects](https://env.7xmtools.com/api-docs/notification-object.html).
- You can retrieve a list of all your named lists using the [Get Named Lists](https://env.7xmtools.com/api-docs/tracking.html#get-named-lists) request.

## Operations

### Add Tracking

**Token cost:** 1 per tracking

Adds a new tracking to your list. If you already have an existing tracking for the ASIN on your list, it will be overridden, and if it was deactivated, it will be reactivated. You can batch up to **3,000** trackings in a single request to significantly speed up the process of adding multiple trackings.

You can choose between an HTTP GET or POST request.

#### GET format

```
GET https://api.keepa.com/tracking?key=<yourAccessKey>&type=add&tracking=<trackingJSON>
```

#### POST format

```
POST https://api.keepa.com/tracking?key=<yourAccessKey>&type=add
```

The **POST payload** must contain a single or an array of [tracking creation objects](https://env.7xmtools.com/api-docs/tracking-creation-object.html). You can specify up to **3,000** tracking creation objects in a single request in JSON array notation: `[object, object, ...]`.

| Parameter | Required | Description |
| --- | --- | --- |
| `key` | required | Your private API key. |
| `type` | required | Must be `add`. |
| `tracking` | required (GET format only) | The tracking JSON contains an array of [tracking creation objects](https://env.7xmtools.com/api-docs/tracking-creation-object.html). It must be URL-encoded if the GET format is used. Due to URL length limitations, do not use the GET method for batch requests. |
| `list` | optional | Name of the [named tracking list](https://env.7xmtools.com/api-docs/tracking.html#named-tracking-lists) this request should act on, e.g. `&list=user123`. |

**Response:**

- A `trackings` array field containing the created or updated [tracking object(s)](https://env.7xmtools.com/api-docs/tracking-object.html).
- If an error occurred, the `error` field is set.
- If a tracking could not be added in a batch request, the `error` field will include a comma-separated list of all failed ASINs.

#### Example

Add a price watch for ASIN `B00M0QVG3W` on amazon.de (domain 3), notifying via API when the Amazon price drops to 49.99 € (4999 euro cents) or the product comes back in stock:

**Java**

```java
KeepaAPI api = new KeepaAPI("YOUR_API_KEY");
TrackingRequest tracking = new TrackingRequest("B00M0QVG3W", AmazonLocale.DE, 1);
tracking.ttl = 0;                            // never expires
tracking.expireNotify = false;
tracking.desiredPricesInMainCurrency = true;
// thresholdValues / notifyIf can be set on the tracking object as needed
api.sendRequest(Request.getTrackingAddRequest(tracking))
    .done(result -> {
        for (Tracking t : result.trackings) System.out.println(t.asin);
    })
    .fail(failure -> System.out.println(failure));
```

**PHP**

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

$api = new KeepaAPI("YOUR_API_KEY");
// the PHP client serializes the tracking creation object from an array:
$tracking = [
    "asin" => "B00M0QVG3W",
    "ttl" => 0,
    "expireNotify" => false,
    "desiredPricesInMainCurrency" => true,
    "mainDomainId" => 3,
    "updateInterval" => 1,
    "thresholdValues" => [
        ["thresholdValue" => 4999, "domain" => 3, "csvType" => 0, "isDrop" => true]
    ],
    "notificationType" => [false, false, false, false, false, true, false]
];
$response = $api->sendRequestWithRetry(Request::getTrackingAddRequest($tracking));
if ($response->status == ResponseStatus::OK) {
    print_r($response->trackings);
}
```

**Python**

```python
import requests

tracking = {
    "asin": "B00M0QVG3W",
    "ttl": 0,
    "expireNotify": False,
    "desiredPricesInMainCurrency": True,
    "mainDomainId": 3,
    "updateInterval": 1,
    "metaData": "customer-42",
    "thresholdValues": [
        {"thresholdValue": 4999, "domain": 3, "csvType": 0, "isDrop": True}
    ],
    "notifyIf": [{"domain": 3, "csvType": 0, "notifyIfType": 1}],
    "notificationType": [False, False, False, False, False, True, False],
    "individualNotificationInterval": -1,
}

r = requests.post(
    "https://api.keepa.com/tracking",
    params={"key": "YOUR_API_KEY", "type": "add"},
    json=[tracking],
)
data = r.json()
print(data["trackings"][0]["asin"], data["trackings"][0]["isActive"])
```

**Node.js**

```javascript
const tracking = {
  asin: "B00M0QVG3W",
  ttl: 0,
  expireNotify: false,
  desiredPricesInMainCurrency: true,
  mainDomainId: 3,
  updateInterval: 1,
  metaData: "customer-42",
  thresholdValues: [{ thresholdValue: 4999, domain: 3, csvType: 0, isDrop: true }],
  notifyIf: [{ domain: 3, csvType: 0, notifyIfType: 1 }],
  notificationType: [false, false, false, false, false, true, false],
  individualNotificationInterval: -1,
};

const res = await fetch("https://api.keepa.com/tracking?key=YOUR_API_KEY&type=add", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify([tracking]),
});
const data = await res.json();
console.log(data.trackings[0].asin, data.trackings[0].isActive);
```

**cURL**

```bash
curl -s -X POST "https://api.keepa.com/tracking?key=YOUR_API_KEY&type=add" \
  -H "Content-Type: application/json" \
  -d '[{
    "asin": "B00M0QVG3W",
    "ttl": 0,
    "expireNotify": false,
    "desiredPricesInMainCurrency": true,
    "mainDomainId": 3,
    "updateInterval": 1,
    "metaData": "customer-42",
    "thresholdValues": [
      { "thresholdValue": 4999, "domain": 3, "csvType": 0, "isDrop": true }
    ],
    "notifyIf": [
      { "domain": 3, "csvType": 0, "notifyIfType": 1 }
    ],
    "notificationType": [false, false, false, false, false, true, false],
    "individualNotificationInterval": -1
  }]'
```

#### Example response

```json
{
  "timestamp": 1753651200000,
  "tokensLeft": 4994,
  "refillIn": 43000,
  "refillRate": 300,
  "tokenFlowReduction": 30.6,
  "tokensConsumed": 1,
  "processingTimeInMs": 18,
  "trackings": [
    {
      "asin": "B00M0QVG3W",
      "createDate": 7663520,
      "isActive": true,
      "ttl": 0,
      "expireNotify": false,
      "mainDomainId": 3,
      "updateInterval": 1,
      "metaData": "customer-42",
      "trackingListName": null,
      "thresholdValues": [
        { "thresholdValueCSV": [7663520, 4999], "domain": 3, "csvType": 0, "isDrop": true }
      ],
      "notifyIf": [
        { "domain": 3, "csvType": 0, "notifyIfType": 1 }
      ],
      "notificationType": [false, false, false, false, false, true, false],
      "notificationCSV": null,
      "individualNotificationInterval": -1
    }
  ]
}
```

Response shortened for readability; illustrative values. See the [Tracking Object](https://env.7xmtools.com/api-docs/tracking-object.html) for all field semantics.

### Remove Tracking

**Token cost:** 0

Removes a single tracking from your list.

```
GET https://api.keepa.com/tracking?key=<yourAccessKey>&type=remove&asin=<ASIN>
```

To remove all your trackings with a single call:

```
GET https://api.keepa.com/tracking?key=<yourAccessKey>&type=removeAll
```

| Parameter | Required | Description |
| --- | --- | --- |
| `key` | required | Your private API key. |
| `type` | required | `remove` to remove a single tracking, or `removeAll` to remove all your trackings with a single call. `removeAll` can also be used to delete a [named list](https://env.7xmtools.com/api-docs/tracking.html#named-tracking-lists). |
| `asin` | required (for `remove`) | The ASIN of the product you want to remove from your tracking list. |
| `list` | optional | Name of the [named tracking list](https://env.7xmtools.com/api-docs/tracking.html#named-tracking-lists) this request should act on, e.g. `&list=user123`. |

**Response:**

- Only token bucket information.
- If you did not have a tracking for the specified ASIN, the `error` field is set.

> **Note:** Your `tokenFlowReduction` will not be updated immediately upon removing a tracking.

#### Example

**Java**

```java
KeepaAPI api = new KeepaAPI("YOUR_API_KEY");
Request r = Request.getTrackingRemoveRequest("B00M0QVG3W");
api.sendRequest(r)
    .done(result -> {
        System.out.println("tracking removed");
    })
    .fail(failure -> System.out.println(failure));
```

**PHP**

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

$api = new KeepaAPI("YOUR_API_KEY");
$response = $api->sendRequestWithRetry(Request::getTrackingRemoveRequest("B00M0QVG3W"));
if ($response->status == ResponseStatus::OK) {
    echo "tracking removed";
}
```

**Python**

```python
import requests

params = {"key": "YOUR_API_KEY", "type": "remove", "asin": "B00M0QVG3W"}
r = requests.get("https://api.keepa.com/tracking", params=params)
data = r.json()
print(data.get("error"), data["tokensLeft"])
```

**Node.js**

```javascript
const res = await fetch("https://api.keepa.com/tracking?key=YOUR_API_KEY&type=remove&asin=B00M0QVG3W");
const data = await res.json();
console.log(data.error ?? "removed", data.tokensLeft);
```

**cURL**

```bash
curl -s "https://api.keepa.com/tracking?key=YOUR_API_KEY&type=remove&asin=B00M0QVG3W"
```

#### Example response

```json
{
  "timestamp": 1753651260000,
  "tokensLeft": 4994,
  "refillIn": 43000,
  "refillRate": 300,
  "tokenFlowReduction": 30.6,
  "tokensConsumed": 0,
  "processingTimeInMs": 4
}
```

Illustrative values.

### Get Tracking

**Token cost:** 0

Retrieves a single tracking from your list.

```
GET https://api.keepa.com/tracking?key=<yourAccessKey>&type=get&asin=<ASIN>
```

#### Retrieve your list

```
GET https://api.keepa.com/tracking?key=<yourAccessKey>&type=list[&asins-only=1][&page=<n>&perPage=<m>]
```

| Parameter | Required | Description |
| --- | --- | --- |
| `key` | required | Your private API key. |
| `type` | required | `get` to retrieve a single tracking, or `list` to retrieve your whole list. |
| `asin` | required (for `get`) | The ASIN of the product you want to retrieve your tracking for. |
| `asins-only` | optional (`list` only) | `asins-only=1` returns only the ASINs you track (fast, lightweight). Pagination parameters are **ignored** in this mode because the call always returns the full list. |
| `page` | optional (`list` only) | Page of the batch you want (first page = `0`). |
| `perPage` | optional (`list` only) | Number of tracking records to return in one batch. If you supply this parameter, the highest accepted value is **100,000** — larger values are capped to it. If you omit it, the whole list is returned in one batch (up to **500,000** records). |
| `list` | optional | Name of the [named tracking list](https://env.7xmtools.com/api-docs/tracking.html#named-tracking-lists) this request should act on, e.g. `&list=user123`. |

> **Pagination details:** The default is `page=0` with no page size limit, which returns the whole list in one batch (up to **500,000** records). To page through a larger list, supply `perPage` (maximum **100,000**) and increment `page` until the response array is empty.

**Response:**

- A `trackings` field containing the [tracking object(s)](https://env.7xmtools.com/api-docs/tracking-object.html) (always an array).
- If you did not have a tracking for the specified ASIN, the `error` field is set.
- In case of the `list` operation with the `asins-only` parameter, an `asinList` field containing a string array of all tracked ASINs.

#### Example

**Java**

```java
KeepaAPI api = new KeepaAPI("YOUR_API_KEY");
Request r = Request.getTrackingGetRequest("B00M0QVG3W");
api.sendRequest(r)
    .done(result -> {
        System.out.println(result.trackings[0].asin);
    })
    .fail(failure -> System.out.println(failure));
```

**PHP**

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

$api = new KeepaAPI("YOUR_API_KEY");
$response = $api->sendRequestWithRetry(Request::getTrackingGetRequest("B00M0QVG3W"));
if ($response->status == ResponseStatus::OK) {
    print_r($response->trackings);
}
```

**Python**

```python
import requests

params = {"key": "YOUR_API_KEY", "type": "get", "asin": "B00M0QVG3W"}
r = requests.get("https://api.keepa.com/tracking", params=params)
data = r.json()
tracking = data["trackings"][0]
print(tracking["asin"], tracking["isActive"], tracking["updateInterval"])
```

**Node.js**

```javascript
const res = await fetch("https://api.keepa.com/tracking?key=YOUR_API_KEY&type=get&asin=B00M0QVG3W");
const data = await res.json();
const tracking = data.trackings[0];
console.log(tracking.asin, tracking.isActive, tracking.updateInterval);
```

**cURL**

```bash
curl -s "https://api.keepa.com/tracking?key=YOUR_API_KEY&type=get&asin=B00M0QVG3W"
```

#### Example response

```json
{
  "timestamp": 1753651320000,
  "tokensLeft": 4998,
  "refillIn": 22000,
  "refillRate": 300,
  "tokenFlowReduction": 30.6,
  "tokensConsumed": 0,
  "processingTimeInMs": 6,
  "trackings": [
    {
      "asin": "B00M0QVG3W",
      "createDate": 7663520,
      "isActive": true,
      "ttl": 0,
      "expireNotify": false,
      "mainDomainId": 3,
      "updateInterval": 1,
      "metaData": "customer-42",
      "trackingListName": null,
      "thresholdValues": [
        { "thresholdValueCSV": [7663520, 4999], "domain": 3, "csvType": 0, "isDrop": true }
      ],
      "notifyIf": [
        { "domain": 3, "csvType": 0, "notifyIfType": 1 }
      ],
      "notificationType": [false, false, false, false, false, true, false],
      "notificationCSV": [3, 0, 5, 1, 7663890],
      "individualNotificationInterval": -1
    }
  ]
}
```

Response shortened for readability; illustrative values.

Retrieving only the ASINs of your entire list:

```bash
curl -s "https://api.keepa.com/tracking?key=YOUR_API_KEY&type=list&asins-only=1"
```

```json
{
  "timestamp": 1753651380000,
  "tokensLeft": 4998,
  "refillIn": 22000,
  "refillRate": 300,
  "tokenFlowReduction": 30.6,
  "tokensConsumed": 0,
  "processingTimeInMs": 3,
  "asinList": ["B00M0QVG3W", "B0F3GWXLTS", "B07FZ8S74R"]
}
```

### Get Notifications

**Token cost:** 0

Retrieves your recent [notification objects](https://env.7xmtools.com/api-docs/notification-object.html). A notification will be marked as read once delivered through this call or pushed to your webhook. Notifications are deleted **24 hours** after creation. Use this request if you do not want to use push notifications via webhook or if your webhook endpoint was offline.

```
GET https://api.keepa.com/tracking?key=<yourAccessKey>&type=notification&since=<since>&revise=<revise>
```

| Parameter | Required | Description |
| --- | --- | --- |
| `key` | required | Your private API key. |
| `type` | required | Must be `notification`. |
| `since` | required | Retrieve all available notifications that occurred since this date, in KeepaTime minutes. |
| `revise` | required | Boolean value (`0` = false, `1` = true). Whether or not to request notifications already marked as read. |
| `all` | optional | Boolean value (`0` = false, `1` = true). By default a single call returns at most **2,000** notifications, newest first. Set `all=1` to lift that limit and return every notification matching the request.<br>Example: `&all=1` |
| `readOnly` | optional | Boolean value (`0` = false, `1` = true). If set to `1`, the returned notifications are *not* marked as read, so a later call without `revise` still returns them. Use this to inspect notifications without consuming them.<br>Example: `&readOnly=1` |
| `list` | optional | Name of the [named tracking list](https://env.7xmtools.com/api-docs/tracking.html#named-tracking-lists) this request should act on, e.g. `&list=user123`. |

**Response:**

- A `notifications` field containing [notification object(s)](https://env.7xmtools.com/api-docs/notification-object.html), sorted by most recent first. Always an array.
- At most **2,000** notifications per call unless `all=1` is used. If you receive exactly 2,000, request the remainder with `all=1` or by paging on `since`.

#### Example

Fetch all unread notifications created since KeepaTime minute 7,662,080:

**Java**

```java
KeepaAPI api = new KeepaAPI("YOUR_API_KEY");
Request r = Request.getTrackingNotificationRequest(7662080, false);
api.sendRequest(r)
    .done(result -> {
        for (Notification n : result.notifications) {
            System.out.println(n.asin + "  " + n.trackingNotificationCause);
        }
    })
    .fail(failure -> System.out.println(failure));
```

**PHP**

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

$api = new KeepaAPI("YOUR_API_KEY");
$response = $api->sendRequestWithRetry(Request::getTrackingNotificationRequest(7662080, false));
if ($response->status == ResponseStatus::OK) {
    print_r($response->notifications);
}
```

**Python**

```python
import requests

params = {"key": "YOUR_API_KEY", "type": "notification", "since": 7662080, "revise": 0}
r = requests.get("https://api.keepa.com/tracking", params=params)
data = r.json()
for n in data["notifications"]:
    print(n["asin"], n["csvType"], n["trackingNotificationCause"])
```

**Node.js**

```javascript
const res = await fetch("https://api.keepa.com/tracking?key=YOUR_API_KEY&type=notification&since=7662080&revise=0");
const data = await res.json();
for (const n of data.notifications) {
  console.log(n.asin, n.csvType, n.trackingNotificationCause);
}
```

**cURL**

```bash
curl -s "https://api.keepa.com/tracking?key=YOUR_API_KEY&type=notification&since=7662080&revise=0"
```

#### Example response

```json
{
  "timestamp": 1753651440000,
  "tokensLeft": 4998,
  "refillIn": 12000,
  "refillRate": 300,
  "tokenFlowReduction": 30.6,
  "tokensConsumed": 0,
  "processingTimeInMs": 7,
  "notifications": [
    {
      "asin": "B00M0QVG3W",
      "title": "Example Product Title",
      "image": "61vXG3m1KWL.jpg",
      "ttl": 1440,
      "createDate": 7663480,
      "domainId": 3,
      "notificationDomainId": 3,
      "csvType": 0,
      "trackingNotificationCause": 1,
      "currentPrices": [4899, 4750, 4210, 15230, 6999, -1],
      "sentNotificationVia": [false, false, false, false, false, true, false],
      "metaData": "customer-42",
      "trackingListName": null
    }
  ]
}
```

Response shortened for readability; illustrative values. See the [Notification Object](https://env.7xmtools.com/api-docs/notification-object.html) for all field semantics.

### Get Named Lists

**Token cost:** 0

Retrieves a list of all the names of your [named lists](https://env.7xmtools.com/api-docs/tracking.html#named-tracking-lists).

```
GET https://api.keepa.com/tracking?key=<yourAccessKey>&type=listNames
```

| Parameter | Required | Description |
| --- | --- | --- |
| `key` | required | Your private API key. |
| `type` | required | Must be `listNames`. |

**Response:**

- A `trackingListNames` field containing the names of all your named lists. Always an array.

#### Example

**Java**

```java
KeepaAPI api = new KeepaAPI("YOUR_API_KEY");
// type=listNames has no dedicated factory method — build it directly.
// (Request.getTrackingListRequest(false) covers type=list.)
Request r = new Request();
r.path = "tracking";
r.parameter.put("type", "listNames");
api.sendRequest(r)
    .done(result -> System.out.println(result))
    .fail(failure -> System.out.println(failure));
```

**PHP**

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

$api = new KeepaAPI("YOUR_API_KEY");
// type=listNames has no dedicated factory method — build it directly.
// (Request::getTrackingListRequest(false) covers type=list.)
$r = new Request();
$r->path = "tracking";
$r->parameter["type"] = "listNames";
$response = $api->sendRequestWithRetry($r);
if ($response->status == ResponseStatus::OK) {
    print_r($response);
}
```

**Python**

```python
import requests

params = {"key": "YOUR_API_KEY", "type": "listNames"}
r = requests.get("https://api.keepa.com/tracking", params=params)
data = r.json()
print(data["trackingListNames"])
```

**Node.js**

```javascript
const res = await fetch("https://api.keepa.com/tracking?key=YOUR_API_KEY&type=listNames");
const data = await res.json();
console.log(data.trackingListNames);
```

**cURL**

```bash
curl -s "https://api.keepa.com/tracking?key=YOUR_API_KEY&type=listNames"
```

#### Example response

```json
{
  "timestamp": 1753651500000,
  "tokensLeft": 4998,
  "refillIn": 2000,
  "refillRate": 300,
  "tokenFlowReduction": 30.6,
  "tokensConsumed": 0,
  "processingTimeInMs": 3,
  "trackingListNames": ["user123", "user456", "watchlist-electronics"]
}
```

Illustrative values.

### Set Webhook

**Token cost:** 0

Updates the webhook URL our service will call whenever a notification is triggered. The URL can also be updated and tested via the [website](https://env.7xmtools.com/api).

```
GET https://api.keepa.com/tracking?key=<yourAccessKey>&type=webhook&url=<URL>
```

| Parameter | Required | Description |
| --- | --- | --- |
| `key` | required | Your private API key. |
| `type` | required | Must be `webhook`. |
| `url` | required | The new webhook URL. |

> **Note:** Set Webhook is the only tracking request that does *not* support the `list` parameter.

#### Push notification details

- A push notification will be an HTTP POST call with a single [notification object](https://env.7xmtools.com/api-docs/notification-object.html) as its content.
- Your server must respond with a status code of **200** to confirm successful retrieval.
- If delivery fails, a second attempt will be made with a **15-second** delay.

> **Important:** The content type of the POST is `application/json` and **not** `application/x-www-form-urlencoded`. If you use PHP, you have to use `file_get_contents('php://input')` or `$HTTP_RAW_POST_DATA` to access the content.

**Response:**

- Only token bucket information if the update was successful.
- If the specified URL is of invalid format, the `error` field is set.

#### Example

**Java**

```java
KeepaAPI api = new KeepaAPI("YOUR_API_KEY");
Request r = Request.getTrackingWebhookRequest("https://example.com/keepa/notify");
api.sendRequest(r)
    .done(result -> {
        System.out.println("webhook set");
    })
    .fail(failure -> System.out.println(failure));
```

**PHP**

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

$api = new KeepaAPI("YOUR_API_KEY");
$response = $api->sendRequestWithRetry(Request::getTrackingWebhookRequest("https://example.com/keepa/notify"));
if ($response->status == ResponseStatus::OK) {
    echo "webhook set";
}
```

**Python**

```python
import requests

params = {
    "key": "YOUR_API_KEY",
    "type": "webhook",
    "url": "https://example.com/keepa/notify",
}
r = requests.get("https://api.keepa.com/tracking", params=params)
data = r.json()
print(data.get("error") or "webhook updated")
```

**Node.js**

```javascript
const webhookUrl = encodeURIComponent("https://example.com/keepa/notify");
const res = await fetch(`https://api.keepa.com/tracking?key=YOUR_API_KEY&type=webhook&url=${webhookUrl}`);
const data = await res.json();
console.log(data.error ?? "webhook updated");
```

**cURL**

```bash
curl -s "https://api.keepa.com/tracking?key=YOUR_API_KEY&type=webhook&url=https%3A%2F%2Fexample.com%2Fkeepa%2Fnotify"
```

#### Example response

```json
{
  "timestamp": 1753651560000,
  "tokensLeft": 4998,
  "refillIn": 55000,
  "refillRate": 300,
  "tokenFlowReduction": 30.6,
  "tokensConsumed": 0,
  "processingTimeInMs": 2
}
```

Illustrative values.
