Skip to main content
A webhook sends a JSON POST to a URL you choose each time a selected event happens in your workspace, such as a contact unsubscribing, an email bouncing or a form being submitted. Use webhooks to keep a CRM or data warehouse in sync, or to trigger your own workflows.

Add a webhook

Only workspace Owners and Admins can add, test, turn off or delete webhooks. Other members who can open the page see the list and each webhook’s status.
1

Open Webhooks

Go to Settings → Developers → Webhooks and click Add Webhook.
2

Enter the endpoint

Enter the Endpoint URL. It must start with https://, and it must be publicly reachable. Private and internal addresses are refused.
3

Set a signing secret

Enter a Signing Secret. It is optional, but without one deliveries are not signed and you cannot verify where they came from.
4

Pick the events

Tick at least one event under Events, then click Add Webhook.
5

Send a test

Click Test on the webhook’s row. A test delivery with "event": "test" is sent, and the result appears in the delivery history below the row.

Events

Double opt-in confirmations

When someone clicks a double opt-in confirmation link, you can receive two kinds of event:
  • LIST_SUBSCRIPTION_CONFIRMED is sent once for each list whose pending subscription the click activated. It is sent for a brand-new signup and for an existing, already-active contact who joined another double opt-in list. data holds contactId, email, listId and listName.
  • CONTACT_CONFIRMED is sent only when the contact was pending and is now active, so an already-active contact confirming a new list does not send it. data holds contactId and email.
A new signup who confirms one list therefore sends one CONTACT_CONFIRMED and one LIST_SUBSCRIPTION_CONFIRMED. To track list subscriptions, subscribe to LIST_SUBSCRIPTION_CONFIRMED. The same catalog is available from the API for integrations that build their own event picker. See the API reference.

What a delivery looks like

Every delivery has the same envelope. The event-specific fields are in data:
Each request also carries these headers:

Verify the signature

Deliveries follow the Standard Webhooks spec, so any Standard Webhooks library can verify them with your signing secret. To verify by hand, compute an HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw body} and compare it with the value after v1,:
Verify against the raw request body, exactly as received. If you parse the JSON and serialise it again, the signature will not match.
If your code already checks X-Signature-256, it keeps working: that header is sha256= followed by the hex HMAC-SHA256 of the raw body, keyed with the secret as-is.

Retries and automatic disabling

Respond with any 2xx status within 10 seconds to acknowledge a delivery. Anything else counts as a failure and is retried:
  • Three quick attempts, 1 and 2 seconds apart.
  • Then seven more after 5 minutes, 30 minutes, 2 hours, 5 hours, 8 hours, 8 hours and 10 hours. That makes 10 attempts over about 34 hours.
  • 410 Gone retires the webhook at once, and no more attempts are made.
  • 429 Too Many Requests backs off without counting as a failure.
If a webhook keeps failing for more than 12 hours, it is turned off and its pending retries are dropped. While a webhook is off, new events are not queued for it. Each webhook row shows its status: Active, Failing since a date, Disabled after 12h of failures, Retired (endpoint answered 410) or Inactive. Owners and Admins also get an on/off switch; next to it they see the status only when something is wrong (failing, or turned off automatically), since the switch already shows on or off. Turning a webhook back on clears its failure history.

Delivery history

Click the arrow on a webhook row to see its most recent deliveries. Each one shows whether it succeeded, the event, the HTTP status, the response time and when it was sent. Delete on a webhook also deletes its delivery history.

REST hooks for Zapier and Make

Integration platforms can subscribe and unsubscribe themselves through the API with a key that has the Webhooks — manage scope. These subscriptions receive the same JSON body and the webhook-id and webhook-timestamp headers. They are not signed, but failed deliveries are retried on the same schedule as your endpoints. They do not appear on the Webhooks page. See the API reference.

Troubleshooting