[04]Sending
Webhooks
Configure up to five endpoints per workspace. Every delivery carries an HMAC-SHA256 signature over "{timestamp}.{raw body}". Verify it in constant time and reject anything where the timestamp is more than 300 seconds old. Event ids are stable across retries, so your consumer must be idempotent.
Mailhaap-Signature: t=1755792000,v1=5257a869e7ecebeda32affa62cdca3fa...
Mailhaap-Event-Id: evt_01J8XQ...
Mailhaap-Delivery-Attempt: 1Retry schedule
Seven attempts over 24 hours: immediately, then 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 24 hours. After seven consecutive failures the endpoint moves to disabled_by_failures and the owner is emailed. Every undelivered event stays fetchable from GET /v1/events, so a disabled endpoint never means lost data.
Event types
- email.queued · email.sent · email.delivered · email.deferred
- email.bounced · email.complained · email.failed
- email.opened · email.clicked
- contact.unsubscribed
- domain.verified · domain.degraded
- campaign.completed · campaign.throttled · campaign.blocked
- tenant.limit_reached
{
"id": "evt_01J8XQ...",
"type": "email.bounced",
"created_at": "2026-08-21T16:05:02.114Z",
"api_version": "2026-08-01",
"data": {
"message_id": "msg_01J8XQ...",
"to": "[email protected]",
"from": "[email protected]",
"subject": "Order A-1043 confirmed",
"tags": [{ "name": "category", "value": "order_confirmation" }],
"bounce": {
"class": "hard",
"subtype": "mailbox_not_found",
"smtp_code": "550"
}
}
}A block is not a hard bounce
bounce.class can be hard, soft, block or technical. A block is a rejection caused by receiver policy or sender reputation — it is about us, not the recipient. Suppressing on a block would destroy your list for a problem that was ours, so we do not, and neither should you.