Examail Webhooks
Configure a webhook in the Sendexa dashboard under Developers → Webhooks and subscribe to delivery events instead of polling /v1/email/status/:messageId.
Real-time delivery
Get notified the moment a message is sent, delivered, bounces, or is marked as spam.
Signed payloads
Every webhook is signed with HMAC-SHA256 in the X-Sendexa-Signature header — verify it before trusting the body.
One pipeline, two sources
Events land the same way whether the message was sent via the REST API or picked up as a bounce/DSN by Examail's own mail node.
Where events come from
EmailMessagerow — you don't configure anything for this, it's automatic once you're sending through Examail.Sendexa POSTs signed JSON to your endpoint whenever a message's status changes.
Example payload
{"channel": "EMAIL","event": "email.delivered","messageId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","to": ["user@example.com"],"subject": "Welcome to Sendexa","status": "DELIVERED","cost": 0.0001}
Events
| Sendexa event | Fires when | Meaning |
|---|---|---|
| MESSAGE_SENT | Provider accepts the message | Handed off for delivery |
| MESSAGE_DELIVERED | Delivered / opened / clicked | Reached the inbox, optionally engaged |
| MESSAGE_FAILED | Hard bounce, DSN failure, or complaint | Recipient auto-added to your suppression list |
Emails submitted via SMTP relay currently only fire MESSAGE_SENT — bounce-back tracking for that path is on the roadmap (see the SMTP relay docs for the full list of current limitations).
Verify signature
Header:
const crypto = require("crypto");function verifyWebhook(rawBody, signature, secret) {const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");return crypto.timingSafeEqual(Buffer.from(expected),Buffer.from(signature || ""),);}
POST /v1/email/send — send a message
GET /v1/email/status/:messageId — poll status, history, and stats
GET /v1/email/suppressions — see who's been auto-suppressed from bounces/complaints