Signed webhooks for every email event
Deliveries, bounces, complaints, 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.
Verify a delivery
// app/api/hooks/rasket/route.tsimport { verify } from "@rasket/webhook-verify";
export async function POST(request: Request) { const rawBody = await request.text(); // text(), never json()
try { const event = verify(rawBody, request.headers, process.env.RASKET_WEBHOOK_SECRET); await handle(event); } catch { return new Response("invalid signature", { status: 400 }); }
return new Response("ok", { status: 200 });}What every webhook delivery carries
An endpoint is a URL, a list of event types and a signing secret. Everything below is true of every request we make to it.
A signature on every request
Three headers travel with the body: the event's id, a timestamp, and one or more signatures. The signature covers the raw bytes we sent, so a rewritten payload or a stale timestamp never verifies.
Twenty-three event types
Each endpoint subscribes to the types it wants. Subscribing to one whose producer arrives in a later release is allowed and simply never fires.
Ten attempts, backing off
Anything that is not a 2xx within ten seconds is a failed delivery. We try again up to ten times, spread over roughly a day, with jitter on every delay.
Replay the exact bytes
Fix your handler, then send the event again from the dashboard or the API. A replay carries the identical payload under the same event id.
Rotate the secret with an overlap
A new signing secret runs beside the old one for 24 hours and both sign, so a handler that accepts any matching signature needs no coordinated deploy.
How many endpoints a team may have is part of its plan. See what each plan includes.
How signed webhooks work
Three steps, and the middle one is the only one worth being careful about.
- 1
Create an endpoint and pick its events
Give us a URL and the event types you want it to receive. We hand back a signing secret beginning whsec_, shown once, and nothing is delivered anywhere else.
- 2
Read the raw body, then verify
Check that svix-timestamp is within five minutes, recompute the signature over the exact bytes, and compare it with svix-signature. Anything that parses the JSON first has already destroyed what was signed.
- 3
Answer 2xx, then do your work
Store the event and reply. Work finished before the reply eventually times out and is retried. Dedupe on svix-id, and do not rely on arrival order.
Every event type you can subscribe to
Twenty-three types today, grouped by what they are about. The envelope is the same for all of them: a type, the time it happened, and a data object.
Email delivery
What happened to a message you sent, from the moment it is accepted.
- email.sent
- email.scheduled
- email.delivered
- email.delivery_delayed
- email.bounced
- email.complained
- email.opened
- email.clicked
- email.failed
- email.suppressed
- email.canceled
Domains
A sending domain added, changed or removed, including one that arrives through a claim.
- domain.created
- domain.updated
- domain.deleted
Suppressions
An address added to your suppression list, or taken off it.
- suppression.added
- suppression.removed
Contacts
A contact created, changed or erased through the API. An import sends none of these.
- contact.created
- contact.updated
- contact.deleted
Received mail
Mail that arrived at one of your receiving addresses, with the envelope and the attachment list.
- email.received
Automation runs
A run enrolled a contact, reached the end of its graph, or ended without finishing.
- automation.run.started
- automation.run.completed
- automation.run.failed
What happens when your endpoint is down
Nothing is dropped while you are fixing something. A failed delivery is recorded, retried, and left where you can replay it.
A delivery fails if it is not a 2xx within ten seconds: a timeout, a refused connection, a DNS or TLS error, or a redirect, which we never follow. We then try again up to ten times, with about ten percent of jitter on each delay so a recovering outage is not hit by everything at once.
| Attempt | Delay before it |
|---|---|
| 1 | immediately |
| 2 | 5 seconds |
| 3 | 30 seconds |
| 4 | 2 minutes |
| 5 | 10 minutes |
| 6 | 30 minutes |
| 7 | 1 hour |
| 8 | 2 hours |
| 9 | 4 hours |
| 10 | 8 hours |
After the tenth attempt we stop and mark the event failed. It is not lost: the payload we signed and every attempt we made stay readable, and you can replay it once your handler is right. An endpoint with no successful delivery for five days running is switched off and your team's admins are emailed. Events keep being recorded while it is off, so the backlog is still there to deliver when you turn it back on.
Related features and webhook documentation
The rest of the product that touches events, and the reference pages behind every claim on this page.
- Receiving: inbound mail through the same event
- Domains: the identity your mail is signed with
- Email API: the send that produces these events
- Events: every payload, in full
- Webhooks reference: headers, retries and replay
- Node SDK: verify inside a route handler
- Quickstart: from an empty account to a delivered email
Questions about webhooks
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. For Node and TypeScript, @rasket/webhook-verify is one function with no dependencies of its own, and the Node SDK bundles the same verifier.
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.
How many endpoints can I have?
The number of webhook endpoints is part of your plan, and every plan includes some. The pricing page lists what each one allows.
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.
Start listening to your email
Create an endpoint, subscribe it to the events you care about, and verify the first delivery in a few lines.