Guides
Webhooks (Email → API)
The payload you receive and how to verify its signature.
When mail arrives at an endpoint with a webhook destination, BetterMX POSTs a JSON payload to your URL.
json
{
"id": "msg_2b4f…",
"endpoint_id": "ep_9f…",
"received_at": "2026-06-16T10:24:01Z",
"from": { "address": "john@acme.com", "name": "John Doe" },
"subject": "PO #4821",
"text": "Need 12 units.",
"html": "<p>Need 12 units.</p>",
"attachments": [{ "filename": "po.pdf", "size": 18234, "sha256": "…" }],
"authentication": { "spf": "pass", "dkim": "pass", "dmarc": "pass" }
}Verifying the signature
Each delivery carries BetterMX-Signature: t=<unix>,v1=<hex>. Recompute the HMAC-SHA256 of "{t}.{rawBody}" with your signing secret, compare in constant time, and reject timestamps older than five minutes.
javascript
import crypto from "node:crypto";
function verify(body, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map(p => p.split("=")));
const mac = crypto.createHmac("sha256", secret).update(`${t}.${body}`).digest("hex");
if (mac !== v1) throw new Error("bad signature");
if (Math.abs(Date.now()/1000 - Number(t)) > 300) throw new Error("stale");
}Retries & replay
Non-2xx responses are retried with exponential backoff. Delivery is at-least-once and idempotent on the message id — dedupe on it. Failed deliveries can be replayed from the dashboard.