Email Webhooks
Webhooks let Routee push delivery and engagement events to your application in real time — no polling required. For transactional email, webhooks are configured per message using the callback object on the send request.
Prefer to pull instead of push?You can also query the Tracking API (
GET /email/tracking/single/{trackingId}) at any time. Webhooks and the Tracking API report the same events.
Configure callbacks on send
Add a callback object to your POST https://connect.routee.net/transactional-email payload. Routee then POSTs JSON to your HTTPS endpoints as the message progresses.
curl -X POST 'https://connect.routee.net/transactional-email' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"from": { "address": "[email protected]" },
"to": [{ "address": "[email protected]" }],
"subject": "Password reset",
"content": { "html": "<p>Reset your password.</p>" },
"callback": {
"statusCallback": {
"strategy": "OnChange",
"url": "https://your-app.example/webhooks/email-status?token=YOUR_SECRET"
},
"eventCallback": {
"onOpen": "https://your-app.example/webhooks/email-open?token=YOUR_SECRET",
"onClick": "https://your-app.example/webhooks/email-click?token=YOUR_SECRET"
}
}
}'Callback types
| Object | Delivers | Fields |
|---|---|---|
statusCallback | Delivery status transitions | strategy = OnChange (every transition) or OnCompletion (final status only); url |
eventCallback | Engagement events — POST on every open / click that lands | onOpen URL, onClick URL |
Webhooks vs skip tracking
eventCallbackonly configures where to POST open/click events. Click rewriting and the open pixel are on by default (trackLinks/trackOpens). Set them tofalseon the send body to skip instrumentation. See Track Links & Opens Explained.
Callback strategies
| Strategy | When callbacks fire |
|---|---|
| OnChange | Every delivery status transition. |
| OnCompletion | Only when delivery reaches a final status. |
Delivery status values
Status callbacks carry the same lifecycle values as the tracking timeline:
deliveryStatus | Meaning |
|---|---|
QUEUED | Accepted by Routee; waiting in the mail pipeline |
SENT | Handed off to the recipient mail server |
DELIVERED | Recipient server accepted the message |
BOUNCED | Permanent failure (bad address, policy reject) |
FAILED | Undeliverable after retries |
DEFERRED | Temporary failure; may retry |
A human-readable status accompanies the machine deliveryStatus. Each notification also identifies the message by its trackingId (the id returned by the send request).
DELIVERED, BOUNCED, and FAILED are final. Routee does not send a later QUEUED callback for the same message.
Handling webhooks reliably
- Respond fast: return
2xximmediately, then process asynchronously (queue the payload). Slow endpoints may be retried or timed out. - Be idempotent: the same event can be delivered more than once (retries). De-duplicate on
trackingId+status+ timestamp before acting. AfterBOUNCEDorFAILED, there is no laterQUEUEDfor that message. - Secure the endpoint: serve over HTTPS and include a hard-to-guess secret in the callback URL (path segment or query string) that you validate on every request. Reject anything without it. Restrict by source IP where possible.
- Expect ordering gaps: events can arrive out of order (e.g. an open before the delivered status). Rely on
timestamp, not arrival order.
Step-by-stepSee the tutorial Receive transactional email delivery callbacks for an end-to-end receiver.
Next steps
- Email tracking, statuses & callbacks — full status list and the pull-based Tracking API
- Send a transactional email — the
callbackobject reference - Callback Object Explained · Status Callback Object Explained · Track Links & Opens Explained
Callback retry policy
Your endpoint must respond with HTTP 200 OK within 2 seconds. Otherwise Routee closes the connection and retries (up to 12 attempts over 24 hours).
| Attempt | Delay after previous try |
|---|---|
| 1st | 30 sec |
| 2nd | 1 min |
| 3rd | 2 min |
| 4th | 5 min |
| 5th | 10 min |
| 6th | 15 min |
| 7th | 30 min |
| 8th | 1 hour |
| 9th | 2 hours |
| 10th | 4 hours |
| 11th | 8 hours |
| 12th | 24 hours |
Design your handler to be idempotent — the same event may be delivered more than once.
Updated 17 days ago

