Skip to content

Event types

The email was accepted by the receiving MTA. Not yet delivered to the recipient’s inbox.

{
"type": "email.sent",
"created_at": "2026-04-22T22:30:02Z",
"data": {
"email_id": "a1b2...",
"from": "[email protected]",
"subject": "Your receipt",
"smtp_ip": "142.54.161.92"
}
}

The email landed in the recipient’s mailbox (or was placed in their spam folder — both count as delivered from an SMTP standpoint).

{
"type": "email.delivered",
"data": {
"email_id": "a1b2...",
"delivered_at": "2026-04-22T22:30:04Z"
}
}

Delivery failed. Hard bounces add the recipient to the suppression list.

{
"type": "email.bounced",
"data": {
"email_id": "a1b2...",
"bounce_type": "hard",
"bounce_detail": "550 5.1.1 The email account does not exist"
}
}

bounce_type is one of hard, soft, block.

The recipient marked the email as spam (received via FBL). Suppression is permanent.

{
"type": "email.complained",
"data": {
"email_id": "a1b2...",
"complained_at": "2026-04-22T23:15:00Z"
}
}

The tracking pixel was loaded.

{
"type": "email.opened",
"data": {
"email_id": "a1b2...",
"opened_at": "2026-04-22T22:35:00Z",
"user_agent": "Mozilla/5.0 ..."
}
}

Note: Apple Mail Privacy Protection auto-loads images, inflating opens. Treat clicks as the real engagement signal.

A link in the email was clicked.

{
"type": "email.clicked",
"data": {
"email_id": "a1b2...",
"clicked_at": "2026-04-22T22:36:00Z",
"url": "https://acme.com/product/123",
"user_agent": "Mozilla/5.0 ..."
}
}

Permanent failure (not a bounce — usually a configuration issue or DNS-level rejection).

{
"type": "email.failed",
"data": {
"email_id": "a1b2...",
"error": "DNS lookup failed for example.com"
}
}

Fires when a campaign finishes sending all queued emails (regardless of delivery status).

{
"type": "campaign.sent",
"data": {
"campaign_id": "camp_a1b2...",
"total_recipients": 19872,
"sent_count": 19850,
"failed_count": 22
}
}

Fires once per campaign when delivery confirmations have been received for all sent emails.

Fires when a campaign is auto-paused due to a circuit-breaker tripping.

{
"type": "campaign.auto_paused",
"data": {
"campaign_id": "camp_a1b2...",
"reason": "complaint_rate_threshold_exceeded",
"metric_value": 0.0012,
"threshold": 0.001
}
}

Subscribe to events when you create the webhook:

{
"url": "https://yourapp.com/webhooks",
"events": ["email.delivered", "email.bounced", "email.complained", "campaign.auto_paused"]
}

Subscribe to all events with the wildcard:

{ "events": ["*"] }