Когда вы проверяете тысячи или миллионы email-адресов, синхронное ожидание каждого результата непрактично. Вебхуки проверки email предоставляют элегантное решение, уведомляя ваше приложение о завершении задач проверки, устраняя необходимость постоянного опроса и обеспечивая эффективные асинхронные рабочие процессы. Это всеобъемлющее руководство охватывает всё, что разработчикам нужно знать о реализации вебхуков проверки email, от базовой настройки до продвинутых паттернов для обработки крупномасштабных операций проверки.
Понимание вебхуков проверки email
Вебхуки — это HTTP-обратные вызовы, которые доставляют данные в ваше приложение при возникновении определённых событий. В контексте проверки email вебхуки уведомляют ваши системы о завершении заданий массовой проверки, когда заканчивается проверка отдельного email в асинхронном режиме или когда происходят другие значимые события в процессе проверки.
Почему использовать вебхуки для проверки email?
Традиционные паттерны запрос-ответ хорошо работают для проверки одного email, но массовые операции представляют сложности. Проверка 100 000 email может занять часы, и держать HTTP-соединение открытым так долго нереально. Опрос обновлений статуса расходует ресурсы и создаёт ненужную нагрузку на API.
Устранение накладных расходов на опрос
Без вебхуков вам нужно было бы повторно запрашивать API, чтобы проверить, завершены ли массовые задания. Это создаёт ненужный сетевой трафик, потребляет лимиты API и добавляет сложность в приложение. Вебхуки отправляют уведомления именно тогда, когда они нужны.
Обработка в реальном времени
Вебхуки обеспечивают немедленные действия при завершении проверки. Ваше приложение может обрабатывать результаты, обновлять базы данных и запускать последующие действия без задержек, вызванных интервалами опроса.
Масштабируемая архитектура
Архитектуры на основе вебхуков масштабируются естественным образом. Независимо от того, обрабатываете ли вы одно массовое задание или сотни одновременно, ваша конечная точка вебхука получает уведомления по мере их поступления, и вы можете обрабатывать их асинхронно, используя очереди или воркеры.
Эффективность ресурсов
Вместо поддержания соединений или запуска циклов опроса ваше приложение остаётся в ожидании до прибытия вебхуков. Это снижает затраты на вычисления и упрощает инфраструктурные требования.
События вебхуков в проверке email
Сервисы проверки email обычно запускают вебхуки для нескольких типов событий:
Завершение массового задания
Самое распространённое событие вебхука срабатывает, когда массовое задание проверки завершает обработку. Полезная нагрузка включает статус задания, сводную статистику и информацию о загрузке результатов.
Прогресс массового задания
Некоторые сервисы отправляют вебхуки прогресса с интервалами во время массовой обработки, позволяя отслеживать прогресс проверки и оценивать время завершения.
Сбой массового задания
Когда массовое задание сталкивается с ошибками, которые предотвращают завершение, вебхуки сбоя предоставляют подробности о том, что пошло не так, и доступны ли частичные результаты.
Проверка одного email (асинхронный режим)
Для высоконагруженных сценариев проверки в реальном времени асинхронная проверка одного email отправляет результаты через вебхук вместо ожидания синхронного ответа.
Настройка конечных точек вебхуков
Реализация вебхуков требует создания конечной точки в вашем приложении, которая может принимать и обрабатывать полезные нагрузки вебхуков.
Базовая структура конечной точки
Конечная точка вебхука — это просто HTTP POST-конечная точка, которая принимает 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}`);
}
}
Лучшие практики ответа на вебхуки
Сервисы проверки email ожидают быстрых ответов от конечных точек вебхуков. Если ваша конечная точка отвечает слишком долго, сервис может предположить, что доставка не удалась, и повторить попытку.
Отвечайте немедленно
Подтверждайте получение вебхука немедленно, а затем обрабатывайте полезную нагрузку асинхронно:
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);
}
});
});
Используйте очереди сообщений для тяжёлой обработки
Для производственных систем ставьте полезные нагрузки вебхуков в очередь для обработки рабочими процессами:
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);
});
Настройка вебхуков через API
Зарегистрируйте вашу конечную точку вебхука в сервисе проверки 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
);
Защита конечных точек вебхуков
Конечные точки вебхуков публично доступны, что делает безопасность критически важной. Без надлежащей проверки злоумышленники могли бы отправлять поддельные полезные нагрузки вебхуков для манипулирования вашим приложением.
Проверка подписи
Большинство сервисов проверки email подписывают полезные нагрузки вебхуков, используя HMAC-SHA256 с общим секретом. Проверяйте подписи перед обработкой:
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 });
});
Проверка временной метки
Предотвратите атаки повторного воспроизведения, проверяя временные метки вебхуков:
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
});
Белый список IP-адресов
Для дополнительной безопасности ограничьте доступ к вебхукам известными IP-адресами:
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
});
Обработка идемпотентности
Вебхуки могут доставляться несколько раз из-за проблем с сетью или повторных попыток. Реализуйте идемпотентность для безопасной обработки дубликатов:
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;
}
}
Для производственных систем используйте Redis для распределённой идемпотентности:
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 });
});
Обработка полезных нагрузок вебхуков
Различные события вебхуков требуют различной логики обработки. Давайте рассмотрим общие паттерны для обработки вебхуков проверки email.
Обработка завершения массового задания
Когда массовое задание проверки завершается, загрузите и обработайте результаты:
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
});
}
});
}
Обработка сбоев массового задания
Когда задания завершаются неудачей, сохраните информацию об ошибке и определите, возможно ли восстановление:
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`);
}
Обработка обновлений прогресса
Вебхуки прогресса помогают отслеживать длительные задания:
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);
}
}
Продвинутые паттерны вебхуков
Производственные системы извлекают выгоду из продвинутых паттернов, которые улучшают надёжность и поддерживаемость.
Очередь недоставленных сообщений для неудавшихся вебхуков
Когда обработка вебхуков повторно завершается неудачей, перемещайте полезные нагрузки в очередь недоставленных сообщений для ручной проверки:
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 для вебхуков
Храните все события вебхуков для аудиторских следов и возможности воспроизведения:
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);
}
}
}
Мультитенантная маршрутизация вебхуков
Для SaaS-приложений направляйте вебхуки к обработчикам конкретных тенантов:
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)
});
}
Обработка ошибок и надёжность
Надёжные реализации вебхуков обрабатывают сбои корректно и гарантируют, что данные не будут потеряны.
Стратегии повторных попыток
Реализуйте экспоненциальную задержку для временных сбоев:
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);
}
Паттерн Circuit Breaker
Предотвратите каскадные сбои, когда нижестоящие сервисы недоступны:
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);
});
}
Мониторинг и оповещения
Отслеживайте метрики работоспособности вебхуков:
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);
Тестирование реализаций вебхуков
Тщательное тестирование гарантирует, что обработчики вебхуков работают корректно в продакшене.
Локальное тестирование с ngrok
Используйте ngrok для предоставления локальных конечных точек для тестирования вебхуков:
# Start your local server node server.js # In another terminal, expose it via ngrok ngrok http 3000
Зарегистрируйте URL ngrok в качестве конечной точки вебхука во время разработки.
Имитация полезных нагрузок вебхуков
Создайте тестовые заготовки для различных типов событий:
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');
});
});
Интеграционное тестирование
Протестируйте полный поток вебхуков, включая проверку подписи:
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);
});
});
Интеграция вебхуков BillionVerify
BillionVerify предоставляет комплексную поддержку вебхуков для событий проверки email, что упрощает создание асинхронных рабочих процессов проверки.
Настройка вебхуков
Настройте вебхуки через панель управления BillionVerify или 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);
}
Формат полезной нагрузки вебхука
Вебхуки BillionVerify включают исчерпывающую информацию о событиях проверки:
{
"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"
}
Полный пример интеграции
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');
});
Заключение
Вебхуки проверки email трансформируют то, как приложения обрабатывают массовую проверку, обеспечивая эффективную, масштабируемую и надёжную асинхронную обработку. Реализуя надлежащую обработку вебхуков с мерами безопасности, обработкой ошибок и мониторингом, вы можете создать надёжные рабочие процессы проверки email, которые масштабируются в соответствии с потребностями вашего приложения.
Ключевые выводы для реализации вебхуков проверки email:
- Отвечайте быстро на запросы вебхуков и обрабатывайте полезные нагрузки асинхронно
- Проверяйте подписи, чтобы гарантировать, что вебхуки поступают из легитимных источников
- Реализуйте идемпотентность для безопасной обработки повторных доставок
- Используйте очереди сообщений для надёжной обработки в масштабе
- Мониторьте работоспособность вебхуков с помощью метрик и оповещений
Независимо от того, обрабатываете ли вы тысячи или миллионы проверок email, вебхуки обеспечивают основу для эффективной асинхронной обработки. Начните реализовывать вебхуки сегодня с комплексной поддержкой вебхуков BillionVerify и выведите ваши рабочие процессы проверки email на новый уровень.