Get webhooks for email events
Add a webhook in Settings so Meisa posts to your app when an email bounces, a link is clicked, a contact changes and more, signed with HMAC-SHA256.
On this page
A webhook makes Meisa send a POST request to your app when something happens, like an email bouncing or a contact being tagged. Go to Settings, open API keys and webhooks, switch to the Webhooks tab, click Add webhook, enter your URL and pick the events.
Add a webhook
- In the sidebar, click Settings, then API keys and webhooks under Connect.
- Open the Webhooks tab.
- Click Add webhook.
- Fill in:
- Name, for example “Billing sync”.
- Address: the HTTPS URL in your app, for example
<https://yourapp.com/hooks/meisa>. - Events: tick the events you want (see below).
- Click Add webhook.
- Copy the secret shown in Your signing secret and store it in your app’s secrets. You need it to check that requests really come from Meisa.
Events you can subscribe to
| Group | Events |
|---|---|
email.sent, email.delivered, email.opened, email.clicked (Link clicked), email.bounced, email.complained (Marked as spam) |
|
| Contacts | contact.created (Contact added), contact.updated, contact.tagged (Tag added), contact.untagged (Tag removed) |
| Sequences | sequence.enrolled (Added to a sequence), sequence.completed (Finished a sequence), sequence.unenrolled (Removed from a sequence) |
| Broadcasts | campaign.sent (Broadcast started), campaign.completed (Broadcast finished) |
A common setup is email.bounced and email.complained, so your app can flag bad addresses on its side too.
What Meisa sends
Each delivery is a POST with a JSON body:
{
"event": "email.bounced",
"timestamp": "2026-11-03T10:15:00.000000+00:00",
"data": {
"email_send_id": "9b1c...",
"contact_id": "3f2a...",
"bounce_type": "Permanent",
"bounce_subtype": "General",
"auto_unsubscribed": true
}
}
And these headers:
X-Webhook-Signature: HMAC-SHA256 of the raw request body, using your signing secret, as hex.X-Webhook-Timestamp: when it was sent.X-Webhook-Event: the event name.User-Agent: Meisa-Webhook/1.0.
Verify the signature
Always check the signature before trusting a request. Compute the HMAC over the raw body exactly as received, before parsing the JSON.
Node.js (Express):
const crypto = require('crypto');
app.post('/hooks/meisa', express.raw({ type: 'application/json' }), (req, res) => {
const expected = crypto
.createHmac('sha256', process.env.MEISA_WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
const received = req.get('X-Webhook-Signature') || '';
const ok = received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!ok) return res.status(401).end();
const event = JSON.parse(req.body);
// handle event.event and event.data
res.status(200).end();
});
Python:
import hmac, hashlib, os
def is_valid(raw_body: bytes, signature: str) -> bool:
expected = hmac.new(os.environ["MEISA_WEBHOOK_SECRET"].encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature or "")
Retries
Meisa counts any response below 400 as delivered. Respond quickly (within 30 seconds) and do slow work in a background job. If the request fails or times out, Meisa retries up to 5 attempts in total, waiting longer each time (about 1, 2, 4 and 8 minutes). Because of retries, the same event can arrive twice, so make your handler safe to run more than once.
Test and monitor
From the webhook’s menu:
- Send a test: sends a sample request with the event
test. - See deliveries: the latest 50 deliveries with status codes, to debug failures.
- Edit, or switch the webhook off with its toggle.
- Change signing secret: the old secret stops working at once, so update your app right after.
- Delete.
Troubleshooting
- Signature never matches: you’re hashing the parsed and re-serialized JSON. Hash the raw body bytes instead.
- Deliveries fail with a timeout: return
200first, then process the event in the background. - No deliveries at all: check the webhook is on and the event is ticked.
Related articles
Did this answer your question?
Thanks for letting us know.Thanks, we will improve this article. Want a hand right now?
Still need help?
Chat with us and get an answer in a few minutes.