api reference
Check an email, domain or website
GET and POST /v1/check: check one email address, domain or website URL, choose a policy, request deep enrichment, and read the full response.
POST https://api.isbusinessemail.com/v1/check
GET https://api.isbusinessemail.com/v1/check?email=…
GET https://api.isbusinessemail.com/v1/check?domain=…
GET https://api.isbusinessemail.com/v1/check?url=…
Checks one email address, one domain or one website URL. POST is recommended: with GET the address ends up in URLs, which tend to be logged by proxies, load balancers and browsers.
Request
POST body
{ "email": "jane+news@acme.io" }
or
{ "domain": "acme.io" }
or a website address:
{ "url": "https://www.acme.io/pricing" }
Send exactly one of email, domain or url, with Content-Type: application/json.
Website URLs
For url, only the host counts: https://www.acme.io/pricing, acme.io/about and //acme.io all check acme.io (a leading www. is dropped; other subdomains are kept). Only http and https are accepted; IP addresses are not. The response is the same as for a domain check, plus url with the address as you sent it, and email is null. Use it to qualify a lead’s company website, or to compare a signup’s website with their email domain.
Options
Options can be sent as query parameters on either method (?policy=strict&deep=true) or as fields in the POST body.
| Option | Values | Default | Effect |
|---|---|---|---|
policy |
b2b, strict, lenient |
b2b |
Which categories map to allow, review and block. See Categories and policies. |
deep |
true, false |
false |
Adds domain age (RDAP) and a homepage check. Secret keys only. Counts as 5 checks; at most 1,000 deep checks a day. |
workspace |
true, false |
true |
false skips the Microsoft tenant lookup, the slowest part of a check. Use it when you only need the category: Microsoft 365 is still detected from MX, SPF and autodiscover, but tenant_id, auth and identity_provider stay null. |
{ "email": "jane@acme.io", "policy": "strict", "deep": true }
Input limits
- Email ≤ 254 characters, local part ≤ 64, domain ≤ 253, URL ≤ 2,048.
- Control characters and wildcards are rejected.
- International domains are accepted and converted to punycode.
A request that isn’t well-formed (missing input, both email and domain, wrong types, over the length limits) returns 400 invalid_input. A well-formed request for an address that isn’t valid returns 200 with category: "invalid" and a reason such as invalid_syntax or no_mx. That way you can treat “bad address” as a verdict, not an exception.
Response
{ "email": "jane+news@acme.io", "normalized_email": "jane@acme.io", "domain": "acme.io",
"is_business": true, "category": "business", "confidence": 0.96, "recommendation": "allow",
"is_free_provider": false, "is_disposable": false, "is_relay": false, "is_role_account": false,
"shared_inbox": { "confidence": 0, "match": null }, "group": { "confidence": 0, "match": null },
"is_blocked": false, "is_new_domain": false, "is_lookalike": false, "has_subaddress": true, "did_you_mean": null,
"mail": { "has_mx": true, "provider": "google_workspace", "mx": [{ "priority": 1, "host": "smtp.google.com" }],
"spf": "v=spf1 include:_spf.google.com ~all", "dmarc_policy": "reject" },
"workspace": { "google_workspace": { "detected": true, "evidence": ["mx_google","dkim_google"] },
"microsoft_365": { "detected": false, "tenant_id": null, "auth": null, "identity_provider": null, "evidence": [] },
"other_suite": null, "pending": false },
"integrations": { "google_workspace_ready": true, "microsoft_365_ready": false },
"domain_age_days": null, "reasons": ["mx_google_workspace","dmarc_reject","txt_saas_tokens:3"],
"degraded": false, "cached": false, "took_ms": 38, "request_id": "req_…" }
Every field is described in Response fields. The short version:
recommendationis what to do under your policy.categoryis what the address is.reasonsexplains why. Codes are listed in Reason codes.workspaceandintegrationstell you whether Google Workspace or Microsoft 365 integrations can work for this company.
Response headers
| Header | Meaning |
|---|---|
RateLimit-Policy, RateLimit |
Standardized rate-limit fields (IETF HTTPAPI draft) |
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset |
The same information in the widely used legacy format |
Retry-After |
On 429 and 503: seconds to wait before retrying |
Cache-Control: private, max-age=300, ETag |
On GET responses |
See Rate limits.
Checking a domain instead of an address
curl -s https://api.isbusinessemail.com/v1/check \
-H "Authorization: Bearer $IBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain":"acme.io"}'
Domain checks return the same shape. Address-specific fields (normalized_email, is_role_account, shared_inbox, group, has_subaddress, is_blocked for exact addresses) don’t apply and are null, false or 0. Use domain checks for CRM enrichment and sales routing where you only have a company domain.
Timing and caching
- Results for a domain are cached at the edge, so repeat checks are fast and
cached: true. - DNS lookups use a 1.5 s budget. The Microsoft tenant lookup gets 0.7 s; if it hasn’t answered by then, the response returns with
workspace.pending: trueand the lookup completes in the background, so the next check of that domain returns the full result. - If DNS fails entirely, you still get an answer from our lists, with
degraded: trueand lowerconfidence.
Use a client timeout of about 2–3 seconds and fail open.
Examples
GET with a domain
curl -s "https://api.isbusinessemail.com/v1/check?domain=acme.io" \
-H "Authorization: Bearer $IBE_API_KEY"
Strict policy with deep enrichment
curl -s "https://api.isbusinessemail.com/v1/check?policy=strict&deep=true" \
-H "Authorization: Bearer $IBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"jane@acme.io"}'
More languages: Code examples. Many addresses at once: Batch.