Start typing to search the documentation.

to navigate·to open

Webhooks

Email Webhooks

Receive email lifecycle and engagement events (delivered, opened, clicked, bounced, complained, unsubscribed, and more) — registration, the signed payload envelope, HMAC-SHA256 verification, and retries.

Email webhooks push delivery and engagement events to an HTTPS endpoint you control. They use the same envelope, signing scheme, and retry behaviour as SMS webhooks — only the event names differ.

Events

Event Fired when
email.queued The message is accepted and queued.
email.sent The message is handed to the mail relay.
email.delivered The message is delivered to the inbox.
email.opened The recipient opened the message.
email.clicked The recipient clicked a tracked link.
email.bounced The message bounced.
email.complained The recipient marked it as spam.
email.unsubscribed The recipient unsubscribed.
email.failed The message could not be sent.

Register an endpoint

Add and manage endpoints from the Email app → Webhooks page. Provide a URL, an optional description, and the events to subscribe to. WRNexus returns a whsec_-prefixed signing secret once on creation — copy and store it. You can pause, edit, delete, and send a test event to verify wiring.

Payload

Deliveries are POST requests, Content-Type: application/json, with the canonical envelope:

{
  "id": "whd_8f1c0e2b-...",
  "event": "email.opened",
  "createdAt": "2026-06-18T14:32:10Z",
  "data": {
    "messageId": "f58a2939-2c4b-4f0a-9b7e-1f2a3b4c5d6e",
    "recipient": "customer@example.com",
    "url": null
  }
}

For email.clicked, data.url is the clicked link; for email.bounced / email.complained, data.reason carries the reason. id is a unique delivery id, reused across re-deliveries for idempotent dedupe.

Verify the signature

Every delivery includes an HMAC of the raw body in X-WRNexus-Signature:

X-WRNexus-Signature: sha256=<hex-hmac>

It is HMAC-SHA256 keyed by your endpoint’s whsec_ secret. Recompute over the raw body and compare in constant time — the verification code is identical to the SMS webhook example.

const crypto = require('crypto');
const expected =
  'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const ok =
  expected.length === header.length &&
  crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));

Responding & retries

  • Acknowledge with any 2xx within a few seconds.
  • Retries up to 5 attempts with exponential back-off (≈ 1s, 2s, 4s, 8s, capped at 60s) on any non-2xx or transport error.
  • Idempotency — dedupe on the stable delivery id.

See also