// reference
Webhooks.
We POST every delivery state change to a URL you control. Events are signed with HMAC-SHA256 and delivered with at-least-once semantics — dedupe by event id.
Verifying signatures
Each request carries a VoltMail-Signature header containing an HMAC-SHA256 of the raw request body, keyed with your endpoint secret.
ts// Node — verify the signature header
import crypto from 'crypto';
function verify(body: string, header: string, secret: string) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(header),
Buffer.from(expected),
);
}Events
email.sentMessage accepted by the receiving SMTP server.
Fires once per recipient, after the receiver has acknowledged with a 2xx SMTP response.
payload{
"id": "evt_01HV9X8T2U3V4W5X6Y7Z8A9B0C",
"type": "email.sent",
"created_at": "2026-05-01T12:00:01Z",
"data": {
"email_id": "em_01HV9X3Q8K2BM0F7Z8E5T6Y9N3",
"to": "jane@example.com",
"subject": "Your receipt"
}
}email.deliveredReceiver confirmed delivery to the recipient mailbox.
Fires when the destination MTA returns a 250 OK after queue processing — usually within seconds of email.sent.
payload{
"id": "evt_01HV9X8U3V4W5X6Y7Z8A9B0C1D",
"type": "email.delivered",
"created_at": "2026-05-01T12:00:08Z",
"data": {
"email_id": "em_01HV9X3Q8K2BM0F7Z8E5T6Y9N3",
"to": "jane@example.com",
"smtp_response": "250 2.0.0 OK"
}
}email.bouncedHard or soft bounce.
Fires when the receiver returns a 4xx (soft) or 5xx (hard) SMTP response. Hard bounces auto-suppress the address.
payload{
"type": "email.bounced",
"data": {
"email_id": "em_01HV9X3Q…",
"to": "missing@example.com",
"bounce_type": "hard",
"diagnostic": "550 5.1.1 user unknown"
}
}email.complainedRecipient marked the email as spam.
Fires when an FBL (feedback loop) provider reports a complaint. The address is auto-suppressed.
payload{
"type": "email.complained",
"data": {
"email_id": "em_01HV9X3Q…",
"to": "angry@example.com",
"feedback_type": "abuse"
}
}email.openedTracking pixel fetched.
Fires the first time the tracking pixel is loaded for this email. Subsequent opens are deduplicated within 24 hours.
payload{
"type": "email.opened",
"data": {
"email_id": "em_01HV9X3Q…",
"to": "jane@example.com",
"user_agent": "Mozilla/5.0 (iPhone; …) Mobile",
"ip": "203.0.113.42"
}
}email.clickedRecipient clicked a tracked link.
Fires once per (email_id, url) pair on the first click. Repeat clicks are recorded in analytics but not redelivered.
payload{
"type": "email.clicked",
"data": {
"email_id": "em_01HV9X3Q…",
"to": "jane@example.com",
"url": "https://acme.dev/orders/4711"
}
}email.unsubscribedRecipient hit one-click unsubscribe.
Fires when a recipient uses the List-Unsubscribe-Post header. Address is auto-suppressed across the workspace.
payload{
"type": "email.unsubscribed",
"data": {
"email_id": "em_01HV9X3Q…",
"to": "jane@example.com",
"method": "list-unsubscribe-post"
}
}