Skip to main content
Helo can notify your application in real time whenever something happens in your account — such as an email being delivered, or a domain’s DNS records being verified. These notifications arrive as HTTP POST requests to a URL of your choosing — that’s a webhook. For example, instead of polling the API to find out whether an email was delivered or opened, we’ll send you a webhook when such an event happens, and your app just listens and reacts.

Supported webhook events

Helo can send you webhooks whenever any of the following events occur.

Message events

Message events track the emails you send, from acceptance through delivery and engagement.

Domain events

Domain events track changes to the DNS records of your sending domains. Use them to react when a domain becomes ready for sending, or when a record stops resolving correctly. Domain events aren’t tied to a single Channel. They’re sent to webhooks for all channels, and to webhooks for any channel the domain is available on. Do you need webhooks for an event we don’t yet support? Let us know!

Webhook payloads

Every webhook is a JSON object. The eventType field identifies the event, and timestamp says when it occurred.

Message event payloads

Message events include details about the message, so you can match the event to your own records:
  • message-accepted and message-processed include a recipients array, covering every recipient of the message.
  • All other message events include a single recipient.
  • Most events include a details object with event-specific information — such as the bounce type for email-bounced, or the clicked link for link-clicked. Fields are omitted when the information isn’t available.

Domain event payloads

Domain events identify the domain and the DNS record that changed:

How to set up webhooks

First, set up a publicly accessible URL that Helo can communicate with. Your endpoint needs to accept HTTP POST requests and respond with a 200 OK to let Helo know the event was received successfully. We recommend designing your webhook endpoint so most of the work is done asynchronously. When you receive the webhook, write a message to a queue or event stream, so your API can promptly respond. Then use a background service to read from the stream or queue and handle the actual processing work. When you create the webhook in Helo, you’ll need to specify the following:
  • URL (required): This is the endpoint we’ll send requests to.
  • Events (required): Select the types of events you’d like us to send webhooks for.
  • Channel (optional): You can receive webhooks for a specific channel. If omitted, you’ll receive webhooks for all channels.
  • Additional headers (optional): If you’d like Helo to include additional custom headers when sending webhooks, you can define them here. Header names must start with X-Customer- (for example, X-Customer-Id), and you can add up to 10.
You can also create, edit, or delete your webhooks via the Webhooks API endpoint.

Request headers

Every webhook request includes the following headers:

Verify webhook signatures

Helo signs every webhook request, so you can confirm it came from Helo and wasn’t modified in transit. We strongly recommend verifying the signature before acting on a webhook. Each webhook has its own signing key, returned as payloadSigningKey when you create or retrieve the webhook. If your key is ever exposed, regenerate it.

Verify with an SDK

The Helo SDKs include a helper that verifies the signature for you. For example, in Node.js:
The helper also rejects requests whose timestamp is more than 5 minutes from the current time, to protect against replayed requests.
Always verify against the raw request body. Parsing and re-serializing the JSON changes the bytes, and the signature won’t match.

Verify manually

The X-Helo-Webhook-Signature header has the form:
  • t is the Unix timestamp (in seconds) when the request was signed.
  • v1 is the signature: a hex-encoded HMAC-SHA256 of the string {t}.{raw request body}, using your webhook’s signing key.
To verify a request:
1

Parse the header

Split the header on ,, then split each element on the first =. Ignore any elements you don’t recognize — new signature versions may be added in future.
2

Compute the expected signature

Join the timestamp, a ., and the raw request body. Compute the HMAC-SHA256 of that string with your signing key, and hex-encode it in lowercase.
3

Compare the signatures

Compare your signature to the v1 value with a constant-time comparison. Reject the request if they don’t match.
4

Check the timestamp

Reject the request if the timestamp is too far from the current time (we recommend 5 minutes).

Retry schedule

If Helo doesn’t receive a 200 response, we’ll retry the delivery automatically for up to 24 hours. We use an exponential backoff with an initial retry interval of 10 seconds, e.g.,
  • 1st attempt
  • 10 seconds later… 2nd attempt
  • 20 seconds later… 3rd attempt
  • 40 seconds later… 4th attempt
  • etc.
Because a webhook can be retried after your endpoint has already processed it (for example, if your response timed out), you may occasionally receive the same event more than once. Use the X-Helo-Webhook-Event-Id header to detect duplicates.
First attempts are placed in a separate queue from retry attempts within our webhook processing system and have a timeout of 5 seconds. Making sure you respond quickly on the first attempt will ensure timely delivery of your webhooks. Retry attempts have a timeout of 60 seconds.