Webhooks
Get a signed POST at your endpoint the moment something happens to a message - delivered, bounced, opened or clicked.
Events
Configure webhooks per hive in the dashboard and subscribe to any of:
delivery- the receiving server accepted the message.bounce- the message hard- or soft-bounced.spam_complaint- the recipient marked it as spam.open- the recipient opened the message (open tracking on).click- the recipient clicked a tracked link (link tracking on).
How delivery works
Each event is a POST to your URL with these headers:
X-Buzzmark-Event: open
X-Buzzmark-Signature: <hex HMAC-SHA256 of the raw body, keyed with your webhook secret>
Respond with any 2xx status to acknowledge. Anything else (or a timeout) is treated as a failure and retried.
Payload
The body is JSON. The exact fields depend on the event, but every payload includes the message identifier, recipient and timestamp:
{
"RecordType": "Click",
"MessageID": "f5ab446c-...",
"Recipient": "customer@example.com",
"Tag": "welcome",
"Metadata": { "user_id": "42" },
"ReceivedAt": "2026-05-31T22:30:00+00:00",
"OriginalLink": "https://yourdomain.com/welcome"
}
Use the MessageID to tie the event back to the message you sent and to your own records via Metadata.
Verifying the signature
Compute the HMAC-SHA256 of the raw request body using your hive’s webhook secret and compare it,
in constant time, with the X-Buzzmark-Signature header. Always verify before trusting a payload.
// PHP
$expected = hash_hmac('sha256', $request->getContent(), $webhookSecret);
if (! hash_equals($expected, $request->header('X-Buzzmark-Signature'))) {
abort(401);
}
// Node.js
const crypto = require('crypto');
const expected = crypto.createHmac('sha256', webhookSecret).update(rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
Retries
Failed deliveries are retried with exponential backoff, up to 6 attempts. Every attempt is recorded in the dashboard’s delivery log, where you can inspect the response and re-queue a delivery manually. Make your endpoint idempotent - the same event may arrive more than once.
Inbound webhooks
Inbound mail is forwarded separately. Point your inbound MTA at the per-hive address shown in the dashboard
({hash}@in.buzzmarkapp.com); Buzzmark stores the parsed message and POSTs a normalised payload to
your hive’s inbound webhook URL (with the same retry policy), including an
X-Buzzmark-Inbound-Hash header.
{
"From": "sender@world.com",
"FromName": "Sender",
"To": "{hash}@in.buzzmarkapp.com",
"Subject": "Hello",
"HtmlBody": "<p>…</p>",
"TextBody": "…",
"Headers": [{ "Name": "Message-Id", "Value": "..." }],
"Attachments": [{ "Name": "file.pdf", "ContentType": "application/pdf", "ContentLength": 1234 }]
}
Next
- API reference - send mail and read your message log.
- SMTP - send through a familiar mail relay.