Skip to content
Claim your free business email
Webhooks

Signed webhooks for every email event

Deliveries, bounces, opens and clicks reach your endpoint seconds after they happen. Every request is signed, retried when you do not answer, and kept so you can send it again.

Rasket10:04:13
Event
email.delivered
Endpoint
api.northwind.dev
Signed
HMAC-SHA256
Attempt
1 of 10
Your endpoint

POSThttps://api.northwind.dev/webhooks/rasket

content-type:
application/json
user-agent:
Rasket-Webhooks/1.0
svix-id:
msg_2h9kQ4tXv8Lm…
svix-timestamp:
1790589853
svix-signature:
v1,g0hWq3Yp6c…
{
  "type": "email.delivered",
  "created_at": "2026-09-28T10:04:13.207Z",
  "data": {
    "email_id": "4ef9a417-02e9-4d39-…",
    "from": "receipts@mail.northwind.dev",
    "to": ["maya@example.com"],
    "subject": "Your receipt for order #2041"
  }
}

Response200 - OK142 ms

Event catalogue

Every event type you can subscribe to. 23 types in five groups, all in one envelope: a type, a time and a data object.

Email

12 types

What happened to a message you sent, from the moment it is accepted, and mail that arrived at one of your receiving addresses.

  • email.bounced
  • email.canceled
  • email.clicked
  • email.complained
  • email.delivered
  • email.delivery_delayed
  • email.failed
  • email.opened
  • email.received
  • email.scheduled
  • email.sent
  • email.suppressed

Domains

3 types

A sending domain added, changed or removed.

  • domain.created
  • domain.deleted
  • domain.updated

Contacts

3 types

A contact created, changed or erased through the API. An import sends none of these.

  • contact.created
  • contact.deleted
  • contact.updated

Suppressions

2 types

An address added to your suppression list, or taken off it.

  • suppression.added
  • suppression.removed

Automations

3 types

A run enrolled a contact, reached the end, or ended without finishing.

  • automation.run.completed
  • automation.run.failed
  • automation.run.started
Deliveries

Every attempt, on the record. See what we sent, what your server answered and when we will try again. Nothing is dropped while you fix something.

Northwind · Webhooks

Webhook

https://api.northwind.dev/webhooks/rasket

Listening for
email.bouncedemail.clicked+3
Status
Enabled
Signing secret
whsec_••••••••a41f

Events

  • email.clicked1mRetrying
  • email.delivered2mSuccess
  • email.bounced6mSuccess
  • email.opened1hFailed
  • email.delivered2hPending

email.delivered

Replay
ID
msg_2h9kQ4tXv8Lm…
Timestamp
2026-09-28 10:04:13
HTTP status code
200 - OK
Attempts
3

Attempts

  1. Attempt 1503 - Service Unavailable10:04:13231 ms
  2. Attempt 2No response10:04:1810000 ms

    timeout

  3. Attempt 3200 - OK10:04:48142 ms

Ten attempts, backing off. With about ten percent jitter on every delay.

Delay before each attempt

  1. #1now
  2. #25 s
  3. #330 s
  4. #42 min
  5. #510 min
  6. #630 min
  7. #71 h
  8. #82 h
  9. #94 h
  10. #108 h

After the tenth attempt, about sixteen hours after the first, the event is marked Failed. The payload we signed and every attempt stay readable, on the dashboard and through the API, until you replay it.

  • Ten seconds to answer.

    Anything that is not a 2xx within ten seconds is a failed attempt: a timeout, a refused connection, a DNS or TLS error, or a redirect, which we never follow.

  • Replay the exact bytes.

    Fix your handler, then press Replay on the dashboard or call the API. A replay carries the identical payload under the same event id, so a handler that dedupes ignores it.

  • Switched off, not lost.

    An endpoint with no successful delivery for five days is turned off and your admins are emailed. Its events are still recorded, ready to deliver when you enable it again.

Verify

Verify in a few lines. The scheme is Svix-compatible, so one call to the svix library does it. Read the raw body, pass it in, get the event back.

svix-id
The event's id. Stable across retries and replays, so dedupe on it.
svix-timestamp
Unix seconds. More than five minutes from now is refused as a replay.
svix-signature
One or more v1 signatures over the id, the timestamp and the raw body.

Recipes for other languages →

Terminal
$ npm install svix
app/api/hooks/rasket/route.ts
import { Webhook } from "svix";
const wh = new Webhook(process.env.RASKET_WEBHOOK_SECRET);
export async function POST(request: Request) {  const rawBody = await request.text(); // text(), never json()
  try {    const event = wh.verify(      rawBody,      Object.fromEntries(request.headers),    );    await handle(event);    return new Response(null, { status: 200 });  } catch {    return new Response("invalid signature", { status: 400 });  }}
Secrets and limits

Rotate without a deploy window. The new secret signs at once and the old one keeps signing for 24 hours, so your handler accepts either while you ship.

Signing secretRotate signing secret
Rotate+12 h+24 h
whsec_••••••••a41fPrevious · 24 h
whsec_••••••••7c2eCurrent
svix-signature: v1,Kx3pQ9wR2f… v1,g0hWq3Yp6c…

Endpoints on every plan. Each has its own URL, its own events and its own secret, shown once.

  • Free2 endpoints
  • Pro5 endpoints
  • Scale10 endpoints
Questions

Questions about webhooks. What people ask before the first delivery.

Do I have to use your library to verify a signature?

No. The scheme is HMAC-SHA256 over the event id, the timestamp and the raw body, and it is compatible with the Svix libraries, so the official Python, Go, Ruby and PHP ones verify our deliveries as they are. That includes Node and TypeScript, where npm install svix gives you new Webhook(secret).verify(rawBody, headers) today; our own zero-dependency verifier follows when it is published.

Are webhook events delivered in order?

No. A delivered event can arrive before the sent event that logically precedes it. Key your handler on the email id, the type and the event's own created_at rather than on the order things turn up in.

Can the same event arrive twice?

Yes, and a handler has to expect it. Dedupe on the svix-id header: it is stable for the life of an event and does not change when the event is retried or replayed.

What happens if my handler is slow?

Anything that is not a 2xx within ten seconds counts as a failure and is retried. Store the event, answer 2xx, and do the work afterwards. A redirect is a failure too, because we never follow one.

Can I see what was actually sent to my endpoint?

Yes. Every event keeps the exact payload we signed, along with every attempt we made, the status code that came back and the first 8 KB of your response. Both are readable on the dashboard and through the API.