BavimailBavimail

Signed webhook deliveries backed by the real event model

Bavimail emits outbound lifecycle events, inbound receipt events, domain verification events, and test pings. Verification should match the actual SDK helper and header contract.

Last updated May 29, 2026

Event Types

These event names come from the backend enum and should be treated as the public contract for webhook subscriptions.

EventDescription
email.inbound.receivedInbound email accepted and parsed.
email.outbound.sentOutbound delivery or engagement lifecycle event.
email.outbound.failedOutbound delivery or engagement lifecycle event.
email.outbound.openedOutbound delivery or engagement lifecycle event.
email.outbound.clickedOutbound delivery or engagement lifecycle event.
email.outbound.scheduledOutbound delivery or engagement lifecycle event.
email.outbound.cancelledOutbound delivery or engagement lifecycle event.
email.outbound.deliveredOutbound delivery or engagement lifecycle event.
email.outbound.bouncedOutbound delivery or engagement lifecycle event.
email.outbound.complainedOutbound delivery or engagement lifecycle event.
domain.verifiedDomain verification state update.
domain.failedDomain verification state update.
webhook.testWebhook test delivery.

Verification flow

Verify the raw JSON payload against the exact signature headers before trusting the event body. The webhook secret is hex-encoded and is used as the HMAC key.

import { verifyWebhookSignature } from 'bavimail'

app.post('/webhooks/email', async (req, res) => {
  const payload = JSON.stringify(req.body)
  const event = await verifyWebhookSignature(
    payload,
    req.headers['x-webhook-signature'],
    req.headers['x-webhook-timestamp'],
    process.env.BAVIMAIL_WEBHOOK_SECRET!,
  )

  switch (event.eventType) {
    case 'email.outbound.delivered':
    case 'email.outbound.opened':
    case 'email.outbound.clicked':
    case 'email.outbound.bounced':
      await reconcileEmailState(event)
      break
  }

  res.status(200).end()
})

Delivery contract

Headers

x-webhook-signature x-webhook-timestamp

Store the event id, event type, and timestamp so retries can be handled idempotently in your own system.

Do not document suppression updates as webhook events. The current emitted set is outbound lifecycle, inbound receipt, domain verification, and test traffic only.

Verify x-webhook-signature and x-webhook-timestamp before parsing the body as a trusted event.

How does Bavimail handle webhook signatures and retries?

Every webhook is signed with an HMAC header (x-webhook-signature) and timestamped (x-webhook-timestamp). Your handler verifies both and returns 2xx to acknowledge. On non-2xx or timeout, Bavimail retries with exponential backoff. The 13 supported event types are documented at /docs/webhooks.

Do you handle bounce processing?

Automatically. Bavimail processes bounces, complaints, and unsubscribes in real-time. Suppression lists update instantly so you never send to a bad address twice.

Event meanings

EventDescription
email.inbound.receivedA new inbound email was received and parsed.
email.outbound.sentAn outbound email was accepted for delivery.
email.outbound.deliveredAn outbound email was delivered to the recipient's mail server.
email.outbound.openedA recipient opened an outbound email (pixel tracking).
email.outbound.clickedA recipient clicked a link in an outbound email.
email.outbound.bouncedAn outbound email bounced (hard or soft).
email.outbound.complainedA recipient marked an outbound email as spam.
email.outbound.failedAn outbound email permanently failed to send.
email.outbound.scheduledAn outbound email was scheduled for future delivery.
email.outbound.cancelledA scheduled outbound email was cancelled before sending.
domain.verifiedA domain passed DNS verification.
domain.failedA domain failed DNS verification after retries.
webhook.testA test event sent when you create or test a webhook endpoint.

Example wire payload

The following delivery event illustrates the snake_case envelope. Event-specific data varies; see the inbound guide for an inbound example.

{
  "event_id": "evt_abc123",
  "event_type": "email.outbound.delivered",
  "timestamp": "2026-04-11T14:30:00Z",
  "data": {
    "email_id": "em_xyz789",
    "alias_id": "alias_abc123",
    "to_email": "[email protected]",
    "subject": "Hello from Bavimail",
    "delivered_at": "2026-04-11T14:30:00Z"
  }
}

Receiving events

  • Return a successful response quickly and process the event asynchronously.
  • Be idempotent. Use the event_id field to deduplicate. Bavimail may deliver the same event more than once.
  • Subscribe only to events you need. Reduces noise and processing load.