Skip to content
Integration

Consuming Resend Webhooks: Email Event Tracking and Delivery Troubleshooting

How to receive and verify Resend webhooks for email delivery tracking (email.sent, email.delivered, email.bounced), Svix signature verification, and handling retries.

Published 2 min read
On this page

Resend provides modern transactional email infrastructure with real-time webhooks for every stage of the email lifecycle: when an email is sent, delivered, opened, clicked, bounced, or marked as spam.

Handling Resend webhooks properly is critical for maintaining high sender reputation, automatically marking invalid email addresses in your database, and alerting on deliverability spikes.

What Resend webhooks are

Resend sends HTTP POST requests signed via the Svix standard whenever an email status changes. Payloads include:

  • type: The event name (email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.opened, email.clicked).
  • created_at: ISO timestamp of the event.
  • data: Details of the email object including email_id, from, to, subject, and bounce classification (bounce.type = hard_bounce | transient).

Common use cases

  • Suppressing bounced addresses — Automatically deactivate unsendable emails on email.bounced (hard bounce) to protect sender reputation.
  • Delivery confirmation — Update order status or transactional message history when email.delivered arrives.
  • Spam complaint monitoring — Alert support or security teams on email.complained to investigate abusive senders.
  • Engagement telemetry — Track open and click rates directly in your analytics warehouse.

Verifying Resend signatures

Resend signs webhook payloads using Svix headers:

  • svix-id: Unique message ID.
  • svix-timestamp: Unix timestamp of the delivery.
  • svix-signature: Computed HMAC signature (v1,signature_base64).
import { Webhook } from 'svix';

export async function POST(req: Request) {
  const payload = await req.text(); // Raw text body
  const headers = {
    'svix-id': req.headers.get('svix-id')!,
    'svix-timestamp': req.headers.get('svix-timestamp')!,
    'svix-signature': req.headers.get('svix-signature')!
  };

  const wh = new Webhook(process.env.RESEND_WEBHOOK_SECRET!);
  try {
    const event = wh.verify(payload, headers);
    // Process verified event...
    return new Response('OK', { status: 200 });
  } catch (err) {
    return new Response('Invalid signature', { status: 400 });
  }
}

Failure recovery with HookWatch

If your webhook receiver encounters a database deadlock or temporary network glitch during an email bounce spike:

  1. HookWatch captures each delivery attempt along with the complete Resend payload and error stack.
  2. Recurring 500 errors group into actionable incidents.
  3. You can fix your endpoint handler and replay the exact bounced delivery events without losing bounce suppression state.
Get started

See what happened to every webhook.

HookWatch keeps the request, the response, and every attempt for each delivery — so the debugging, retry, and replay steps in this article are a matter of reading, not reconstructing.