Skip to main content

Webhooks

If you prefer the traditional push model, you can configure webhooks. We will send a POST request to your URL for every event.

Payload

The payload structure is identical to the Event object used in streams.
{
  "id": "evt_8923...",
  "type": "EMAIL_DELIVERED",
  "timestamp": "2024-01-01T12:00:00Z",
  "payload": {
    "email_id": "msg_123...",
    "recipients": ["[email protected]"],
    "smtp_response": "250 OK"
  }
}

Event Types

EventDescription
email.sentEmail successfully queued for delivery
email.deliveredEmail delivered to recipient’s mailserver
email.failedEmail delivery permanently failed
email.bouncedEmail bounced (hard or soft)
email.openedRecipient opened the email
email.clickedRecipient clicked a link

Security: Verifying Signatures

We verify the identity of the sender using Svix conventions (standard HTTP headers).
import { Webhook } from 'svix';

const secret = "whsec_...";
const headers = request.headers;
const payload = request.body;

const wh = new Webhook(secret);
const evt = wh.verify(payload, headers);

// Safe to process 'evt'
Always verify webhook signatures before processing. Never trust the payload without verification.

Creating a Webhook

You can create webhooks via the dashboard or the API:
const webhook = await client.webhooks.create({
  name: 'My Webhook',
  url: 'https://your-app.com/webhooks/email',
  events: ['email.delivered', 'email.bounced']
});

// Store webhook.secret securely - it's only shown once!
console.log('Secret:', webhook.secret);

Retry Policy

We retry failed webhook deliveries with exponential backoff:
AttemptDelay
1Immediate
25 seconds
330 seconds
42 minutes
510 minutes
61 hour
After 6 failed attempts, the webhook is marked as failing and paused. You can re-enable it from the dashboard.