Webhooks
Receive real-time notifications when email events occur.
Create a Webhook
Create a webhook endpoint to receive event notifications.
POST /v1/webhookscreate-webhook.ts
const webhook = await client.webhooks.create({
url: 'https://example.com/webhooks/veilmail',
events: [
'email.delivered',
'email.bounced',
'email.complained',
'subscriber.unsubscribed',
],
description: 'Production webhook',
});
// Save the secret for signature verification
console.log(webhook.secret); // whsec_xxxxxEvent Types
Subscribe to the following event types:
| Event | Description |
|---|---|
email.sent | Email was sent |
email.delivered | Email was delivered |
email.opened | Email was opened |
email.clicked | Link in email was clicked |
email.bounced | Email bounced |
email.complained | Recipient marked as spam |
email.failed | Email failed to send |
subscriber.added | Subscriber was added |
subscriber.removed | Subscriber was removed |
subscriber.unsubscribed | Subscriber unsubscribed |
campaign.sent | Campaign started sending |
campaign.completed | Campaign finished sending |
Webhook Payload
Webhook payloads are JSON objects with the following structure:
{
"id": "evt_xxxxx",
"type": "email.delivered",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"emailId": "email_xxxxx",
"to": "user@example.com",
"subject": "Welcome!",
"deliveredAt": "2024-01-15T10:30:00Z"
}
}Signature Verification
Verify webhook signatures to ensure requests are from Veil Mail. The signature is included in the X-VeilMail-Signature header.
verify-webhook.ts
import crypto from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Express.js example
app.post('/webhooks/veilmail', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-veilmail-signature'];
const payload = req.body.toString();
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(payload);
switch (event.type) {
case 'email.delivered':
console.log('Email delivered:', event.data.emailId);
break;
case 'email.bounced':
console.log('Email bounced:', event.data.emailId);
break;
}
res.status(200).send('OK');
});Retry Behavior
Webhook deliveries are retried with exponential backoff if your endpoint returns an error or is unreachable.
- Retries: Up to 5 attempts
- Backoff: 1 minute, 5 minutes, 30 minutes, 2 hours, 24 hours
- Success: HTTP 2xx response within 30 seconds
Test a Webhook
Send a test event to verify your webhook endpoint is working correctly.
POST /v1/webhooks/:id/testtest-webhook.ts
const result = await client.webhooks.test('webhook_xxxxx');
if (result.success) {
console.log(`Webhook responded in ${result.responseTime}ms`);
} else {
console.log('Webhook test failed:', result.error);
}Rotate Signing Secret
Rotate your webhook signing secret for security.
POST /v1/webhooks/:id/rotate-secretrotate-secret.ts
const webhook = await client.webhooks.rotateSecret('webhook_xxxxx');
// Update your application with the new secret
console.log(webhook.secret); // whsec_new_xxxxx