> ## Documentation Index
> Fetch the complete documentation index at: https://apidoc.mailercloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Set up webhooks

> Receive real-time notifications in your systems when campaigns send, open, click, bounce, or unsubscribe.

Webhooks push campaign events to your endpoint as they happen — no polling.

## Supported events

`campaign_sent` · `campaign_opened` · `campaign_clicked` · `unsubscribe` · `campaign_error` · `spam` · `hard_bounce`

## Create a webhook

```bash theme={null}
curl --request POST \
  --url https://cloudapi.mailercloud.com/v1/webhooks \
  --header 'Authorization: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "CRM sync",
    "url": "https://yourapp.com/hooks/mailercloud",
    "events": ["campaign_sent", "campaign_opened", "hard_bounce", "unsubscribe"]
  }'
```

Your endpoint should return a `2xx` status quickly; do any heavy processing asynchronously.

## Test it

Fire a sample payload at your endpoint before going live with [Test webhook](/api-reference/webhooks/test-webhook), and pause/resume delivery any time with [Toggle webhook status](/api-reference/webhooks/toggle-webhook-status).

## Typical uses

* Sync unsubscribes and hard bounces back to your CRM so you stop emailing dead addresses everywhere
* Trigger in-app flows when a customer opens or clicks a campaign
* Alert your team on `campaign_error` events

## Transactional webhooks

Transactional sends — through the [Email API](/guides/transactional-email) or
[SMTP relay](/guides/smtp-relay) — have their own webhooks, configured in the dashboard under
**Transactional → Settings → Webhooks** (not the campaign API above). Subscribe to any of these
events: `Sent`, `Delivery`, `Open`, `Bounce`, `Spam`, `Unsubscribe`, `Reject`.

Each event is an HTTP `POST` with a JSON body:

```json theme={null}
{
  "event": "Delivered",
  "message_id": "order-10482-confirmation",
  "email": "jane@example.com",
  "metadata": "example.com",
  "date_event": "2026-10-01 11:08:47",
  "ts": 1759310656,
  "ts_event": 1759310648
}
```

`Open` adds `browser`, `device`, `os`, `userAgent` and a `geo` object; `Bounce`, `Spam` and
`Reject` add a `description` with the reason.

### Your custom data on every event

Any passthrough key you attach to a send — `metadata.custom` on the
[Email API](/guides/transactional-email#custom-data-on-webhooks), or `X-MC-Custom-*` headers over
[SMTP relay](/guides/smtp-relay#custom-data-on-webhooks) — is returned on **every** event for that
message, inside a `custom` object (values as strings):

```json theme={null}
{
  "event": "Delivered",
  "message_id": "order-10482-confirmation",
  "email": "jane@example.com",
  "custom": {
    "order_ref": "10482",
    "repo_id": "412f80f9-0b34-41c3-bb54-88a13acef7a9"
  }
}
```

Keys that break a limit (max 10 keys, key name ≤ 50 chars, value ≤ 256 chars) are dropped and named
in a `custom_dropped` array — the send always succeeds. When no custom data was sent, neither field
appears.

### Payload signing

Turn on **Payload signing** when creating the webhook and every request carries a
`Webhook-Signature` (HMAC-SHA256 of the body, keyed by your secret) and a `Webhook-Timestamp`.
Recompute the HMAC and compare it in constant time, and reject stale timestamps to prevent replay.
With signing off, the payload is byte-identical and no signature headers are added.

<Info>
  For the full field reference per event, the custom-data limits, and signature-verification code,
  see the [Transactional webhooks help guide](https://help.mailercloud.com/en/articles/221-webhooks-in-api-platform).
</Info>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.