Providers / April 25, 2026

How to receive Resend webhooks reliably (email lifecycle events)

Provider verification diagram showing signatures checked before event delivery

Resend fires webhooks for every event in an email's lifecycle: dispatched, delivered (or delayed), opened, clicked, bounced, complained. They're how your application stays in sync with what's actually happening to messages after they leave your code.

This guide covers what Resend sends, how to verify it (Standard Webhooks-compatible), and what production reliability requires.

What Resend sends

Resend webhooks are JSON POST requests. An email.delivered event:

{
  "type": "email.delivered",
  "created_at": "2026-04-25T14:30:00.000Z",
  "data": {
    "email_id": "4ef9a417-9fb0-4c72-bdf6-c45e6e4d5b1c",
    "from": "you@your-app.com",
    "to": ["customer@example.com"],
    "subject": "Your weekly summary",
    "created_at": "2026-04-25T14:29:50.000Z"
  }
}

Headers (Standard Webhooks spec):

svix-id: msg_2NxV5y...
svix-timestamp: 1714000000
svix-signature: v1,abc123...
content-type: application/json

Common Resend event types:

  • email.sent — the message was accepted by Resend
  • email.delivered — the recipient mail server accepted the message
  • email.delivery_delayed — temporary deferral (greylisting, soft bounce)
  • email.bounced — hard bounce (invalid address, mailbox full)
  • email.complained — recipient marked as spam
  • email.opened — recipient opened the message (tracking-pixel based)
  • email.clicked — recipient clicked a link

The data.email_id is the Resend ID for the message — use it to correlate webhooks back to the send.

Resend's signature scheme (Standard Webhooks)

Resend follows the Standard Webhooks spec (the same scheme used by Clerk and several other providers). The signature is HMAC-SHA256 of {svix-id}.{svix-timestamp}.{raw-body}, base64-encoded, prefixed with v1,:

signature = "v1," + base64(hmac_sha256(secret, svix_id + "." + svix_timestamp + "." + raw_body))

Verification:

  1. Read the raw body before any JSON parsing
  2. Reject if now - svix_timestamp > 300 seconds (replay protection)
  3. Recompute the signature; the header may contain multiple space-separated values during secret rotation — accept any match
  4. Compare constant-time

The official svix library does this for you in every supported language.

Resend's retry policy

Resend uses Standard Webhooks-style delivery. Failed deliveries are retried by the provider and are visible in Resend's webhook tooling, but you should still design your own recovery path for accepted events that fail downstream.

This means:

  • Acknowledge fast — return 2xx in under one second
  • Be idempotent on svix-id — duplicates will arrive during retries
  • Have a recovery story — past Resend's window, manual replay from the dashboard is the only built-in fallback

DIY: minimal Resend webhook handler in Node

import { Webhook } from 'svix'

const secret = process.env.RESEND_WEBHOOK_SECRET!

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

  let event
  try {
    event = new Webhook(secret).verify(body, headers)
  } catch {
    return new Response('Bad signature', { status: 400 })
  }

  // Idempotency on svix-id
  // ...

  queueWork(event)

  return new Response('ok', { status: 200 })
}

Production needs more:

  • A persistence layer for svix-id idempotency
  • A queue for async work
  • Replay path for events past Resend's retry window
  • Filtering — high-volume senders see large amounts of email.opened and email.clicked events
  • Routing — bounces and complaints to a suppression-list updater, opens and clicks to your analytics stack

Hooksbase: receive Resend webhooks without rebuilding the rest

Hooksbase treats Resend as one of five pre-verified providers. After the request passes Hooksbase ingest auth, the Standard Webhooks signature is verified at the Hooksbase edge before the payload reaches your endpoint.

Setup:

  1. Create a webhook in Hooksbase with provider: resend
  2. Paste your Resend webhook signing secret (encrypted at rest)
  3. Put a small forwarder at the Resend webhook URL. It should preserve the raw body and Svix headers, then POST to the Hooksbase ingest URL with Authorization: Bearer <ingest secret>. If your source is already a custom producer that can attach that header, it can call Hooksbase directly.
  4. Add your application URL as the destination

You get:

  • Signature verification before the event reaches your code
  • Idempotency for your destination — every dispatch includes a unique webhook-id header you can dedupe on across retries. Resend's svix-id is captured as provider.sourceId and queryable on every delivery.
  • Retries with exponential backoff to your endpoint after Hooksbase accepts the event
  • Routing rules by event type — send email.bounced to a suppression-list updater, email.complained to your abuse-handling flow, email.opened/email.clicked to analytics
  • Payload transforms — extract just the fields your downstream needs from Resend's nested structure
  • Provider-aware queryable fieldsprovider.eventType (the Resend event), provider.verified on every delivery
  • Deterministic replay — re-run an event with the same payload bytes after a fix while the payload is retained
  • Delivery history and DLQ
  • Event drains (Pro+) — stream Resend lifecycle events directly to Axiom, Datadog, object storage, OTLP HTTP, or your own HTTP sink alongside the rest of your agent telemetry

Common Resend webhook use cases for AI agents

  • Suppression-list agentemail.bounced and email.complained events trigger an agent that auto-removes the address from active campaigns and flags it in your CRM
  • Re-engagement agentemail.opened after a long quiet period triggers an agent that drafts and schedules a personalized follow-up
  • Click-driven workflow agentemail.clicked on a specific CTA triggers an agent that advances the recipient to the next stage of a sequence
  • Deliverability monitoring agent — patterns of email.delivery_delayed and email.bounced trigger an agent that diagnoses sender-reputation issues and pages on-call
  • Receipt confirmation agentemail.delivered on a transactional confirmation triggers a downstream system to mark the order as "notified"

Where to go next

Start free at app.hooksbase.com, then use Starter+ provider verification when you're ready to receive signed Resend webhooks through Hooksbase.

Frequently asked questions

How do you verify a Resend webhook signature?

Resend follows the Standard Webhooks spec, the same scheme Clerk uses. Read the raw body first, compute HMAC-SHA256 of {svix-id}.{svix-timestamp}.{raw-body}, base64-encode it, and compare constant-time against the v1,-prefixed signature header, rejecting timestamps older than 300 seconds. The official svix library handles this, and multiple space-separated signatures during rotation are normal — accept any match.

How long does Resend retry a failed webhook?

Resend uses Standard Webhooks-style delivery, which retries failed deliveries and shows them in Resend's webhook tooling. Past that window, manual replay from the dashboard is the only built-in fallback, so plan a recovery path of your own for events that were accepted and then failed downstream.

What should you use as the idempotency key for Resend webhooks?

The svix-id header. Duplicates arrive during retries, so record each one you have processed and make repeated deliveries produce the same outcome as the first.

What is Hooksbase?

Hooksbase is event infrastructure for AI agents. It ingests events over four channels — HTTP, email, HTML form, and scheduled cron — verifies them, routes them by rule, runs versioned Automations in the event path, and delivers them to HTTP and cloud destinations (AWS SQS, AWS EventBridge, GCP Pub/Sub, and S3-compatible storage) with retries, strict ordering, Standard Webhooks-compatible signing, deterministic replay, and a dead-letter path. It is a hosted service, runs on Cloudflare Workers, is operated at hooksbase.com, and is not affiliated with — and shares no code or ownership with — other similarly named webhook, hook, or tunnelling tools.

Related guides