api reference
Rate limits and quotas
Per-second, daily and in-flight limits for each tier, how batch and deep checks count, rate-limit headers, and how to handle 429 responses.
The API is free, so limits keep it fast and fair for everyone. These are the defaults; we can change them, and we can raise them for you.
Tiers
| Tier | Who | Per second | Per day | In flight |
|---|---|---|---|---|
| 0 | New accounts | 5 | 100 | 10 |
| 1 | Automatic after 7 clean days | 10 | 1,000 | 10 |
| 2 | On request | 20 | 10,000 | 20 |
| 3 | High volume, on request | 200 | 100,000 | 50 |
- “Clean” means no abuse flags, no limit-evasion and no terms violations.
- Need tier 2 or 3? Need more limits? Contact us. Request it from the dashboard or by email. Tell us your use case and expected volume.
- Limits are per account, shared by all its keys.
- These are the defaults. Your dashboard’s Settings page shows the limits that apply to your account right now, and
GET /v1/usagereturns them.
What counts
| Request | Counts as |
|---|---|
/v1/check |
1 |
/v1/check with deep=true |
5 (and at most 1,000 deep checks a day) |
/v1/check/batch |
1 per item (up to 100 items per request) |
/v1/feedback |
0 checks; separate limit of 50 a day per key |
/v1/usage, /v1/health |
0 |
| Test addresses | 0, never counted |
Daily quotas reset at 00:00 UTC.
Headers
Every counted response carries rate-limit headers in both the standardized and the legacy format:
| Header | Meaning |
|---|---|
RateLimit-Policy |
The limits that apply to you, in the format of the IETF HTTPAPI RateLimit header fields draft |
RateLimit |
Current remaining allowance and time to reset, same draft |
X-RateLimit-Limit |
Your daily quota |
X-RateLimit-Remaining |
Checks left today |
X-RateLimit-Reset |
When the daily quota resets |
Retry-After |
On 429 (and 503): seconds to wait before retrying |
Parse whichever your HTTP client already understands.
Errors
| Code | Status | Meaning | What to do |
|---|---|---|---|
rate_limited |
429 | Too many requests per second, or too many in flight | Wait Retry-After seconds, retry with backoff and jitter |
quota_exceeded |
429 | Daily quota used up | Stop until 00:00 UTC, or ask for a higher tier. Signups should fail open. |
batch_too_large |
413 | More than 100 items | Split the batch |
payload_too_large |
413 | Body over 256 KB | Send smaller batches |
When you hit your daily quota we send one email that day with your usage and a link to request higher limits.
Handling 429 well
async function checkWithRetry(body, attempts = 3) {
for (let i = 0; i < attempts; i++) {
const res = await fetch('https://api.isbusinessemail.com/v1/check', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.IBE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
signal: AbortSignal.timeout(2500),
});
if (res.status !== 429) return res;
const problem = await res.json();
if (problem.code === 'quota_exceeded') return res; // retrying won't help today
const wait = Number(res.headers.get('Retry-After') ?? 1) * 1000;
await new Promise((r) => setTimeout(r, wait + Math.random() * 250));
}
throw new Error('rate limited');
}
For a live signup form, don’t retry at all: fail open and re-check in the background.
Staying well under your limits
- Cache on your side by domain. Verdicts for a domain rarely change within a day.
- Check once per signup, on submit, not on every keystroke. For inline hints, debounce and use a publishable key, which has its own limits.
- De-duplicate before batch jobs, and check domains instead of addresses when you only need the company.
Fair use
Limits exist to keep the service free. Creating multiple accounts to get around them, rotating IPs, or reselling access are against the Acceptable Use Policy and lead to suspension. If you need more, ask; we say yes to most reasonable requests.