Rate limits & usage headers
Each plan has two limits: a monthly quota of checks and a per-second limit.
| Plan | Checks per month | Requests per second |
|---|---|---|
| Free | 2,500 | 2 |
| Premium | 100,000 | 20 |
Prices and plan details are in Plans & billing.
Monthly quota
- Every authenticated
POST /v1/checkwith a valid body counts as one check, including addresses that turn out to be invalid (400). - Requests rejected with
401,422or429, and checks that fail with503, are not counted. - The quota resets on the 1st of every month at 00:00 UTC, whatever your plan and whenever you paid. Unused checks don't carry over. Annual Premium also gets 100,000 checks per month.
- When the quota is used up,
/v1/checkanswers429withtype: "QuotaExceededError"until the reset.Retry-Afteris the number of seconds until the reset:
HTTP/1.1 429 Too Many Requests
Retry-After: 712800
X-RateLimit-Limit: 2500
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1793491200
X-Account-Status: active
X-Plan: free
{
"error": {
"type": "QuotaExceededError",
"message": "Monthly quota of 2,500 checks reached. It resets on the 1st of next month (UTC)."
}
}
Need more checks this month? Upgrade to Premium: your existing key gets the Premium quota immediately, and the checks you already made this month still count.
Per-second limit
Requests above your plan's per-second limit get 429 with type: "RateLimitError" and Retry-After: 1:
{
"error": {
"type": "RateLimitError",
"message": "Too many requests per second for your plan. Slow down and retry."
}
}
In batch jobs, pace your calls (Free: one call every 500 ms or slower). In a signup flow, don't make the user wait for a retry: fail open instead.
Telling the two 429s apart
Both limits answer 429. Branch on error.type, never on the message text:
error.type | Meaning | Retry-After | What to do |
|---|---|---|---|
RateLimitError | Too many requests per second | 1 | Slow down. Retrying after 1 second is fine |
QuotaExceededError | Monthly quota used up | Seconds until the 1st | Don't retry this month: fail open and upgrade |
Never block a signup shows this check in Node.js and Python.
Usage headers
| Header | Example | Meaning |
|---|---|---|
X-RateLimit-Limit | 2500 | Checks per month in the plan that applies to this request |
X-RateLimit-Remaining | 2391 | Checks left this month |
X-RateLimit-Reset | 1793491200 | Unix time (seconds) of the next reset: the 1st of next month, 00:00 UTC |
X-Account-Status | active | active, past_due or expired: see When Premium ends |
X-Plan | free | The plan whose limits apply to this request: free or premium |
Retry-After | 1 | Only on 429: seconds to wait (1 for RateLimitError, seconds until the reset for QuotaExceededError) |
When each header is sent:
X-Account-StatusandX-Plan: on every request with a valid API key.X-RateLimit-*: on every request that reaches the quota step, that is every200,400for an invalid address,503and monthly-quota429. They are not sent on401,422or a per-second429.
Watch X-RateLimit-Remaining and X-Account-Status in your monitoring to avoid surprises.