Documentação · Node.js
Node 18+ tem fetch nativo. Não precisa instalar nada — basta chamar a API REST do EmailChecker direto. A validação é em lote: você envia os emails, recebe um id e consulta esse id até o lote fechar. Compatível com qualquer runtime: Node, Bun, Deno, Edge.
# Nenhum pacote externo necessário com Node 18+.
# Para versões anteriores, use undici ou node-fetch.
npm install undici # opcional, só pra Node <18Passo 1 · POST /api/v1/batch
Endpoint assíncrono. Manda de 1 a 100.000 emails num POST e recebe 201 com o id do lote. O campo name é opcional e serve pra você achar o lote depois.
// emailchecker.mjs — Node 18+, só fetch nativo
const API_KEY = process.env.EMAILCHECKER_API_KEY;
const BASE_URL = 'https://app.emailchecker.email/api/v1';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function api(path, init) {
const r = await fetch(`${BASE_URL}${path}`, {
...init,
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
signal: AbortSignal.timeout(30_000),
});
// limite: 300 req/min e 10.000/hora por key
if (r.status === 429) {
await sleep(60_000);
return api(path, init);
}
const body = await r.json();
if (!r.ok) throw new Error(`EmailChecker ${r.status}: ${body.error}`);
return body.data;
}
// POST /api/v1/batch — de 1 a 100.000 emails; "name" é opcional
async function submitBatch(emails, name) {
const batch = await api('/batch', {
method: 'POST',
body: JSON.stringify(name === undefined ? { emails } : { emails, name }),
});
return batch.id; // uuid do lote
}
const batchId = await submitBatch(
['joao@empresa.com.br', 'contato@outra.com.br'],
'minha-lista',
);
console.log('lote enviado:', batchId);Passo 2 · GET /api/v1/batch/{id}
Não enviamos webhook: o jeito de saber que terminou é consultar o lote até status virar completed. Só aí o array emails vem preenchido, com result, score, reason e os atributos isv_*. O limite é de 300 req/min e 10.000/hora por key — um poll a cada 5 segundos sobra.
// poll.mjs — não existe webhook: consulte o lote até ele fechar
// GET /api/v1/batch/{id} — 5s entre polls dá ~12 req/min, folgado no limite
async function waitForBatch(id, { intervalMs = 5_000, timeoutMs = 1_800_000 } = {}) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const batch = await api(`/batch/${id}`);
if (batch.status === 'completed') return batch;
if (batch.status === 'failed' || batch.status === 'cancelled') {
throw new Error(`lote ${batch.status}`);
}
await sleep(intervalMs); // pending | processing
}
throw new Error('lote não terminou dentro do tempo');
}
const batch = await waitForBatch(batchId);
console.log(`${batch.size} emails, finalizado em ${batch.finished_at}`);
// emails[] só vem preenchido com status === "completed"
for (const e of batch.emails) {
// result: "deliverable" | "undeliverable" | "risky" | "unknown"
if (e.result === 'deliverable' && e.score >= 80) {
console.log(e.email, e.score, e.reason, e.is_free);
}
}Pitfalls
Erros sutis que só aparecem em produção. Conheça antes de subir o código.
Diferente de axios, o fetch do Node não aborta sozinho. Sem signal, uma conexão lenta pendura a request indefinidamente e segura um worker. Use AbortSignal.timeout(30_000) (Node 18+) ou um AbortController com setTimeout e clearTimeout no finally pra não vazar o timer.
fetch só rejeita em erro de rede; status 4xx/5xx caem no caminho de sucesso com r.ok === false. Um 401/422 (sua key ou payload) não deve ter retry; um 429/5xx deve. Cheque r.status antes de decidir: relançar erro fatal em 4xx, esperar e repetir em 429/5xx.
Chamar await r.text() pra logar o erro e depois r.json() lança "body used already". Leia o corpo uma única vez numa variável (const raw = await r.text()) e faça JSON.parse a partir dela, ou clone com r.clone() antes da primeira leitura.
Se os emails vierem de objetos do ORM com campos undefined eles somem do JSON sem aviso, e qualquer BigInt lança TypeError. Monte o payload explícito ({ emails }) com strings puras em vez de stringificar as linhas do banco inteiras.
Mais linguagens
Comece grátis com 500 créditos. Sem cartão, sem compromisso.