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 to discuss higher limits.
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:
{
"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:
- Wait 1 second, then retry
- If still failing, wait 2 seconds, then retry
- Then 4 seconds, 8 seconds, 16 seconds…
- 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
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
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 |
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.