Event Types
The Email API fires nine event types. Subscribe to all of them or
just the ones you care about via the matching_event_types array
on the destination config.
| Event | When it fires | Header value |
|---|---|---|
Send | We accept the API call + queue the email | Send |
Delivery | Recipient MX returns 250 OK | Delivery |
Bounce | Hard or soft bounce | Bounce |
Complaint | Recipient marks as spam (FBL report) | Complaint |
Open | Recipient opens the email (pixel loaded) | Open |
Click | Recipient clicks a link in the email | Click |
Reject | We refused to send (suppression list, etc.) | Reject |
RenderingFailure | Template variable substitution failed | RenderingFailure |
DeliveryDelay | Soft bounce — will retry | DeliveryDelay |
Every payload starts with the same envelope:
{
"eventType": "<EventName>",
"mail": {
"timestamp": "ISO8601",
"messageId": "uuid",
"source": "from-address",
"destination": ["to-address"]
},
"<eventTypeLowercase>": { ... }
}Below: the event-specific block for each type.
Send
Fires when the API accepts your call. The email is now in the queue — no MX attempt yet.
{
"eventType": "Send",
"mail": {
"timestamp": "2026-05-03T12:34:56.123Z",
"messageId": "550e8400-e29b-41d4-a716-446655440000",
"source": "[email protected]",
"destination": ["[email protected]"]
},
"send": {}
}Delivery
Fires when the recipient’s mailbox provider accepts the email (250 OK). This is the strongest delivery signal — the receiving server has accepted the message for the recipient’s mailbox.
{
"eventType": "Delivery",
"mail": { ... },
"delivery": {
"timestamp": "2026-05-03T12:34:57.456Z",
"recipients": ["[email protected]"],
"smtpResponse": "250 OK"
}
}Bounce
Hard bounce (Permanent) means the address is dead — recipient is
auto-added to your suppression list. Soft bounce (Transient) means
mailbox-full / server-down / etc. — we retry up to 3 times before
giving up.
{
"eventType": "Bounce",
"mail": { ... },
"bounce": {
"timestamp": "2026-05-03T12:34:58.789Z",
"bounceType": "Permanent",
"bounceSubType": "no_such_user",
"bouncedRecipients": [
{
"emailAddress": "[email protected]",
"diagnosticCode": "550 5.1.1 user unknown"
}
]
}
}Complaint
Recipient marked the email as spam. We received the FBL (feedback- loop) report from their inbox provider and auto-suppressed the address. Complaints are critical to monitor — high complaint rates trigger reputation-based sending pauses.
{
"eventType": "Complaint",
"mail": { ... },
"complaint": {
"timestamp": "2026-05-03T12:35:10.123Z",
"complaintFeedbackType": "abuse",
"complainedRecipients": [
{ "emailAddress": "[email protected]" }
]
}
}Open
Recipient opened the email — the 1×1 tracking pixel loaded. Privacy- focused mail clients (Apple Mail, etc.) pre-load the pixel proactively, so opens are a directional signal, not an exact one.
{
"eventType": "Open",
"mail": { ... },
"open": {
"timestamp": "2026-05-03T12:36:00.000Z",
"ipAddress": "203.0.113.42",
"userAgent": "Mozilla/5.0 (iPhone; ...)"
}
}Click
Recipient clicked a tracked link. We rewrite every <a href> in the
HTML body through a redirect proxy that records the click + 302s to
the original URL. Unsubscribe links are NOT tracked.
{
"eventType": "Click",
"mail": { ... },
"click": {
"timestamp": "2026-05-03T12:37:00.000Z",
"ipAddress": "203.0.113.42",
"userAgent": "Mozilla/5.0 (Macintosh; ...)",
"link": "https://yourapp.com/dashboard"
}
}Reject
We refused to send. Common reasons: recipient on suppression list, sandbox limit reached, sending paused.
{
"eventType": "Reject",
"mail": { ... },
"reject": {
"reason": "address on suppression list"
}
}Reply
A recipient replied to one of your emails. We catch replies via a
unique Reply-To: reply+<token>@mail.splashifypro.com we stamp on
every outbound (token encodes the original outbox_id). When the
reply lands at our inbound listener, we parse it, look up which
outbound it’s responding to, and fire this event.
{
"eventType": "Reply",
"mail": { ... },
"reply": {
"outbox_id": "f8c5def1-1234-5678-9abc-def012345678",
"original_recipient": "[email protected]",
"from": "Customer Name <[email protected]>",
"subject": "Re: Your order has shipped",
"message_id": "<[email protected]>",
"in_reply_to": "<[email protected]>",
"references": "<[email protected]>",
"text_body": "Thanks! When can I expect delivery?...",
"html_body": "<div dir=\"ltr\">Thanks! When can I expect...",
"received_at": "2026-05-04T09:15:30.123Z"
}
}text_body is truncated to 32 KB and html_body to 64 KB — long
quoted-thread replies stay inside the webhook envelope without
bloating it. Use in_reply_to + references for thread correlation
on your side.
Disabling reply capture. If you’d rather replies go directly to
the address in your From header (or your own Reply-To if you
set one), pass Reply-To: [email protected] on your send
request — when the field is non-empty we won’t override it. Replies
then route directly to your address and we never see them.
Replies that were already in flight when you change the setting still arrive at the original
reply+<token>address until the recipient updates their thread.
RenderingFailure
Template variable substitution failed — {{variable}} referenced
in template body wasn’t supplied at send time, OR was malformed.
{
"eventType": "RenderingFailure",
"mail": { ... },
"renderingFailure": {
"templateName": "welcome",
"errorMessage": "missing required variable: first_name"
}
}DeliveryDelay
Soft bounce — we’ll retry. Fires once on the first retry-eligible soft bounce so you can surface a “delivery delayed” UI without waiting for the final outcome.
{
"eventType": "DeliveryDelay",
"mail": { ... },
"deliveryDelay": {
"timestamp": "2026-05-03T12:34:59.000Z",
"delayType": "TemporaryFailure",
"delayedRecipients": ["[email protected]"]
}
}Subscribing to a subset
Want only bounces and complaints? Set matching_event_types on the
destination:
curl ... -d '{
"name": "deliverability-alerts",
"destination_type": "WEBHOOK",
"webhook_url": "https://yourapp.com/webhooks/deliverability",
"webhook_secret": "...",
"matching_event_types": ["bounce", "complaint"]
}'Empty array = subscribe to everything. Specific list = events not on the list are skipped.
Multiple destinations per config set
You can attach multiple webhook destinations to a single config set — one for engagement events (open / click), one for deliverability alerts (bounce / complaint), one for archival (everything). Each destination delivers + retries independently.