Skip to main content
Webhooks send email events to your backend as they happen, so you can react to deliveries, bounces and complaints without polling the API. Use them to mark an address as undeliverable, stop mailing someone who complained, or keep delivery status in your own database. Events are sent for emails sent through the Email Service: the REST API, the SDK, SMTP, and the Resend-compatible API. Campaigns and sequences have their own reports.

Events

The short names delivery, bounce, complaint, open and click are accepted as aliases and stored by their full names. The names match Resend’s, so a handler written for Resend keeps working.

Create a webhook

1

Open Webhooks

Go to Settings > Email Service > Webhooks > Add Webhook. Only account owners and admins manage webhooks.
2

Set the URL

The HTTPS endpoint events are sent to, such as https://api.acme.com/webhooks/hiveku. It must be on the public internet: http:// addresses, private networks and localhost are refused.
3

Pick events

Choose the events you want. You can change them later.
4

Copy the signing secret

Hiveku generates a signing secret for each webhook and shows it once. Copy it for signature verification. You can rotate it later on the webhook’s page.
5

Send a test

Press Send Test on the webhook’s page. Your endpoint receives an email.test event, signed like every event, and the result is listed under Recent Deliveries.
With an API key that has the email:webhooks permission, create one through the API:
The answer holds the signing secret (secret). It is not shown again. A webhook made with an API key receives events only for the emails that key sends, and only that key can see or change it through the API. Webhooks made in Settings, or by your AI assistant, cover every Email Service email of the account. An account can have up to 10 webhooks switched on, a webhook Hiveku switched off for failing included; one you switched off yourself counts again when you turn it back on.

Event payload

Every event is a JSON POST with the same envelope:
  • id is the same for every retry of an event. Use it to skip an event you already handled: an event can arrive more than once.
  • created_at is when the event happened. data.created_at is when the email was sent.
  • data.email_id is the id the send API returned.
  • data.tags holds the tags you sent the email with.
Each event type adds its own object to data: email.sent and email.opened carry only the common fields.

What events never contain

Sent emails can hold live sign-in and password-reset links, so an event never carries:
  • the email’s body or headers;
  • Bcc addresses, even in recipients (an event about Bcc recipients only is not sent at all);
  • more of a clicked link than its site address (https://app.acme.com, never the path or query, where tokens live);
  • the IP address or browser of whoever opened or clicked.
People with the Open sent emails permission see those details in Settings > Email Service > Email Logs.

Verify signatures

Every request carries these headers: Verify against the raw request body, and refuse a timestamp more than five minutes old so a captured request cannot be replayed.
Verify against the raw request body, not a re-serialized JSON object. Any change, even whitespace, invalidates the signature.

Retries

Any 2xx answer within 10 seconds counts as delivered, whatever the body. Anything else is retried:
  • about 1 minute after the first attempt, then 2 minutes and 10 minutes later;
  • then every hour, six times;
  • then every 6 hours, with a last try 24 hours after the event.
Redirects are not followed: point the webhook at the final address. After the last try Hiveku gives up on that event. New events are sent before retries, so an event your endpoint keeps refusing never holds up the others. Events can therefore arrive out of order: use created_at when order matters. An event your endpoint refuses (a 4xx answer other than 408, 410 and 429) is retried on its own schedule, and never pauses the webhook or holds up the other events. When events are given up, the account’s inbox gets one notice: an urgent one when nothing at all was delivered to the webhook for a day and the endpoint refused the types it takes, a suggestion when it does not take some types, or when events waited 24 hours without being sent (an endpoint that answers too slowly for the number of events). Your endpoint looks down when a request gets no answer at all, or it answers 5xx, 408 or 429. When nothing gets through, Hiveku then pauses the webhook instead of sending every waiting event to it: after a request with no answer, or three such answers. The pause starts at about a minute and grows the longer the endpoint looks down, up to 15 minutes, and the waiting events keep their retry times. While anything has failed since the last delivery, the newest waiting event of each type goes first, all together, so a type your handler hangs on never goes first alone. A type your handler gives no answer for while it takes other types is left out until the next minute’s pass, so it does not hold up the others. When the endpoint answers again after an outage, the events that could not reach it are sent at once. After a 429, the next events go one at a time.
Answer 2xx to event types your handler does not use, and do the work after answering. An event refused, or not answered within 10 seconds, is sent again.

Switched off after failures

Hiveku switches a webhook off when its endpoint has looked down for 24 hours with nothing delivered (refused events in between do not change that), when it has refused its events for 7 days, or at once when it answers 410 Gone. Only a delivered event ends a run of failures. Only failures of the event types your endpoint has taken count (any type, until it takes one), so an endpoint that refuses or fails the types it does not handle and takes the rest stays on, however far apart your sends are. New events are not sent to a webhook that is switched off. The account’s inbox gets a notice, and the webhook’s page says it was switched off. Fix the endpoint, press Send Test to check it, then press Enable. Events that were already waiting are sent then, as long as they are less than 24 hours old; new events are not queued while the webhook is off. Turning a webhook back on, or changing its address, starts its 24 hours again and forgets the types it took. A webhook you switch off yourself drops the events that were waiting. A Send Test that gets through also ends a pause: the endpoint is back.

Recent deliveries

The webhook’s page lists its 50 most recent deliveries; deliveries are kept 30 days. Each one shows its event, whether it was delivered, is being retried or failed, how many attempts it took, and what your endpoint answered.

Tag filters

To receive events for only some emails, give the webhook a tag filter (API and MCP: filter_tags). An event is sent only when its email carried at least one of the filter’s tags with the same value. The filter applies on top of the events the webhook subscribes to.
Send "filter_tags": null to remove the filter.