Email callback payloads
Delivery and engagement webhook JSON — field reference and examples for Connect HTTP send.
Email callback payloads
Reference for the JSON Routee POSTs to your webhook URLs when you configure callback on POST /transactional-email on Connect.
Setup first: Receive transactional email delivery callbacks — how to register
statusCallbackandeventCallbackURLs, retry rules, and firewall notes.
Overview
On https://connect.routee.net/transactional-email, Routee delivers callbacks as a JSON object with batchId, messageId, status, results[], and optional reason (failures) or click (engagement).
SMTP relay does not use these webhooks — use Search email tracking or portal logs instead.
Configure on send (reminder)
{
"from": { "address": "[email protected]" },
"to": [{ "address": "[email protected]" }],
"subject": "Order shipped",
"content": { "html": "<p>Your order is on the way.</p>" },
"callback": {
"statusCallback": {
"strategy": "OnChange",
"url": "https://partner.example/webhooks/email-status"
},
"eventCallback": {
"onOpen": "https://partner.example/webhooks/email-open",
"onClick": "https://partner.example/webhooks/email-click"
}
}
}| Send-time field | Used for |
|---|---|
statusCallback | Delivery lifecycle (QUEUED, DELIVERED, BOUNCED, …) |
eventCallback.onOpen / onClick | Engagement (OPENED, CLICKED) |
strategy: OnChange (every transition) or OnCompletion (terminal delivery only). Applies to status callbacks.
Identifiers
| Field | Where | Meaning |
|---|---|---|
trackingId | Send response | Batch id for the send — use with Get email tracking (batch summary) |
batchId | Callback payload | Same value as trackingId |
messageId | Callback payload | Per-recipient id — use with Get email tracking (recipient timeline) |
Multi-recipient sends: one trackingId / batchId, many messageId values.
Delivery status (statusCallback.url)
statusCallback.url)Routee POSTs a JSON object to your status URL. Top-level status values include:
QUEUED, SENT, DIFFERED, DELIVERED, BOUNCED, FAILED, UNDELIVERED
Common fields
| Field | Type | Description |
|---|---|---|
batchId | string | Batch tracking id (send response trackingId) |
messageId | string | Per-recipient message id |
createdAt, updatedAt | string (ISO-8601) | Timestamps |
status | string | Current delivery status (see enum above) |
from, to | string | Envelope addresses |
sender | string | From address (email) |
subject | string | Subject line (max 144 chars when present) |
cc, label | string | Optional |
results[] | array | Status history — each item has updatedAt, status |
customHeaders[] | array | Optional { name, value } pairs |
reason | object | Optional on failure/bounce — see below |
reason (failures & bounces)
reason (failures & bounces)Present when diagnostic detail is available:
| Field | Description |
|---|---|
description | Human-readable SMTP or processing message |
code | Provider or internal code when available |
deliveryStatus | Underlying delivery status string |
dsn | Parsed DSN map when available |
Example — delivered
{
"batchId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"messageId": "507f1f77bcf86cd799439011",
"createdAt": "2026-07-14T08:15:00Z",
"updatedAt": "2026-07-14T08:16:22Z",
"status": "DELIVERED",
"from": "[email protected]",
"to": "[email protected]",
"sender": "[email protected]",
"subject": "Order shipped",
"results": [
{
"updatedAt": "2026-07-14T08:15:01Z",
"status": "QUEUED"
},
{
"updatedAt": "2026-07-14T08:16:22Z",
"status": "DELIVERED"
}
],
"customHeaders": []
}Example — bounced (with reason)
reason){
"batchId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"messageId": "507f1f77bcf86cd799439011",
"createdAt": "2026-07-14T08:15:00Z",
"updatedAt": "2026-07-14T08:17:05Z",
"status": "BOUNCED",
"from": "[email protected]",
"to": "[email protected]",
"sender": "[email protected]",
"subject": "Order shipped",
"results": [
{
"updatedAt": "2026-07-14T08:17:05Z",
"status": "BOUNCED"
}
],
"reason": {
"description": "550 5.1.1 User unknown",
"code": "550",
"deliveryStatus": "BOUNCED",
"dsn": {
"action": "failed",
"status": "5.1.1"
}
}
}Engagement (eventCallback.onOpen / onClick)
eventCallback.onOpen / onClick)Routee POSTs a JSON object to the URL you configured for the event. Top-level status: OPENED or CLICKED.
Shares the same envelope fields as status callbacks (batchId, messageId, from, to, sender, subject, results[], …).
click (CLICKED only)
click (CLICKED only)| Field | Description |
|---|---|
url | Original long URL |
shortUrl | Tracked short URL when present |
ip, country, city | Geo / network hints when available |
referrer, device, browser | Client hints when available |
lag | Milliseconds from send to click |
clickedAt | Timestamp string |
Example — opened
{
"batchId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"messageId": "507f1f77bcf86cd799439011",
"createdAt": "2026-07-14T08:15:00Z",
"updatedAt": "2026-07-14T08:20:11Z",
"status": "OPENED",
"from": "[email protected]",
"to": "[email protected]",
"sender": "[email protected]",
"subject": "Order shipped",
"results": [
{
"updatedAt": "2026-07-14T08:20:11Z",
"status": "OPENED"
}
]
}Example — clicked
{
"batchId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"messageId": "507f1f77bcf86cd799439011",
"createdAt": "2026-07-14T08:15:00Z",
"updatedAt": "2026-07-14T08:21:44Z",
"status": "CLICKED",
"from": "[email protected]",
"to": "[email protected]",
"sender": "[email protected]",
"subject": "Order shipped",
"results": [
{
"updatedAt": "2026-07-14T08:21:44Z",
"status": "CLICKED"
}
],
"click": {
"url": "https://shop.example.com/orders/12345",
"shortUrl": "https://w.sends.ms/abc123",
"ip": "203.0.113.10",
"country": "GR",
"city": "Athens",
"lag": 404000,
"clickedAt": "2026-07-14T08:21:44Z"
}
}Engagement webhook deduplication
To avoid duplicate notifications while still recording every engagement internally:
| Event | Webhook rule | Internal tracking |
|---|---|---|
| Open | At most one open webhook per message/recipient | Every open increments openedCount in logs |
| Click | At most one click webhook per message/recipient per URL | Every click increments clickCount in logs |
Repeat clicks on the same link are counted in Search email tracking but do not emit duplicate webhooks.
Handler checklist
- Accept
POSTwithContent-Type: application/json - Return HTTP 200 within 2 seconds (platform retry policy applies — see Receive transactional email delivery callbacks)
- Ignore unknown JSON fields for forward compatibility
- Correlate using
trackingIdfrom your send response — match callbackbatchId - For per-recipient logic on multi-recipient sends, use callback
messageIdor poll tracking APIs
Firewall
Whitelist inbound traffic from callbacksallow.routee.net on your callback URLs.
Related
- E-mail — documentation hub
- Receive transactional email delivery callbacks — setup tutorial
- Email tracking, statuses & callbacks — lifecycle, polling, portal timeline
- Send a transactional email — send request including
callback - Search email tracking — poll logs when webhooks are unavailable
Updated 2 days ago

