api reference
Errors
isBusinessEmail errors are RFC 9457 problem+json with a stable code. Every code, its HTTP status, what causes it, and how to handle it.
Errors use RFC 9457 application/problem+json. Branch on code: it’s stable. title and detail are for humans and may change.
{
"type": "https://isbusinessemail.com/docs/errors#invalid_input",
"title": "Bad Request",
"status": 400,
"code": "invalid_input",
"detail": "Send exactly one of \"email\" or \"domain\".",
"docs_url": "https://isbusinessemail.com/docs/errors#invalid_input"
}
| Field | Meaning |
|---|---|
type |
URI of the error type: this page, with the code as anchor |
title |
Short HTTP status text |
status |
HTTP status code |
code |
Stable machine-readable code (below) |
detail |
Human-readable explanation of this occurrence |
docs_url |
Link to the section of this page for code |
Some errors add extra fields; ignore the ones you don’t use.
Summary
| Code | Status | Retry? |
|---|---|---|
invalid_input |
400 | No: fix the request |
unauthorized |
401 | No: send a key |
invalid_key |
401 | No: check the key |
key_revoked |
401 | No: use another key |
forbidden_origin |
403 | No: add the origin to the key |
terms_not_accepted |
403 | No: accept the updated terms |
rate_limited |
429 | Yes, after Retry-After |
quota_exceeded |
429 | After 00:00 UTC |
batch_too_large |
413 | No: split the batch |
payload_too_large |
413 | No: send less |
not_found |
404 | No |
method_not_allowed |
405 | No: use the right method |
internal_error |
500 | Yes, with backoff |
pass_required |
403 | Website checker only |
banned |
403 | Website checker only |
busy |
503 | Website checker only |
API errors
invalid_input
400. The request isn’t well-formed: missing input, both email and domain, a non-string value, an unknown policy, input over the length limits (email 254, local part 64, domain 253), control characters, or invalid JSON. Fix the request; retrying won’t help.
A well-formed request for an address that simply isn’t valid is not an error: it returns 200 with category: "invalid".
unauthorized
401. No API key was sent, and the input isn’t a test address. Send Authorization: Bearer ibe_live_… or X-API-Key. See Authentication.
invalid_key
401. The key is malformed, fails its checksum, or doesn’t exist. Common causes: a truncated copy-paste, a stray space or newline, or using a key from a different environment.
key_revoked
401. The key was revoked, by you, by an admin, or automatically because it was found in a public GitHub repository. Create a new key in the dashboard. Revocation applies everywhere within 60 seconds.
forbidden_origin
403. A publishable key (ibe_pub_…) was used from an origin that isn’t on its allowed list, or without an Origin header. Add the exact origin (scheme + host + port, e.g. https://app.example.com) to the key in the dashboard. For server-side calls, use a secret key.
terms_not_accepted
403. The account hasn’t accepted the current Terms of Service and Privacy Policy. After a material change you get 30 days’ notice and a grace period (responses carry a Warning header); after that, keys return this error until someone on the account signs in and accepts.
rate_limited
429. Too many requests per second, or too many in flight, for your tier. Wait for Retry-After seconds and retry with jitter. See Rate limits.
quota_exceeded
429. Your daily quota is used up. It resets at 00:00 UTC. Signups should fail open; batch jobs should stop and resume tomorrow, or ask for a higher tier.
batch_too_large
413. A batch had more than 100 items. Split it into chunks of 100.
payload_too_large
413. The request body is over the size limit (256 KB for batch). Send fewer or shorter items.
not_found
404. The path doesn’t exist. Check for typos and the /v1 prefix.
method_not_allowed
405. The path exists but not with this HTTP method, e.g. GET /v1/check/batch. The Allow header lists what’s supported.
internal_error
500. Something broke on our side. Retry with exponential backoff, and if it persists, send us the request_id from a previous response or the time of the failure. For signups, fail open.
Website checker errors
These come from the free checker on isbusinessemail.com, not from the developer API. You’ll only see them if you call the website’s internal endpoints, which aren’t a supported API. Get a free key instead.
pass_required
403. The browser needs to pass the human check (Turnstile) before checking more addresses.
banned
403. The network was temporarily blocked after automated or abusive use of the website checker.
busy
503. The website checker’s shared daily budget is used up. API key holders aren’t affected.
degraded is not an error
degraded: true in a 200 response means DNS lookups failed or timed out and the verdict comes from our lists alone, with lower confidence. It’s a flag on a successful response, not an error status. A sensible default: treat review as allow while degraded and re-check later.
Handling errors in code
const res = await fetch(url, options);
if (!res.ok) {
const problem = await res.json().catch(() => ({}));
switch (problem.code) {
case 'rate_limited':
case 'quota_exceeded':
case 'internal_error':
return failOpen(); // let the signup through, re-check later
case 'invalid_key':
case 'key_revoked':
case 'unauthorized':
alertOps(problem); // configuration problem: page someone
return failOpen();
default:
throw new Error(`${problem.code}: ${problem.detail}`);
}
}