ZevCampaign Docs
Sign up

Webhooks

Event catalogue

Every webhook event, when it fires, and what its payload carries.

Twelve events in four groups. Subscribe only to the ones you act on: an endpoint receiving everything and ignoring most of it is an endpoint that falls behind.

Audience

EventFires when
contact.subscribedSomeone confirmed a subscription, or was subscribed through the API. On a double opt-in topic this fires on CONFIRMATION, not on the form submission, so it always means consent.
contact.unsubscribedSomeone opted out, from a link in an email or the preference centre. Treat it as authoritative and stop contacting them from your own systems too.

Delivery

EventFires when
email.deliveredThe recipient’s mail provider accepted the message.
email.bouncedA permanent failure. The contact is suppressed automatically; you do not need to do it yourself.
email.complainedThe recipient reported it. The contact is suppressed automatically. Worth alerting on: complaints are the fastest way to lose a sending reputation.
email.failedWe could not send to this recipient at all. Unlike a bounce, nothing left our side.

Engagement

EventFires when
email.openedA tracking pixel loaded. Indicative, not certain: images are blocked, prefetched and cached, so treat it as weak evidence and never as proof someone read it.
email.clickedA tracked link was followed. Much stronger evidence of engagement than an open.

Campaigns

EventFires when
campaign.sendingA campaign started dispatching.
campaign.sentEvery recipient of a campaign has been attempted.
campaign.pausedA campaign was paused mid-send.
campaign.cancelledA campaign was cancelled mid-send. Queued recipients were not sent to and their quota was refunded.

Payload fields

Every per-recipient event (email.*) carries the same base:

FieldNotes
send_idThis one recipient’s send. Unique per recipient per campaign
campaign_id
campaign_name
contact_id
email
occurred_atWhen it happened at the provider, not when we saw it

Plus, per event:

email.bounced

FieldNotes
bounce_typepermanent, transient or undetermined
reasonThe provider’s own wording. Useful, not parseable
suppressedWhether we have stopped sending to this address

Only a permanent bounce suppresses. A transient one means a full mailbox or a bad afternoon, and the address is still mailable.

email.complained

FieldNotes
complaint_typeThe feedback loop’s category, when given
suppressedAlways true

email.failed

FieldNotes
reasonWhy it never reached the provider

Distinct from a bounce: nothing left our side. A missing merge-tag value, a render error, an address already suppressed. Do not treat this as a dead address, or you will suppress perfectly good ones.

email.opened

FieldNotes
countryTwo-letter code, when we can tell. null otherwise

email.clicked

FieldNotes
urlThe link followed
countryTwo-letter code, or null
device_typemobile, tablet, desktop, or null
clientMail client, or null

We report null rather than guessing. A confident wrong answer is worse in a report than an honest gap.

contact.subscribed

FieldNotes
contact_id, email
topic_id, topic_name
brand_id
sourcedouble_opt_in, api, import or dashboard
occurred_at

source tells you how strong the consent is. double_opt_in means they clicked a link in their own inbox.

contact.unsubscribed

FieldNotes
contact_id, email
scopetopic, brand or all
topic_id, topic_nameSet when scope is topic
brand_idSet for topic and brand
campaign_idWhich campaign the link was in, when it was one
occurred_at

Read the scope. topic means they left one topic, not your whole workspace. Treating it as a global opt-out loses you a subscriber who wanted to stay on everything else.

campaign.*

FieldNotes
campaign_id, campaign_name
subject
brand_id
status
recipient_countWhat the send was sized at
occurred_at

campaign.sent adds delivered, bounced, failed and skipped as they stood when the send finished. Delivery keeps moving afterwards, so treat them as a starting point and read the campaign for current numbers.

Which to subscribe to

Keeping a CRM in sync: contact.subscribed, contact.unsubscribed. These change who you are allowed to contact anywhere, including from your own transactional mail.

List hygiene: email.bounced, email.complained. We suppress automatically on our side; subscribe if you want to mirror it in your own database.

Alerting: email.complained. Complaints are the fastest way to lose a sending reputation, and a sudden cluster is worth waking somebody for.

Engagement scoring: email.opened, email.clicked. Weight clicks far above opens.

Operational dashboards: campaign.sent tells you a send finished without polling for it.

Updated at, Saturday, October 10, 2026