Lorsque vous vérifiez des milliers ou des millions d'adresses email, attendre de manière synchrone chaque résultat n'est pas pratique. Les webhooks de vérification d'email offrent une solution élégante en notifiant votre application lorsque les tâches de vérification sont terminées, éliminant le besoin d'interrogation constante et permettant des workflows asynchrones efficaces. Ce guide complet explore tout ce que les développeurs doivent savoir sur l'implémentation des webhooks de vérification d'email, de la configuration de base aux patterns avancés pour gérer des opérations de vérification à grande échelle.
Comprendre les webhooks de vérification d'email
Les webhooks sont des callbacks HTTP qui transmettent des données à votre application lorsque des événements spécifiques se produisent. Dans le contexte de la vérification d'email, les webhooks notifient vos systèmes lorsque les tâches de vérification en masse sont terminées, lorsque la vérification d'un email individuel se termine en mode asynchrone, ou lorsque d'autres événements significatifs se produisent pendant le processus de vérification.
Pourquoi utiliser des webhooks pour la vérification d'email ?
Les patterns traditionnels de requête-réponse fonctionnent bien pour la vérification d'un seul email, mais les opérations en masse présentent des défis. Vérifier 100 000 emails peut prendre des heures, et maintenir une connexion HTTP ouverte aussi longtemps n'est pas réalisable. L'interrogation pour les mises à jour de statut gaspille des ressources et crée une charge API inutile.
Élimination de la surcharge d'interrogation
Sans webhooks, vous devriez interroger l'API de manière répétée pour vérifier si les tâches en masse sont terminées. Cela crée un trafic réseau inutile, consomme les limites de taux de l'API et ajoute de la complexité à votre application. Les webhooks vous envoient des notifications exactement quand elles sont nécessaires.
Traitement en temps réel
Les webhooks permettent une action immédiate lorsque la vérification est terminée. Votre application peut traiter les résultats, mettre à jour les bases de données et déclencher des actions de suivi sans délais introduits par les intervalles d'interrogation.
Architecture évolutive
Les architectures basées sur les webhooks évoluent naturellement. Que vous traitiez une tâche en masse ou des centaines simultanément, votre endpoint de webhook reçoit les notifications au fur et à mesure qu'elles arrivent, et vous pouvez les traiter de manière asynchrone en utilisant des files d'attente ou des workers.
Efficacité des ressources
Au lieu de maintenir des connexions ou d'exécuter des boucles d'interrogation, votre application reste inactive jusqu'à l'arrivée des webhooks. Cela réduit les coûts de calcul et simplifie les exigences d'infrastructure.
Événements webhook dans la vérification d'email
Les services de vérification d'email déclenchent généralement des webhooks pour plusieurs types d'événements :
Achèvement de tâche en masse
L'événement webhook le plus courant se déclenche lorsqu'une tâche de vérification en masse termine son traitement. La charge utile inclut le statut de la tâche, les statistiques récapitulatives et les informations sur le téléchargement des résultats.
Progression de tâche en masse
Certains services envoient des webhooks de progression à intervalles pendant le traitement en masse, vous permettant de suivre la progression de la vérification et d'estimer le temps d'achèvement.
Échec de tâche en masse
Lorsqu'une tâche en masse rencontre des erreurs qui empêchent son achèvement, les webhooks d'échec fournissent des détails sur ce qui s'est mal passé et si des résultats partiels sont disponibles.
Vérification d'email unique (mode asynchrone)
Pour les scénarios de vérification en temps réel à haut volume, la vérification asynchrone d'email unique envoie les résultats via webhook au lieu d'attendre une réponse synchrone.
Configuration des endpoints webhook
L'implémentation des webhooks nécessite la création d'un endpoint dans votre application qui peut recevoir et traiter les charges utiles des webhooks.
Structure d'endpoint de base
Un endpoint webhook est simplement un endpoint HTTP POST qui accepte des charges utiles 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}`);
}
}
Meilleures pratiques pour les réponses webhook
Les services de vérification d'email attendent des réponses rapides des endpoints webhook. Si votre endpoint met trop de temps à répondre, le service peut supposer que la livraison a échoué et réessayer.
Répondre immédiatement
Accusez réception du webhook immédiatement, puis traitez la charge utile de manière asynchrone :
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);
}
});
});
Utiliser des files d'attente de messages pour le traitement lourd
Pour les systèmes de production, mettez en file d'attente les charges utiles des webhooks pour traitement par des processus workers :
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);
});
Configuration des webhooks avec l'API
Enregistrez votre endpoint webhook auprès du service de vérification d'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
);
Sécurisation des endpoints webhook
Les endpoints webhook sont publiquement accessibles, ce qui rend la sécurité essentielle. Sans vérification appropriée, des attaquants pourraient envoyer de fausses charges utiles webhook pour manipuler votre application.
Vérification de signature
La plupart des services de vérification d'email signent les charges utiles webhook en utilisant HMAC-SHA256 avec un secret partagé. Vérifiez les signatures avant le traitement :
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 });
});
Validation de l'horodatage
Prévenez les attaques par rejeu en validant les horodatages des webhooks :
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
});
Liste blanche d'IP
Pour une sécurité supplémentaire, restreignez l'accès webhook aux adresses IP connues :
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
});
Gestion de l'idempotence
Les webhooks peuvent être livrés plusieurs fois en raison de problèmes réseau ou de nouvelles tentatives. Implémentez l'idempotence pour gérer les doublons en toute sécurité :
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;
}
}
Pour les systèmes de production, utilisez Redis pour l'idempotence distribuée :
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 });
});
Traitement des charges utiles webhook
Différents événements webhook nécessitent différentes logiques de traitement. Explorons les patterns courants pour traiter les webhooks de vérification d'email.
Gestion de l'achèvement de tâche en masse
Lorsqu'une tâche de vérification en masse est terminée, téléchargez et traitez les résultats :
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
});
}
});
}
Gestion des échecs de tâche en masse
Lorsque les tâches échouent, capturez les informations d'erreur et déterminez si la récupération est possible :
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`);
}
Gestion des mises à jour de progression
Les webhooks de progression aident à suivre les tâches de longue durée :
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);
}
}
Patterns webhook avancés
Les systèmes de production bénéficient de patterns avancés qui améliorent la fiabilité et la maintenabilité.
File d'attente des lettres mortes pour les webhooks échoués
Lorsque le traitement des webhooks échoue de manière répétée, déplacez les charges utiles vers une file d'attente des lettres mortes pour révision manuelle :
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
});
});
Sourcing d'événements webhook
Stockez tous les événements webhook pour les pistes d'audit et la capacité de rejeu :
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);
}
}
}
Routage webhook multi-locataire
Pour les applications SaaS, routez les webhooks vers des gestionnaires spécifiques au locataire :
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)
});
}
Gestion des erreurs et fiabilité
Les implémentations webhook robustes gèrent les échecs avec élégance et garantissent qu'aucune donnée n'est perdue.
Stratégies de nouvelle tentative
Implémentez un backoff exponentiel pour les échecs transitoires :
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);
}
Pattern de disjoncteur
Prévenez les échecs en cascade lorsque les services en aval sont indisponibles :
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);
});
}
Surveillance et alertes
Suivez les métriques de santé des webhooks :
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);
Tests des implémentations webhook
Des tests approfondis garantissent que les gestionnaires webhook fonctionnent correctement en production.
Tests locaux avec ngrok
Utilisez ngrok pour exposer les endpoints locaux pour les tests webhook :
# Start your local server node server.js # In another terminal, expose it via ngrok ngrok http 3000
Enregistrez l'URL ngrok comme endpoint webhook pendant le développement.
Charges utiles webhook simulées
Créez des fixtures de test pour différents types d'événements :
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');
});
});
Tests d'intégration
Testez le flux webhook complet incluant la vérification de signature :
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);
});
});
Intégration webhook BillionVerify
BillionVerify fournit un support webhook complet pour les événements de vérification d'email, facilitant la création de workflows de vérification asynchrones.
Configuration des webhooks
Configurez les webhooks via le tableau de bord BillionVerify ou l'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);
}
Format de charge utile webhook
Les webhooks BillionVerify incluent des informations complètes sur les événements de vérification :
{
"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"
}
Exemple d'intégration complète
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');
});
Conclusion
Les webhooks de vérification d'email transforment la façon dont les applications gèrent la vérification en masse en permettant un traitement asynchrone efficace, évolutif et fiable. En implémentant une gestion appropriée des webhooks avec des mesures de sécurité, une gestion des erreurs et une surveillance, vous pouvez construire des workflows de vérification d'email robustes qui évoluent avec les besoins de votre application.
Points clés à retenir pour l'implémentation des webhooks de vérification d'email :
- Répondez rapidement aux requêtes webhook et traitez les charges utiles de manière asynchrone
- Vérifiez les signatures pour garantir que les webhooks proviennent de sources légitimes
- Implémentez l'idempotence pour gérer les livraisons en double en toute sécurité
- Utilisez des files d'attente de messages pour un traitement fiable à grande échelle
- Surveillez la santé des webhooks avec des métriques et des alertes
Que vous traitiez des milliers ou des millions de vérifications d'email, les webhooks fournissent les fondations pour un traitement asynchrone efficace. Commencez à implémenter des webhooks dès aujourd'hui avec le support webhook complet de BillionVerify et faites passer vos workflows de vérification d'email au niveau supérieur.