> ## Documentation Index
> Fetch the complete documentation index at: https://api.docs.dealmachine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate Limits

> Understanding and handling API rate limits

# Rate Limits

All API requests are rate limited per organization to ensure fair usage and platform stability.

## Default Limits

| Window     | Limit          |
| ---------- | -------------- |
| Per minute | 60 requests    |
| Per day    | 5,000 requests |

Per-organization overrides are available on enterprise plans. Contact [support@dealmachine.com](mailto:support@dealmachine.com) to discuss higher limits.

## Response Headers

Every API response includes rate limit headers so you can track your usage in real time:

| Header                      | Description                                            |
| --------------------------- | ------------------------------------------------------ |
| `X-RateLimit-Limit`         | Maximum requests allowed per minute                    |
| `X-RateLimit-Remaining`     | Requests remaining in the current minute window        |
| `X-RateLimit-Reset`         | Unix timestamp (seconds) when the minute window resets |
| `X-RateLimit-Day-Limit`     | Maximum requests allowed per day                       |
| `X-RateLimit-Day-Remaining` | Requests remaining today                               |

## 429 Response

When you exceed the rate limit, the API returns a `429 Too Many Requests` response:

```json theme={null}
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Too many requests. Please retry after the specified time.",
    "request_id": "req_abc123def456",
    "details": {
      "limit_type": "minute",
      "retry_after": 12
    }
  }
}
```

The response also includes a `Retry-After` header with the number of seconds to wait before retrying.

| Field                 | Description                                 |
| --------------------- | ------------------------------------------- |
| `details.limit_type`  | Which limit was exceeded: `minute` or `day` |
| `details.retry_after` | Seconds until you can retry                 |
| `Retry-After` header  | Same value as `details.retry_after`         |

## Exponential Backoff

When you receive a `429` or `5xx` response, use **exponential backoff** to retry. This means waiting progressively longer between retries:

1. Wait **1 second**, then retry
2. If still failing, wait **2 seconds**, then retry
3. Then **4 seconds**, **8 seconds**, **16 seconds**...
4. Cap the maximum wait at **30 seconds**

Add a small random jitter (0-500ms) to each wait to prevent thundering herd problems when multiple clients retry simultaneously.

### JavaScript / TypeScript

```typescript theme={null}
async function fetchWithRetry(
  url: string,
  options: RequestInit,
  maxRetries = 5
): Promise<Response> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.ok) return response;

    // Don't retry client errors (except 429)
    if (response.status >= 400 && response.status < 500 && response.status !== 429) {
      return response;
    }

    if (attempt === maxRetries) return response;

    // Exponential backoff with jitter, capped at 30s
    const baseDelay = Math.min(1000 * Math.pow(2, attempt), 30000);
    const jitter = Math.random() * 500;
    await new Promise((resolve) => setTimeout(resolve, baseDelay + jitter));
  }

  throw new Error("Unreachable");
}

// Usage
const response = await fetchWithRetry(
  "https://api.v2.dealmachine.com/v1/enrichment/address",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      addresses: [{ full_address: "123 Main St, Austin, TX 78704" }],
    }),
  }
);
```

### Python

```python theme={null}
import time
import random
import requests

def fetch_with_retry(url, headers, json_body, max_retries=5):
    for attempt in range(max_retries + 1):
        response = requests.post(url, headers=headers, json=json_body)

        if response.ok:
            return response

        # Don't retry client errors (except 429)
        if 400 <= response.status_code < 500 and response.status_code != 429:
            return response

        if attempt == max_retries:
            return response

        # Exponential backoff with jitter, capped at 30s
        base_delay = min(2 ** attempt, 30)
        jitter = random.uniform(0, 0.5)
        time.sleep(base_delay + jitter)

# Usage
response = fetch_with_retry(
    "https://api.v2.dealmachine.com/v1/enrichment/address",
    headers={"Authorization": f"Bearer {api_key}"},
    json_body={
        "addresses": [{"full_address": "123 Main St, Austin, TX 78704"}]
    },
)
```

## Best Practices

| Do                                                       | Don't                                                 |
| -------------------------------------------------------- | ----------------------------------------------------- |
| Retry `429` and `5xx` responses with exponential backoff | Retry `400` or `401` errors (fix the request instead) |
| Check `X-RateLimit-Remaining` before sending bursts      | Ignore rate limit headers and retry blindly           |
| Use batch endpoints to reduce request count              | Send one item per request when batch is available     |
| Cache results locally when possible                      | Re-fetch data you already have                        |
| Add jitter to retry delays                               | Have all clients retry at the exact same time         |

<Tip>
  All enrichment and batch endpoints accept up to **250 items per request**. Batching reduces your request count significantly — 250 addresses in a single request counts as 1 request toward your rate limit.
</Tip>
