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.

View as Markdown

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}`);
  }
}