api reference

Batch checks

POST /v1/check/batch checks up to 100 emails, domains or website URLs in one request. Each item counts toward your quota. Limits, response and retry advice.

View as Markdown

POST https://api.isbusinessemail.com/v1/check/batch

Checks up to 100 items in one request. Use it for imports, CRM clean-ups and back-filling verdicts on existing users. For a live signup form, use the single /v1/check: it’s faster for one address.

Secret keys only.

Request

{
  "items": [
    "jane@acme.io",
    "bob@gmail.com",
    "contoso.com"
  ],
  "policy": "b2b"
}
Field Required Notes
items yes Array of 1–100 strings. Each is an email address (has @), a website URL (has https:// or a path, like acme.io/about) or a bare domain.
policy no b2b (default), strict or lenient. Applies to every item.

Limits:

  • More than 100 items: 413 batch_too_large. Split into chunks of 100.
  • Request body over 256 KB: 413 payload_too_large.
  • Every item counts as one check toward your per-second and daily limits. Duplicates in the same batch are still counted, so de-duplicate first.

Response

The response contains one result per item, in the same order as items. Each result has the same shape as a single /v1/check response.

{
  "results": [
    { "email": "jane@acme.io", "domain": "acme.io", "category": "business", "recommendation": "allow", "…": "…" },
    { "email": "bob@gmail.com", "domain": "gmail.com", "category": "personal", "recommendation": "block", "…": "…" },
    { "email": null, "domain": "contoso.com", "category": "business", "recommendation": "allow", "…": "…" }
  ]
}

An item that isn’t a valid address or domain doesn’t fail the batch. It comes back with category: "invalid" and a reason such as invalid_syntax.

Example: check a CSV column in chunks

import { readFile } from 'node:fs/promises';

const emails = [...new Set(
  (await readFile('signups.csv', 'utf8'))
    .split('\n').slice(1)               // skip header
    .map((line) => line.split(',')[0]?.trim().toLowerCase())
    .filter(Boolean),
)];

const results = [];
for (let i = 0; i < emails.length; i += 100) {
  const res = await fetch('https://api.isbusinessemail.com/v1/check/batch', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.IBE_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ items: emails.slice(i, i + 100) }),
  });
  if (res.status === 429) {
    const wait = Number(res.headers.get('Retry-After') ?? 1);
    await new Promise((r) => setTimeout(r, wait * 1000));
    i -= 100; // retry this chunk
    continue;
  }
  if (!res.ok) throw new Error(`batch failed: ${res.status}`);
  const { results: chunk } = await res.json();
  results.push(...chunk);
}

console.table(results.map((r) => ({ email: r.email, category: r.category, recommendation: r.recommendation })));

Tips

  • Mind your daily quota. A tier 0 account has 100 checks a day, which is one full batch. Need a one-off import above that? Ask for higher limits.
  • Respect Retry-After on 429 rate_limited and back off; 429 quota_exceeded means the daily quota is used up until 00:00 UTC.
  • Prefer domains for CRM data. If you only care about the company, de-duplicate to domains first. 10,000 contacts often collapse to a few hundred domains.
  • No code? The bulk CSV checker does the same from a CSV upload.