Rate Limits
Understand how rate limiting works and how to build resilient integrations that handle rate limit responses gracefully.
Overview
The Decode Hash API enforces rate limits to ensure fair usage and maintain service reliability for all users. Rate limits are applied per API key and vary by plan.
Each plan also has a monthly lookup quota. Rate limits control how many requests you can make per minute, while quotas control how many total lookups you can perform per billing period.
Limits by Plan
| Plan | Price | Rate Limit | Monthly Quota | Batch Size |
|---|---|---|---|---|
Free | $0/mo | 5 req/min | 100/day | 10 hashes |
Starter | $29/mo | 60 req/min | 10,000/mo | 50 hashes |
ProPopular | $99/mo | 300 req/min | 100,000/mo | 100 hashes |
Business | $299/mo | 1,000 req/min | 1,000,000/mo | 100 hashes |
Rate Limit Headers
Every API response includes headers to help you track your rate limit status:
X-RateLimit-LimitMaximum number of requests allowed per minute for your plan.
X-RateLimit-RemainingNumber of requests remaining in the current rate limit window.
X-RateLimit-ResetUnix timestamp (in seconds) when the rate limit window resets.
Retry-AfterSeconds to wait before retrying. Only present on 429 responses.
Handling 429 Responses
When you exceed your rate limit, the API returns a 429 status with a retry_after value indicating how many seconds to wait:
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Try again in 12 seconds.",
"retry_after": 12
}
}Here is a recommended retry pattern with exponential backoff:
import requests
import time
def lookup_with_retry(hash_value, api_key, max_retries=3):
"""Look up a hash with exponential backoff on rate limits."""
url = "https://api.decode.cowdi.co/v1/lookup"
headers = {"X-API-Key": api_key}
for attempt in range(max_retries):
response = requests.post(
url,
headers=headers,
json={"hash": hash_value}
)
if response.status_code == 200:
return response.json()
if response.status_code == 429:
retry_after = response.json().get("error", {}).get("retry_after", 2 ** attempt)
print(f"Rate limited. Retrying in {retry_after}s...")
time.sleep(retry_after)
continue
response.raise_for_status()
raise Exception("Max retries exceeded")Best Practices
Use batch lookups
When resolving multiple hashes, use the /v1/lookup/batch endpoint instead of making individual requests. A single batch request counts as one request toward your rate limit.
Cache results
Phone number to carrier mappings rarely change. Cache successful lookups to avoid redundant API calls and reduce rate limit pressure.
Monitor your usage
Check the X-RateLimit-Remaining header to proactively throttle your requests before hitting the limit.
Implement backoff
Always implement exponential backoff when retrying rate-limited requests. Respect the retry_after value in the error response.
Upgrade when needed
If you consistently hit rate limits, consider upgrading to a higher plan. The Pro and Business plans offer significantly higher limits.