You can receive a notification of changes to your contacts by setting up a webhook. When a contact is added to one of your lists, updated or deleted we will send you an HTTPS request containing the change.

Setting up webhooks

To receive webhooks, you can provide an HTTPS endpoint that can accept a JSON request body. As events occur to your contacts, we will send requests to that endpoint. This request body will contain a list of events that recently happened to your contacts.

Each webhook request can contain up to 1000 events about your contacts.

Example request body



"id": "42636763-73f9-463e-af8b-3f720bb3d889",

"type": "contact.created",

"list_id": "fa482fa2-5ac4-11ed-9f7a-67da1c836cf8",

"contact_id": "e3ab8c80-5f65-11ed-835e-030e4bb63150",

"occurred_at": "2022-11-18T15:20:23+00:00",

"contact_fields": {

"LastName": "Example",

"FirstName": "Claire"


"contact_status": "SUBSCRIBED",

"contact_email_address": "claire@example.com",

"contact_tags": ["vip"]




Field taxonomy

id (uuid) The id of the event. This can be used to ensure you only process a certain event once.
type (string) The type of event, see event types.
list_id (uuid) The id of the list that the contact belongs to.
contact_id (uuid) The id of the contact the event occurred to.
contact_email_address (string) The email address of the contact.
contact_fields (struct) If present, the custom fields that are assigned to that contact.
contact_tags (array) If present, a list of tags that are assigned to the contact.
contact_status (string) If present, the current status of the contact, see contact status.
occurred_at (datetime) The timestamp the event occurred at in ISO 8601 format.
campaign_id (uuid) The id of the campaign the event occurred on.

Certain fields are only provided for contact.created , contact.updated and contact.deleted events. Your endpoint must be able to handle events with the contact_fields , contact_tags and contact_status fields omitted.

Event type

  • contact.bounced
  • contact.clicked
  • contact.complained
  • contact.created
  • contact.deleted
  • contact.opened
  • contact.unsubscribed
  • contact.updated

Contact status


Validating requests

Requests to your webhook endpoint contain an EmailOctopus-Signature header, which can be used to validate the request was genuinely sent by EmailOctopus.

This signature is generated using HMAC-SHA256 algorithm with the request body as the data and a secret value as the key. A prefix of sha256= is added to the signature. Each of your endpoints has a unique secret key that can be viewed in the dashboard.

Verify the signature by generating the same signature locally and comparing them.

Example code (PHP)


* Validate the signature of a webhook request.


* @param string $requestBody Body of the request including any trailing whitespace.

* @param string $emailoctopusSignature Value of the `EmailOctopus-Signature` header.

* @param string $webhookSecret Secret value obtained from the webhook dashboard.

* @return bool Whether the provided signature matches the expected signature.


function validateSignature (

string $requestBody,

string $emailoctopusSignature,

string $webhookSecret

): bool {

$knownSignature = sprintf('sha256=%s', hash_hmac('sha256', $requestBody, $webhookSecret));

return hash_equals($knownSignature, $emailoctopusSignature);


Frequently asked questions

How quickly will events be sent to my endpoint?

Events are buffered for up to one minute before being sent to your endpoint. This allows us to collect multiple events into a single payload. Regardless of this, once 1000 events are collected we send them to your endpoint as soon as possible.

What happens if my endpoint is temporarily unavailable?

If we cannot send a request to your endpoint, it will be retried up to 9 times. These retries take place over the course of about 10 days, with an increasing delay between each retry.

Can I receive only specific events that I’m interested in?

When setting up a webhook, you can specify which event types to receive.

You can also exclude events that were generated via our API or an import.

How many webhook endpoints can I create?

We support 2 webhook endpoints per team.

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.

Still need help? Contact us Contact us