ZevSend Docs
Sign up

Webhooks

Event catalogue

Every webhook event you can subscribe to and the payload shape it carries.

Each event uses the same envelope. The shape of data varies by channel.

{
  "id": "whe_…",
  "type": "<event.name>",
  "created_at": "2025-05-24T12:34:56.789Z",
  "data": { ... }
}

Email events

email.sent

Fires when the upstream network accepts the email for delivery. This is the first signal that the message has left ZevSend.

email.delivered

Fires when the recipient’s mail server accepts the message.

email.bounced

Permanent delivery failure — the address is invalid or the inbox refused the message. The recipient is automatically added to your team’s suppression list.

{
  "id": "whe_…",
  "type": "email.bounced",
  "created_at": "…",
  "data": {
    "message": {
      "public_id": "eml_…",
      "from_address": "noreply@acme.com",
      "to_address": "deleted@example.com",
      "subject": "Your receipt",
      "status": "bounced",
      "sandbox": false,
      "sent_at": "…"
    },
    "reason": "smtp; 550 5.1.1 No such user"
  }
}

email.complained

Recipient marked the message as spam. The recipient is automatically added to your team’s suppression list.

email.failed

Delivery permanently failed for a non-bounce reason — e.g. the upstream network rejected the message before submitting.

SMS events

sms.sent

Fires when the network accepts the SMS for delivery.

sms.delivered

Fires when the recipient’s handset confirms receipt via a network delivery report.

{
  "id": "whe_…",
  "type": "sms.delivered",
  "created_at": "…",
  "data": {
    "message": {
      "public_id": "sms_…",
      "to_phone": "+2348012345678",
      "status": "delivered",
      "sandbox": false,
      "sent_at": "…"
    }
  }
}

sms.failed

Synchronous rejection at submit time or a permanent failure reported by a later delivery report. The reason field holds the network’s diagnostic where available.

WhatsApp events

whatsapp.sent

Fires when the network accepts the template send.

whatsapp.delivered

Fires when the recipient’s device confirms receipt.

whatsapp.read

Fires when the recipient opens the conversation. This event is best-effort — recipients with read receipts disabled never trigger it.

{
  "id": "whe_…",
  "type": "whatsapp.read",
  "created_at": "…",
  "data": {
    "message": {
      "public_id": "wam_…",
      "to_phone": "+2348012345678",
      "status": "read",
      "sandbox": false,
      "sent_at": "…"
    }
  }
}

whatsapp.failed

Rejected at submit time or a permanent delivery failure. The reason field surfaces the network’s error message.

Ordering and duplicates

We deliver events in order whenever the network behind them provides ordering, but you should not depend on perfect ordering. Two safe patterns:

  • Treat each event as a state assertion, not a transition. An email.delivered for a message that’s already at bounced in your store is a stale event and you should ignore it.
  • Use the id field as your dedupe key. We retry on failure, so the same event may arrive more than once.

Updated at, Thursday, October 1, 2026