Webhooks & events

Your systems see what ours see.

A send returning 200 means the message was accepted, not that it arrived. What happened next — accepted by the receiving server, rejected, marked as spam, opened — is pushed to your endpoint as it happens, signed so you can prove it came from us.

email_9f3c2a7b4 events
email.sent10:00:00.412
email.delivered10:00:03.118
email.opened10:04:51.007
email.clicked10:05:12.884
webhook-signaturev1,k8Ff2p…verified
REST APIPOST /emails
SMTP:465 · TLS
Broadcastto an audience
Authenticatekey or credentials
Verify domainDKIM · SPF · DMARC
Suppress & meterbounces · ceilings
Sign and relayEU MTA · TLS
deliveredbouncedopenedclicked
Webhooksigned · retried
Webhooks are the return path. Whatever the pipeline learns about a message — however it entered — comes back out here, signed.

The events

email.sentAccepted by eusend and in transit.
email.deliveredThe receiving mail server confirmed delivery.
email.bouncedA permanent failure. The address is suppressed automatically and the payload carries a bounce_type plus the receiving server’s verbatim reason. Transient failures are retried and never fire this event.
email.complainedThe recipient marked the message as spam.
email.openedFires once per email, when open tracking is on.
email.clickedA tracked link was clicked; the payload includes link_id and url.

Subscribe to any combination, or use * to receive everything — including event types added later.

Payloads carry your tags

Whatever tags you attached to the send come back on every event it produces. That is what lets a bounce be routed to the team that owns shipping notifications without a database lookup on the way in.

email.bounced
{
  "type": "email.bounced",
  "email_id": "9a8b7c6d-5e4f-4a3b-8c1d-0e9f8a7b6c5d",
  "recipients": ["[email protected]"],
  "tags": { "category": "shipping_update" },
  "timestamp": "2026-05-20T10:00:03.000Z"
}

Signed, and worth verifying

Every delivery carries webhook-id, webhook-timestamp, and a webhook-signature HMAC-SHA256 over the raw request body. The scheme is Svix-compatible, so existing verification libraries work unchanged.

The one thing that catches people: sign the raw body, not the parsed JSON. Re-serializing an object produces different bytes and the signature will never match.

Delivery you can rely on

  • Retries. A failed delivery is retried up to three times with exponential back-off, so a brief outage on your side doesn’t cost you the event.
  • Endpoint validation. Private, loopback, and internal addresses are rejected — at creation, and again after DNS resolution before each delivery. A hostname that later resolves inward stops being deliverable.
  • Idempotency on your side. webhook-id is stable across retries, so deduplicating is a primary key, not a heuristic.

Tracking that stays in the EU

Open pixels and click redirects are served from EU infrastructure — no third-party analytics endpoint sits in the middle of your recipients’ mail. Tracking is on by default and controllable per send, or per organization from the dashboard, and can be turned off entirely.

Wire up the handler before you send anything real.

Test-key sends fire the full webhook lifecycle without delivering, so you can build and verify bounce handling against events that never touched a real inbox.

Create a free account