Skip to content
MailHaap
[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.

Headers on every delivery
Mailhaap-Signature: t=1755792000,v1=5257a869e7ecebeda32affa62cdca3fa...
Mailhaap-Event-Id: evt_01J8XQ...
Mailhaap-Delivery-Attempt: 1

Retry 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
email.bounced
{
  "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.