Reference

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

PlanPriceRate LimitMonthly QuotaBatch Size
Free
$0/mo5 req/min100/day10 hashes
Starter
$29/mo60 req/min10,000/mo50 hashes
ProPopular
$99/mo300 req/min100,000/mo100 hashes
Business
$299/mo1,000 req/min1,000,000/mo100 hashes

Rate Limit Headers

Every API response includes headers to help you track your rate limit status:

X-RateLimit-Limit

Maximum number of requests allowed per minute for your plan.

X-RateLimit-Remaining

Number of requests remaining in the current rate limit window.

X-RateLimit-Reset

Unix timestamp (in seconds) when the rate limit window resets.

Retry-After

Seconds 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:

Response429 Too Many Requests
{
  "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:

Retry with 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

1

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.

2

Cache results

Phone number to carrier mappings rarely change. Cache successful lookups to avoid redundant API calls and reduce rate limit pressure.

3

Monitor your usage

Check the X-RateLimit-Remaining header to proactively throttle your requests before hitting the limit.

4

Implement backoff

Always implement exponential backoff when retrying rate-limited requests. Respect the retry_after value in the error response.

5

Upgrade when needed

If you consistently hit rate limits, consider upgrading to a higher plan. The Pro and Business plans offer significantly higher limits.