Resend Integration
Receive and route Resend webhooks for email delivery, engagement, and bounce events.
Setup
1. Create a Source in Hookbase
Resend uses Svix under the hood for webhook delivery, which signs payloads using HMAC-SHA256 with a base64-encoded signature in the webhook-signature header.
curl -X POST https://api.hookbase.app/api/sources \
-H "Authorization: Bearer whr_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Resend Production",
"slug": "resend",
"verificationConfig": {
"type": "svix",
"secret": "whsec_..."
}
}'Save your webhook URL:
https://api.hookbase.app/ingest/{orgSlug}/resend2. Configure Resend Webhook
- Go to Resend Dashboard → Webhooks
- Click Add webhook
- Enter your Hookbase ingest URL
- Select the events you want to receive
- Click Create
- Copy the Signing secret (starts with
whsec_) and update your Hookbase source
3. Create Routes
# Create destination for your email event handler
curl -X POST https://api.hookbase.app/api/destinations \
-H "Authorization: Bearer whr_your_api_key" \
-d '{"name": "Email Events Handler", "url": "https://api.myapp.com/webhooks/resend"}'
# Create route
curl -X POST https://api.hookbase.app/api/routes \
-H "Authorization: Bearer whr_your_api_key" \
-d '{"name": "Resend to Email Handler", "sourceId": "src_...", "destinationIds": ["dst_..."]}'Signature Verification
Resend uses Svix for webhook delivery. The signature is sent across three headers:
| Header | Description |
|---|---|
webhook-id | Unique message ID |
webhook-timestamp | Unix timestamp (seconds) |
webhook-signature | v1,<base64-encoded-signature> |
Hookbase verifies Svix signatures automatically:
{
"verificationConfig": {
"type": "svix",
"secret": "whsec_..."
}
}Timestamp Tolerance
Svix signatures include a timestamp. Hookbase rejects webhooks older than 5 minutes by default to prevent replay attacks.
Common Events
email.sent
Triggered when an email is accepted by Resend for delivery.
{
"type": "email.sent",
"created_at": "2026-03-07T12:00:00.000Z",
"data": {
"email_id": "em_1234567890",
"from": "[email protected]",
"to": ["[email protected]"],
"subject": "Your order has been confirmed",
"created_at": "2026-03-07T12:00:00.000Z"
}
}email.delivered
Triggered when an email is successfully delivered to the recipient's mail server.
{
"type": "email.delivered",
"created_at": "2026-03-07T12:00:02.000Z",
"data": {
"email_id": "em_1234567890",
"from": "[email protected]",
"to": ["[email protected]"],
"subject": "Your order has been confirmed",
"created_at": "2026-03-07T12:00:00.000Z"
}
}email.opened
Triggered when a recipient opens the email (requires open tracking enabled).
{
"type": "email.opened",
"created_at": "2026-03-07T12:05:00.000Z",
"data": {
"email_id": "em_1234567890",
"from": "[email protected]",
"to": ["[email protected]"],
"subject": "Your order has been confirmed",
"created_at": "2026-03-07T12:00:00.000Z"
}
}email.clicked
Triggered when a recipient clicks a link in the email (requires click tracking enabled).
{
"type": "email.clicked",
"created_at": "2026-03-07T12:06:00.000Z",
"data": {
"email_id": "em_1234567890",
"from": "[email protected]",
"to": ["[email protected]"],
"subject": "Your order has been confirmed",
"click": {
"link": "https://myapp.com/orders/12345",
"timestamp": "2026-03-07T12:06:00.000Z"
},
"created_at": "2026-03-07T12:00:00.000Z"
}
}email.bounced
Triggered when an email bounces (permanent delivery failure).
{
"type": "email.bounced",
"created_at": "2026-03-07T12:00:03.000Z",
"data": {
"email_id": "em_1234567890",
"from": "[email protected]",
"to": ["[email protected]"],
"subject": "Your order has been confirmed",
"bounce": {
"message": "550 5.1.1 The email account that you tried to reach does not exist."
},
"created_at": "2026-03-07T12:00:00.000Z"
}
}email.complained
Triggered when a recipient marks the email as spam.
{
"type": "email.complained",
"created_at": "2026-03-07T14:00:00.000Z",
"data": {
"email_id": "em_1234567890",
"from": "[email protected]",
"to": ["[email protected]"],
"subject": "Your order has been confirmed",
"created_at": "2026-03-07T12:00:00.000Z"
}
}Transform Examples
Slack Alert for Bounces and Complaints
function transform(payload) {
const data = payload.data;
const isBounce = payload.type === 'email.bounced';
const title = isBounce ? 'Email Bounced' : 'Spam Complaint';
const color = isBounce ? 'warning' : 'danger';
return {
attachments: [{
color: color,
title: title,
fields: [
{ title: "To", value: data.to.join(', '), short: true },
{ title: "Subject", value: data.subject, short: true },
{ title: "From", value: data.from, short: true },
{ title: "Email ID", value: data.email_id, short: true }
],
footer: isBounce && data.bounce ? data.bounce.message : "Marked as spam by recipient",
ts: Math.floor(new Date(payload.created_at).getTime() / 1000)
}]
};
}Email Analytics Format
function transform(payload) {
const data = payload.data;
return {
email_id: data.email_id,
event_type: payload.type.replace('email.', ''),
from: data.from,
to: data.to,
subject: data.subject,
link_clicked: data.click ? data.click.link : null,
bounce_message: data.bounce ? data.bounce.message : null,
event_at: payload.created_at,
sent_at: data.created_at
};
}Filter Examples
Delivery Failures Only
{
"name": "Delivery Failures",
"logic": "or",
"conditions": [
{
"field": "type",
"operator": "equals",
"value": "email.bounced"
},
{
"field": "type",
"operator": "equals",
"value": "email.complained"
}
]
}Engagement Events
{
"name": "Engagement Events",
"logic": "or",
"conditions": [
{
"field": "type",
"operator": "equals",
"value": "email.opened"
},
{
"field": "type",
"operator": "equals",
"value": "email.clicked"
}
]
}Specific Sender
{
"name": "Transactional Emails",
"logic": "and",
"conditions": [
{
"field": "data.from",
"operator": "equals",
"value": "[email protected]"
}
]
}Headers
Resend (Svix) webhooks include these headers:
| Header | Description |
|---|---|
webhook-id | Unique message identifier |
webhook-timestamp | Unix timestamp (seconds) |
webhook-signature | v1,<base64-signature> |
Content-Type | application/json |
User-Agent | Svix-Webhooks |
Troubleshooting
Signature Verification Failed
- Verify you're using the webhook signing secret (starts with
whsec_) - Ensure verification type is set to
svix, nothmac - Check that the secret matches what's shown in the Resend dashboard
Missing Events
- Check which events are selected in Resend's webhook settings
- Verify your sending domain is properly configured (SPF, DKIM)
- Check Resend's webhook logs for delivery attempts
No Open/Click Events
- Open and click tracking must be enabled in your Resend domain settings
- HTML emails are required for tracking — plain text emails cannot be tracked
- Some email clients block tracking pixels