# Making Requests

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

Everything you need to call the Keepa API: the base URL, your access key, transport requirements (HTTPS, gzip or zstd, keep-alive), the token-bucket information included in every JSON response, and the possible HTTP status codes.

HTTPS GET · POST (selected endpoints)

The Keepa API offers numerous endpoints, which are explained on the individual pages of this documentation (see the **Endpoints** section in the sidebar, or the [overview](https://env.7xmtools.com/api-docs/index.html)).

## Official API Clients

Keepa provides clients for [Java](https://github.com/keepacom/api_backend) and [PHP](https://packagist.org/packages/keepa/php_api) for fast integration. Even if you do not use Java or PHP, these resources might still be helpful for insights and examples. There is also a community-developed [Python client](https://github.com/akaszynski/keepa) available.

## Price Plans

Requests consume tokens from your subscription's token bucket. Find out how the Keepa API price plans and the token system work on the [Plans & Tokens](https://env.7xmtools.com/api-docs/plans-tokens.html) page.

## Request Basics

```
GET https://api.keepa.com/<endpoint>?key=<yourAccessKey>&<parameters>
```

| Aspect | Requirement |
| --- | --- |
| **Base URL** | `https://api.keepa.com/` |
| **API Access Key** | Every request requires your API access key as a parameter (`key`). You can find and change your key [on the Keepa website](https://env.7xmtools.com/api). |
| **HTTP Method** | All requests are issued over **HTTPS** and must accept **gzip** encoding; **zstd** is supported as well and recommended (see [Response compression](https://env.7xmtools.com/api-docs/request-basics.html#compression)). **GET** works for every endpoint. Endpoints that take a large JSON query — [Product Finder](https://env.7xmtools.com/api-docs/product-finder.html), [Seller Finder](https://env.7xmtools.com/api-docs/seller-finder.html), [Browsing Deals](https://env.7xmtools.com/api-docs/deals.html) and [Add Tracking](https://env.7xmtools.com/api-docs/tracking.html#add-tracking) — additionally accept **POST**, which avoids URL-encoding the query and the URL length limit. If possible, use a **Keep-Alive** connection. |
| **Parallel Requests** | Multiple requests can be made in parallel to increase throughput. |

### Response compression

Responses are always compressed. **gzip** is the baseline that every client must support; **zstd** is supported as well and is the recommended choice — it is smaller than gzip and faster to decompress.

The coding is selected from the `Accept-Encoding` request header:

- Send `Accept-Encoding: gzip, zstd` to receive zstd. The token must be listed explicitly — a wildcard (`*`) does not enable it, and `zstd;q=0` is honored as a refusal.
- Anything else, including no `Accept-Encoding` header at all, is served gzip.

Always decode based on the `Content-Encoding` response header rather than assuming a coding: a request that advertises zstd can still be answered with gzip. Most HTTP clients handle both transparently (curl with `--compressed`, Python `requests`, browser `fetch`); older ones may need an extra package for zstd (for example `pip install "urllib3[zstd]"`). If your client cannot decode zstd, simply keep advertising `gzip` only.

## Response Format

The response is always in **JSON** format. Every response will contain information about your current API access:

```json
{
  "refillRate": Integer,
  "refillIn": Integer,
  "tokensLeft": Integer,
  "tokensConsumed": Integer,
  "tokenFlowReduction": Double,
  "processingTimeInMs": Integer,
  "error": {
    "type": String,
    "message": String,
    "details": String
  }
}
```

### Response fields

| Field | Type | Description |
| --- | --- | --- |
| `refillRate` | Integer | Number of tokens generated by your active subscriptions. |
| `refillIn` | Integer | Time in milliseconds until your token bucket will be refilled (happens every minute). |
| `tokensLeft` | Integer | How many tokens you currently have left. This value can be negative, as requests are always executed as long as there is a positive token balance when the request is submitted. |
| `tokensConsumed` | Integer | Number of tokens this request consumed. |
| `tokenFlowReduction` | Double | Tracking products through the API reduces your actual token refill rate by this value (rounded to an integer). |
| `processingTimeInMs` | Integer | Time the request's server side processing took, in milliseconds. |
| `error` | Object | Contains error information (`type`, `message`, `details` — all String). Only set if an error occurred. An error does not mean the whole request failed (e.g., batch requests). |

> **Note:** You can use this information to plan your requests. **Unused tokens will expire after 60 minutes.**

## Possible HTTP Status Codes

| Code | Status | Meaning |
| --- | --- | --- |
| `200` | OK | The request was successfully executed. |
| `400` | Bad Request | The request was malformed or could not be successfully executed. |
| `402` | Payment Required | The used API key does not grant access. |
| `405` | Method Not Allowed | A request parameter is out of the allowed range. |
| `429` | Too Many Requests | You are out of tokens. |
| `500` | Internal Server Error | An unexpected error occurred when executing this request. |

> **Note:** For any status code other than 200, you will still receive the token bucket information in the error stream. The remainder of the response varies and is explained on the individual endpoint pages.

## Examples

A good first request is a minimal [Product Request](https://env.7xmtools.com/api-docs/product.html) for a single ASIN: it costs a single token and — like every API response — returns your current token status in the response envelope, so you can verify that your key works and see how many tokens you have left.

```bash
https://api.keepa.com/product?key=YOUR_API_KEY&domain=1&asin=B0F3GWXLTS
```

**Java**

```java
KeepaAPI api = new KeepaAPI("YOUR_API_KEY");
Request r = Request.getProductRequest(AmazonLocale.US, null, null, "B0F3GWXLTS");
api.sendRequest(r)
    .done(result -> {
        if (result.status == ResponseStatus.OK) {
            System.out.println(result.products[0].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;

$api = new KeepaAPI("YOUR_API_KEY");
$response = $api->sendRequestWithRetry(Request::getProductRequest(AmazonLocale::US, null, null, null, 1, true, ['B0F3GWXLTS']));
if ($response->status == ResponseStatus::OK) {
    echo $response->products[0]->title;
}
```

**Python**

```python
import requests

# A Session reuses the connection (keep-alive); requests decodes gzip transparently.
session = requests.Session()
params = {"key": "YOUR_API_KEY", "domain": 1, "asin": "B0F3GWXLTS"}
r = session.get("https://api.keepa.com/product", params=params)
data = r.json()
print("Tokens left:", data["tokensLeft"])
print("Title:", data["products"][0]["title"])
```

**Node.js**

```javascript
// fetch keeps the connection alive and handles gzip automatically.
const res = await fetch("https://api.keepa.com/product?key=YOUR_API_KEY&domain=1&asin=B0F3GWXLTS");
const data = await res.json();
console.log("Tokens left:", data.tokensLeft);
console.log("Title:", data.products[0].title);
```

**cURL**

```bash
curl -s --compressed "https://api.keepa.com/product?key=YOUR_API_KEY&domain=1&asin=B0F3GWXLTS"
```

### Example response

Every response starts with the token bucket envelope described above; the endpoint's payload (here: the `products` array of the Product Request) follows alongside it. The `error` field is absent because no error occurred.

```json
{
  "processingTimeInMs": 32,
  "tokensLeft": 279,
  "refillIn": 41565,
  "refillRate": 5,
  "tokenFlowReduction": 0.0,
  "tokensConsumed": 1,
  "products": [
    {
      "asin": "B0F3GWXLTS",
      "domainId": 1,
      "title": "Example Product, 16 oz"
    }
  ]
}
```

*Response shortened for readability; illustrative values.* See the [Product Object](https://env.7xmtools.com/api-docs/product-object.html) for the full payload structure.

### Example error response

If a request fails (any status code other than 200), the token bucket information is still delivered in the error stream, together with the `error` object. In this example the token balance is exhausted, so the request is answered with HTTP `429 - Too Many Requests`. Note that `tokensLeft` can be negative:

```json
{
  "processingTimeInMs": 2,
  "tokensLeft": -3,
  "refillIn": 12844,
  "refillRate": 5,
  "tokenFlowReduction": 0.0,
  "tokensConsumed": 0,
  "error": {
    "type": "documentationExample",
    "message": "You are out of tokens.",
    "details": "Wait until your token bucket refills."
  }
}
```

*Illustrative values — the actual error `type`, `message` and `details` strings vary by endpoint and error condition.*

## Additional Information

- **Available Requests:** [View all available requests](https://env.7xmtools.com/api-docs/index.html#endpoints)
