Quando você está verificando milhares ou milhões de endereços de email, aguardar sincronicamente por cada resultado não é prático. Os webhooks de verificação de email fornecem uma solução elegante ao notificar sua aplicação quando as tarefas de verificação são concluídas, eliminando a necessidade de polling constante e habilitando fluxos de trabalho assíncronos eficientes. Este guia abrangente explora tudo o que os desenvolvedores precisam saber sobre implementação de webhooks de verificação de email, desde configuração básica até padrões avançados para lidar com operações de verificação em larga escala.
Entendendo Webhooks de Verificação de Email
Webhooks são callbacks HTTP que entregam dados à sua aplicação quando eventos específicos ocorrem. No contexto de verificação de email, webhooks notificam seus sistemas quando trabalhos de verificação em massa são concluídos, quando verificações individuais de email terminam no modo assíncrono, ou quando outros eventos significativos ocorrem durante o processo de verificação.
Por Que Usar Webhooks para Verificação de Email?
Os padrões tradicionais de requisição-resposta funcionam bem para verificação de email único, mas operações em massa apresentam desafios. Verificar 100.000 emails pode levar horas, e manter uma conexão HTTP aberta por tanto tempo não é viável. Fazer polling para atualizações de status desperdiça recursos e cria carga desnecessária na API.
Eliminação de Sobrecarga de Polling
Sem webhooks, você precisaria consultar repetidamente a API para verificar se os trabalhos em massa foram concluídos. Isso cria tráfego de rede desnecessário, consome limites de taxa da API e adiciona complexidade à sua aplicação. Os webhooks enviam notificações exatamente quando são necessárias.
Processamento em Tempo Real
Os webhooks permitem ação imediata quando a verificação é concluída. Sua aplicação pode processar resultados, atualizar bancos de dados e acionar ações subsequentes sem atrasos introduzidos por intervalos de polling.
Arquitetura Escalável
Arquiteturas baseadas em webhooks escalam naturalmente. Seja processando um trabalho em massa ou centenas simultaneamente, seu endpoint de webhook recebe notificações conforme chegam, e você pode processá-las de forma assíncrona usando filas ou workers.
Eficiência de Recursos
Em vez de manter conexões ou executar loops de polling, sua aplicação permanece ociosa até que os webhooks cheguem. Isso reduz custos de computação e simplifica os requisitos de infraestrutura.
Eventos de Webhook na Verificação de Email
Serviços de verificação de email tipicamente acionam webhooks para vários tipos de eventos:
Conclusão de Trabalho em Massa
O evento de webhook mais comum é disparado quando um trabalho de verificação em massa termina o processamento. A payload inclui status do trabalho, estatísticas resumidas e informações sobre download de resultados.
Progresso de Trabalho em Massa
Alguns serviços enviam webhooks de progresso em intervalos durante o processamento em massa, permitindo que você acompanhe o progresso da verificação e estime o tempo de conclusão.
Falha de Trabalho em Massa
Quando um trabalho em massa encontra erros que impedem a conclusão, webhooks de falha fornecem detalhes sobre o que deu errado e se resultados parciais estão disponíveis.
Verificação de Email Único (Modo Assíncrono)
Para cenários de verificação em tempo real de alto volume, a verificação assíncrona de email único envia resultados via webhook em vez de aguardar resposta síncrona.
Configurando Endpoints de Webhook
Implementar webhooks requer criar um endpoint em sua aplicação que possa receber e processar payloads de webhook.
Estrutura Básica do Endpoint
Um endpoint de webhook é simplesmente um endpoint HTTP POST que aceita payloads JSON:
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhooks/email-verification', async (req, res) => {
const { event_type, job_id, status, data } = req.body;
console.log(`Received webhook: ${event_type} for job ${job_id}`);
// Process the webhook
try {
await handleWebhookEvent(req.body);
// Always respond quickly to acknowledge receipt
res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook processing error:', error);
// Still acknowledge receipt to prevent retries
res.status(200).json({ received: true, error: error.message });
}
});
async function handleWebhookEvent(payload) {
switch (payload.event_type) {
case 'bulk.completed':
await handleBulkCompleted(payload);
break;
case 'bulk.failed':
await handleBulkFailed(payload);
break;
case 'bulk.progress':
await handleBulkProgress(payload);
break;
default:
console.log(`Unknown event type: ${payload.event_type}`);
}
}
Melhores Práticas de Resposta de Webhook
Serviços de verificação de email esperam respostas rápidas dos endpoints de webhook. Se seu endpoint demorar muito para responder, o serviço pode assumir que a entrega falhou e tentar novamente.
Responda Imediatamente
Reconheça o recebimento do webhook imediatamente, depois processe a payload de forma assíncrona:
app.post('/webhooks/email-verification', async (req, res) => {
// Immediately acknowledge receipt
res.status(200).json({ received: true });
// Process asynchronously
setImmediate(async () => {
try {
await handleWebhookEvent(req.body);
} catch (error) {
console.error('Async webhook processing error:', error);
// Log for retry or manual processing
await logFailedWebhook(req.body, error);
}
});
});
Use Filas de Mensagens para Processamento Pesado
Para sistemas de produção, enfileire payloads de webhook para processamento por processos worker:
const Queue = require('bull');
const webhookQueue = new Queue('email-verification-webhooks');
app.post('/webhooks/email-verification', async (req, res) => {
// Queue the webhook for processing
await webhookQueue.add('process-webhook', req.body, {
attempts: 3,
backoff: {
type: 'exponential',
delay: 1000
}
});
res.status(200).json({ received: true });
});
// Worker process
webhookQueue.process('process-webhook', async (job) => {
const payload = job.data;
await handleWebhookEvent(payload);
});
Configurando Webhooks com a API
Registre seu endpoint de webhook com o serviço de verificação de email:
async function registerWebhook(webhookUrl, events, secret) {
const response = await fetch('https://api.billionverify.com/v1/webhooks', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.BILLIONVERIFY_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: webhookUrl,
events: events,
secret: secret
})
});
const result = await response.json();
if (!response.ok) {
throw new Error(`Failed to register webhook: ${result.error}`);
}
console.log(`Webhook registered: ${result.webhook_id}`);
return result;
}
// Register for bulk job events
await registerWebhook(
'https://yourapp.com/webhooks/email-verification',
['bulk.completed', 'bulk.failed', 'bulk.progress'],
process.env.WEBHOOK_SECRET
);
Protegendo Endpoints de Webhook
Endpoints de webhook são acessíveis publicamente, tornando a segurança essencial. Sem verificação adequada, atacantes poderiam enviar payloads de webhook falsas para manipular sua aplicação.
Verificação de Assinatura
A maioria dos serviços de verificação de email assina payloads de webhook usando HMAC-SHA256 com um segredo compartilhado. Verifique assinaturas antes de processar:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
// Use timing-safe comparison to prevent timing attacks
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
app.post('/webhooks/email-verification', async (req, res) => {
const signature = req.headers['x-webhook-signature'];
if (!signature) {
return res.status(401).json({ error: 'Missing signature' });
}
const isValid = verifyWebhookSignature(
req.body,
signature,
process.env.WEBHOOK_SECRET
);
if (!isValid) {
console.warn('Invalid webhook signature received');
return res.status(401).json({ error: 'Invalid signature' });
}
// Signature valid, process webhook
await handleWebhookEvent(req.body);
res.status(200).json({ received: true });
});
Validação de Timestamp
Previna ataques de replay validando timestamps de webhook:
function isTimestampValid(timestamp, toleranceSeconds = 300) {
const webhookTime = new Date(timestamp).getTime();
const currentTime = Date.now();
const difference = Math.abs(currentTime - webhookTime);
return difference <= toleranceSeconds * 1000;
}
app.post('/webhooks/email-verification', async (req, res) => {
const { timestamp } = req.body;
if (!isTimestampValid(timestamp)) {
console.warn('Webhook timestamp outside acceptable range');
return res.status(400).json({ error: 'Invalid timestamp' });
}
// Continue with signature verification and processing
});
Lista de Permissão de IPs
Para segurança adicional, restrinja o acesso ao webhook a endereços IP conhecidos:
const allowedIPs = [
'203.0.113.0/24', // BillionVerify webhook servers
'198.51.100.0/24'
];
function isIPAllowed(clientIP) {
// Implement CIDR range checking
return allowedIPs.some(range => isIPInRange(clientIP, range));
}
app.post('/webhooks/email-verification', async (req, res) => {
const clientIP = req.ip || req.connection.remoteAddress;
if (!isIPAllowed(clientIP)) {
console.warn(`Webhook from unauthorized IP: ${clientIP}`);
return res.status(403).json({ error: 'Forbidden' });
}
// Continue with processing
});
Tratamento de Idempotência
Webhooks podem ser entregues múltiplas vezes devido a problemas de rede ou tentativas. Implemente idempotência para lidar com duplicatas de forma segura:
const processedWebhooks = new Set(); // Use Redis in production
async function handleWebhookIdempotent(payload) {
const webhookId = payload.webhook_id || payload.event_id;
// Check if already processed
if (processedWebhooks.has(webhookId)) {
console.log(`Duplicate webhook ignored: ${webhookId}`);
return;
}
// Mark as processing
processedWebhooks.add(webhookId);
try {
await handleWebhookEvent(payload);
} catch (error) {
// Remove from processed set to allow retry
processedWebhooks.delete(webhookId);
throw error;
}
}
Para sistemas de produção, use Redis para idempotência distribuída:
const Redis = require('ioredis');
const redis = new Redis();
async function isWebhookProcessed(webhookId) {
const key = `webhook:processed:${webhookId}`;
const result = await redis.set(key, '1', 'NX', 'EX', 86400); // 24 hour expiry
return result === null; // Already exists
}
app.post('/webhooks/email-verification', async (req, res) => {
const webhookId = req.body.webhook_id;
if (await isWebhookProcessed(webhookId)) {
console.log(`Duplicate webhook: ${webhookId}`);
return res.status(200).json({ received: true, duplicate: true });
}
await handleWebhookEvent(req.body);
res.status(200).json({ received: true });
});
Processando Payloads de Webhook
Diferentes eventos de webhook requerem diferentes lógicas de tratamento. Vamos explorar padrões comuns para processar webhooks de verificação de email.
Tratando Conclusão de Trabalho em Massa
Quando um trabalho de verificação em massa é concluído, baixe e processe os resultados:
async function handleBulkCompleted(payload) {
const { job_id, status, summary, download_url } = payload;
console.log(`Bulk job ${job_id} completed with status: ${status}`);
console.log(`Summary: ${summary.valid} valid, ${summary.invalid} invalid`);
// Download results
const results = await downloadResults(download_url);
// Process results
await processVerificationResults(job_id, results);
// Update job status in database
await updateJobStatus(job_id, 'completed', summary);
// Notify relevant parties
await sendCompletionNotification(job_id, summary);
}
async function downloadResults(url) {
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${process.env.BILLIONVERIFY_API_KEY}`
}
});
if (!response.ok) {
throw new Error(`Failed to download results: ${response.status}`);
}
return await response.json();
}
async function processVerificationResults(jobId, results) {
// Batch update contacts in database
const validEmails = results.filter(r => r.is_valid);
const invalidEmails = results.filter(r => !r.is_valid);
await db.transaction(async (trx) => {
// Update valid emails
for (const batch of chunkArray(validEmails, 1000)) {
await trx('contacts')
.whereIn('email', batch.map(r => r.email))
.update({
email_verified: true,
verification_date: new Date(),
verification_job_id: jobId
});
}
// Handle invalid emails
for (const batch of chunkArray(invalidEmails, 1000)) {
await trx('contacts')
.whereIn('email', batch.map(r => r.email))
.update({
email_verified: false,
email_invalid_reason: trx.raw('CASE email ' +
batch.map(r => `WHEN '${r.email}' THEN '${r.reason}'`).join(' ') +
' END'),
verification_date: new Date(),
verification_job_id: jobId
});
}
});
}
Tratando Falhas de Trabalho em Massa
Quando trabalhos falham, capture informações de erro e determine se a recuperação é possível:
async function handleBulkFailed(payload) {
const { job_id, error_code, error_message, partial_results_available } = payload;
console.error(`Bulk job ${job_id} failed: ${error_message}`);
// Update job status
await updateJobStatus(job_id, 'failed', {
error_code,
error_message
});
// Try to retrieve partial results if available
if (partial_results_available) {
console.log('Attempting to retrieve partial results...');
try {
const partialResults = await downloadPartialResults(job_id);
await processVerificationResults(job_id, partialResults);
// Identify unprocessed emails for retry
const processedEmails = new Set(partialResults.map(r => r.email));
const originalEmails = await getOriginalJobEmails(job_id);
const unprocessedEmails = originalEmails.filter(e => !processedEmails.has(e));
if (unprocessedEmails.length > 0) {
// Schedule retry for unprocessed emails
await scheduleRetryJob(job_id, unprocessedEmails);
}
} catch (error) {
console.error('Failed to retrieve partial results:', error);
}
}
// Notify about failure
await sendFailureNotification(job_id, error_message);
}
async function scheduleRetryJob(originalJobId, emails) {
// Create new job for remaining emails
const response = await fetch('https://api.billionverify.com/v1/bulk/verify', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.BILLIONVERIFY_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
emails,
metadata: {
retry_of: originalJobId
}
})
});
const { job_id: newJobId } = await response.json();
console.log(`Scheduled retry job ${newJobId} for ${emails.length} emails`);
}
Tratando Atualizações de Progresso
Webhooks de progresso ajudam a acompanhar trabalhos de longa duração:
async function handleBulkProgress(payload) {
const { job_id, processed_count, total_count, estimated_completion } = payload;
const percentComplete = Math.round((processed_count / total_count) * 100);
console.log(`Job ${job_id}: ${percentComplete}% complete (${processed_count}/${total_count})`);
// Update progress in database
await updateJobProgress(job_id, {
processed_count,
total_count,
percent_complete: percentComplete,
estimated_completion: new Date(estimated_completion)
});
// Optionally notify users of progress
if (percentComplete % 25 === 0) {
await sendProgressNotification(job_id, percentComplete);
}
}
Padrões Avançados de Webhook
Sistemas de produção se beneficiam de padrões avançados que melhoram a confiabilidade e a manutenibilidade.
Fila de Mensagens Mortas para Webhooks Falhados
Quando o processamento de webhook falha repetidamente, mova as payloads para uma fila de mensagens mortas para revisão manual:
const webhookQueue = new Queue('email-verification-webhooks');
const deadLetterQueue = new Queue('webhook-dead-letters');
webhookQueue.process('process-webhook', async (job) => {
try {
await handleWebhookEvent(job.data);
} catch (error) {
// Check if this is the final retry
if (job.attemptsMade >= job.opts.attempts - 1) {
// Move to dead letter queue
await deadLetterQueue.add('failed-webhook', {
original_payload: job.data,
error: error.message,
failed_at: new Date().toISOString(),
attempts: job.attemptsMade + 1
});
}
throw error; // Re-throw to trigger retry
}
});
// Process dead letters manually or with alerts
deadLetterQueue.on('completed', async (job) => {
await sendAlert({
type: 'webhook_dead_letter',
job_id: job.data.original_payload.job_id,
error: job.data.error
});
});
Event Sourcing de Webhook
Armazene todos os eventos de webhook para trilhas de auditoria e capacidade de replay:
async function handleWebhookWithEventSourcing(payload) {
// Store raw event
const eventId = await storeWebhookEvent(payload);
try {
// Process event
await handleWebhookEvent(payload);
// Mark as processed
await markEventProcessed(eventId);
} catch (error) {
// Mark as failed
await markEventFailed(eventId, error);
throw error;
}
}
async function storeWebhookEvent(payload) {
const result = await db('webhook_events').insert({
event_type: payload.event_type,
job_id: payload.job_id,
payload: JSON.stringify(payload),
received_at: new Date(),
status: 'pending'
});
return result[0];
}
// Replay failed events
async function replayFailedEvents() {
const failedEvents = await db('webhook_events')
.where('status', 'failed')
.where('retry_count', '<', 3);
for (const event of failedEvents) {
try {
await handleWebhookEvent(JSON.parse(event.payload));
await markEventProcessed(event.id);
} catch (error) {
await incrementRetryCount(event.id);
}
}
}
Roteamento de Webhook Multi-Tenant
Para aplicações SaaS, encaminhe webhooks para handlers específicos do tenant:
async function handleMultiTenantWebhook(payload) {
const { tenant_id, event_type, data } = payload;
// Get tenant configuration
const tenant = await getTenantConfig(tenant_id);
if (!tenant) {
console.error(`Unknown tenant: ${tenant_id}`);
return;
}
// Route to tenant-specific handler
switch (event_type) {
case 'bulk.completed':
await handleTenantBulkCompleted(tenant, data);
break;
case 'bulk.failed':
await handleTenantBulkFailed(tenant, data);
break;
}
// Forward to tenant webhook if configured
if (tenant.webhook_url) {
await forwardToTenant(tenant.webhook_url, tenant.webhook_secret, payload);
}
}
async function forwardToTenant(url, secret, payload) {
const signature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Webhook-Signature': signature
},
body: JSON.stringify(payload)
});
}
Tratamento de Erros e Confiabilidade
Implementações robustas de webhook lidam com falhas graciosamente e garantem que nenhum dado seja perdido.
Estratégias de Retry
Implemente backoff exponencial para falhas transitórias:
async function processWebhookWithRetry(payload, maxRetries = 5) {
const delays = [1000, 5000, 30000, 120000, 300000]; // 1s, 5s, 30s, 2m, 5m
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
await handleWebhookEvent(payload);
return; // Success
} catch (error) {
const isRetryable = isRetryableError(error);
if (!isRetryable || attempt === maxRetries - 1) {
// Log to dead letter queue
await logFailedWebhook(payload, error, attempt + 1);
throw error;
}
console.log(`Retry ${attempt + 1}/${maxRetries} after ${delays[attempt]}ms`);
await sleep(delays[attempt]);
}
}
}
function isRetryableError(error) {
// Network errors, timeouts, and 5xx responses are retryable
const retryableCodes = ['ECONNRESET', 'ETIMEDOUT', 'ENOTFOUND'];
return retryableCodes.includes(error.code) ||
(error.status && error.status >= 500);
}
Padrão Circuit Breaker
Previna falhas em cascata quando serviços downstream estão indisponíveis:
class CircuitBreaker {
constructor(options = {}) {
this.failureThreshold = options.failureThreshold || 5;
this.resetTimeout = options.resetTimeout || 60000;
this.state = 'CLOSED';
this.failures = 0;
this.lastFailure = null;
}
async execute(fn) {
if (this.state === 'OPEN') {
if (Date.now() - this.lastFailure > this.resetTimeout) {
this.state = 'HALF_OPEN';
} else {
throw new Error('Circuit breaker is OPEN');
}
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failures = 0;
this.state = 'CLOSED';
}
onFailure() {
this.failures++;
this.lastFailure = Date.now();
if (this.failures >= this.failureThreshold) {
this.state = 'OPEN';
console.warn('Circuit breaker opened due to failures');
}
}
}
const databaseCircuitBreaker = new CircuitBreaker();
async function handleBulkCompletedSafely(payload) {
await databaseCircuitBreaker.execute(async () => {
await processVerificationResults(payload.job_id, payload.results);
});
}
Monitoramento e Alertas
Rastreie métricas de saúde do webhook:
const metrics = {
received: 0,
processed: 0,
failed: 0,
latency: []
};
app.post('/webhooks/email-verification', async (req, res) => {
const startTime = Date.now();
metrics.received++;
try {
await handleWebhookEvent(req.body);
metrics.processed++;
} catch (error) {
metrics.failed++;
throw error;
} finally {
metrics.latency.push(Date.now() - startTime);
// Keep only last 1000 measurements
if (metrics.latency.length > 1000) {
metrics.latency.shift();
}
}
res.status(200).json({ received: true });
});
// Expose metrics endpoint
app.get('/metrics/webhooks', (req, res) => {
const avgLatency = metrics.latency.reduce((a, b) => a + b, 0) / metrics.latency.length;
res.json({
received: metrics.received,
processed: metrics.processed,
failed: metrics.failed,
success_rate: (metrics.processed / metrics.received * 100).toFixed(2) + '%',
avg_latency_ms: Math.round(avgLatency)
});
});
// Alert on high failure rate
setInterval(() => {
const failureRate = metrics.failed / metrics.received;
if (failureRate > 0.1) { // More than 10% failures
sendAlert({
type: 'high_webhook_failure_rate',
failure_rate: failureRate,
total_received: metrics.received,
total_failed: metrics.failed
});
}
}, 60000);
Testando Implementações de Webhook
Testes completos garantem que os handlers de webhook funcionem corretamente em produção.
Testes Locais com ngrok
Use ngrok para expor endpoints locais para testes de webhook:
# Start your local server node server.js # In another terminal, expose it via ngrok ngrok http 3000
Registre a URL do ngrok como seu endpoint de webhook durante o desenvolvimento.
Payloads de Webhook Simuladas
Crie fixtures de teste para diferentes tipos de eventos:
const mockPayloads = {
bulkCompleted: {
event_type: 'bulk.completed',
job_id: 'job_123456',
status: 'completed',
timestamp: new Date().toISOString(),
summary: {
total: 1000,
valid: 850,
invalid: 120,
risky: 30
},
download_url: 'https://api.billionverify.com/v1/bulk/download/job_123456'
},
bulkFailed: {
event_type: 'bulk.failed',
job_id: 'job_789012',
error_code: 'PROCESSING_ERROR',
error_message: 'Internal processing error',
partial_results_available: true
},
bulkProgress: {
event_type: 'bulk.progress',
job_id: 'job_345678',
processed_count: 5000,
total_count: 10000,
estimated_completion: new Date(Date.now() + 3600000).toISOString()
}
};
// Test endpoint
describe('Webhook Handler', () => {
it('should process bulk.completed event', async () => {
const response = await request(app)
.post('/webhooks/email-verification')
.set('X-Webhook-Signature', generateSignature(mockPayloads.bulkCompleted))
.send(mockPayloads.bulkCompleted);
expect(response.status).toBe(200);
expect(response.body.received).toBe(true);
// Verify side effects
const job = await db('verification_jobs').where('job_id', 'job_123456').first();
expect(job.status).toBe('completed');
});
});
Testes de Integração
Teste o fluxo completo do webhook incluindo verificação de assinatura:
describe('Webhook Security', () => {
it('should reject requests without signature', async () => {
const response = await request(app)
.post('/webhooks/email-verification')
.send(mockPayloads.bulkCompleted);
expect(response.status).toBe(401);
});
it('should reject requests with invalid signature', async () => {
const response = await request(app)
.post('/webhooks/email-verification')
.set('X-Webhook-Signature', 'invalid_signature')
.send(mockPayloads.bulkCompleted);
expect(response.status).toBe(401);
});
it('should accept requests with valid signature', async () => {
const signature = generateSignature(mockPayloads.bulkCompleted);
const response = await request(app)
.post('/webhooks/email-verification')
.set('X-Webhook-Signature', signature)
.send(mockPayloads.bulkCompleted);
expect(response.status).toBe(200);
});
});
Integração de Webhook do BillionVerify
O BillionVerify fornece suporte abrangente de webhook para eventos de verificação de email, facilitando a construção de fluxos de trabalho de verificação assíncronos.
Configurando Webhooks
Configure webhooks através do painel do BillionVerify ou da API:
// Register webhook via API
async function setupBillionVerifyWebhooks() {
const webhook = await registerWebhook(
'https://yourapp.com/webhooks/billionverify',
['bulk.completed', 'bulk.failed', 'bulk.progress'],
process.env.BILLIONVERIFY_WEBHOOK_SECRET
);
console.log('Webhook configured:', webhook);
}
Formato da Payload do Webhook
Webhooks do BillionVerify incluem informações abrangentes sobre eventos de verificação:
{
"event_type": "bulk.completed",
"webhook_id": "wh_abc123",
"job_id": "job_xyz789",
"timestamp": "2025-01-15T10:30:00Z",
"status": "completed",
"summary": {
"total": 10000,
"valid": 8500,
"invalid": 1200,
"risky": 300,
"disposable": 150,
"catch_all": 200
},
"processing_time_ms": 45000,
"download_url": "https://api.billionverify.com/v1/bulk/download/job_xyz789"
}
Exemplo de Integração Completa
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
// Webhook endpoint for BillionVerify
app.post('/webhooks/billionverify', async (req, res) => {
// Verify signature
const signature = req.headers['x-billionverify-signature'];
const isValid = verifySignature(req.body, signature);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Acknowledge immediately
res.status(200).json({ received: true });
// Process asynchronously
processWebhookAsync(req.body);
});
async function processWebhookAsync(payload) {
try {
switch (payload.event_type) {
case 'bulk.completed':
await handleBulkCompleted(payload);
break;
case 'bulk.failed':
await handleBulkFailed(payload);
break;
case 'bulk.progress':
await handleBulkProgress(payload);
break;
}
} catch (error) {
console.error('Webhook processing error:', error);
await logFailedWebhook(payload, error);
}
}
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});
Conclusão
Webhooks de verificação de email transformam a forma como as aplicações lidam com verificação em massa, habilitando processamento assíncrono eficiente, escalável e confiável. Ao implementar tratamento adequado de webhooks com medidas de segurança, tratamento de erros e monitoramento, você pode construir fluxos de trabalho robustos de verificação de email que escalam com as necessidades da sua aplicação.
Principais pontos para implementar webhooks de verificação de email:
- Responda rapidamente às requisições de webhook e processe payloads de forma assíncrona
- Verifique assinaturas para garantir que webhooks venham de fontes legítimas
- Implemente idempotência para lidar com entregas duplicadas com segurança
- Use filas de mensagens para processamento confiável em escala
- Monitore a saúde do webhook com métricas e alertas
Seja processando milhares ou milhões de verificações de email, webhooks fornecem a base para processamento assíncrono eficiente. Comece a implementar webhooks hoje com o suporte abrangente de webhook do BillionVerify e leve seus fluxos de trabalho de verificação de email para o próximo nível.