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

# Webhook events

> Understand the current Email, SMS, contact, suppression, and broadcast webhook event catalog

<Warning>
  Customer-configurable outgoing webhooks are currently a preview. The
  subscribable event types below mirror the backend's canonical event catalog.
</Warning>

Webhook event types use a resource and lifecycle name such as `email.delivered`,
`contact.updated`, or `broadcast.sent`.

## Common envelope

Webhook deliveries use the canonical versioned event envelope:

```json theme={null}
{
    "id": "7fccf29e-d21e-4bc9-85a3-a4ec9c35a8dd",
    "type": "email.bounced",
    "version": "1",
    "team_id": "f84afc84-824b-441d-a75c-0d3245727e80",
    "object_type": "email",
    "object_id": "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794",
    "data": {
        "status": "partially_failed",
        "provider": "ses",
        "last_event": "bounce"
    },
    "occurred_at": "2026-08-30T11:00:00Z"
}
```

`version` is currently `"1"`. `object_type` is fixed by the event type, and all
currently subscribable events require an `object_id`. The `data` object contains
the resource-specific event payload.

Treat unknown fields and future event types as forward-compatible additions. Do
not fail an entire endpoint because it receives data your application does not
use.

## Subscribing to events

A webhook endpoint must subscribe to at least one supported event. Empty values
and duplicate event names are removed during validation. An unsupported event
name causes the endpoint create or update request to fail with `400 Bad Request`.

`webhook.test` is not a subscribable event. It is generated only when you test a
specific endpoint.

## SMS events

| Event             | Meaning                                      | Suggested action                                    |
| ----------------- | -------------------------------------------- | --------------------------------------------------- |
| `sms.submitted`   | The provider accepted the SMS for delivery.  | Mark the message submitted.                         |
| `sms.sent`        | The provider reported that the SMS was sent. | Continue waiting for final delivery when supported. |
| `sms.delivered`   | The provider reported successful delivery.   | Mark the notification delivered.                    |
| `sms.undelivered` | The provider could not deliver the SMS.      | Verify the destination before retrying.             |
| `sms.failed`      | Dugble could not complete SMS delivery.      | Record the failure for operational review.          |

## Email events

| Event                        | Meaning                                              | Suggested action                                             |
| ---------------------------- | ---------------------------------------------------- | ------------------------------------------------------------ |
| `email.submitted`            | The email was submitted for provider delivery.       | Mark the message submitted and await final outcomes.         |
| `email.delivered`            | The provider reported successful delivery.           | Mark the affected recipients delivered.                      |
| `email.delayed`              | The provider reported a temporary delivery delay.    | Keep waiting or surface a delayed state.                     |
| `email.bounced`              | The provider reported a bounce.                      | Suppress permanent failures before retrying.                 |
| `email.complained`           | A recipient reported the email as spam.              | Suppress the recipient and investigate the send.             |
| `email.rejected`             | The provider rejected the email before delivery.     | Correct the message or sender configuration.                 |
| `email.failed`               | Dugble could not render or otherwise send the email. | Record the failure for operational review.                   |
| `email.opened`               | An open-tracking event was recorded.                 | Update engagement analytics without changing delivery state. |
| `email.clicked`              | A tracked-link click was recorded.                   | Update engagement analytics and attribution.                 |
| `email.subscription_changed` | A contact-list subscription preference changed.      | Synchronize the recipient's subscription preferences.        |

Email event payloads may include recipient-level state and provider diagnostics.
Engagement and subscription events do not imply a delivery-state transition.

## Contact events

| Event             | Meaning                                         | Suggested action                                          |
| ----------------- | ----------------------------------------------- | --------------------------------------------------------- |
| `contact.created` | A contact was created.                          | Create or refresh the contact in downstream systems.      |
| `contact.updated` | A contact's profile or messaging state changed. | Refresh the stored contact representation.                |
| `contact.deleted` | A contact was deleted.                          | Remove or tombstone the corresponding downstream contact. |

## Suppression events

| Event                 | Meaning                    | Suggested action                                              |
| --------------------- | -------------------------- | ------------------------------------------------------------- |
| `suppression.created` | A suppression was added.   | Stop sending affected email until the suppression is removed. |
| `suppression.deleted` | A suppression was removed. | Re-evaluate the address under your normal eligibility rules.  |

## Broadcast events

| Event                 | Meaning                                        | Suggested action                                        |
| --------------------- | ---------------------------------------------- | ------------------------------------------------------- |
| `broadcast.scheduled` | A broadcast was scheduled for future delivery. | Reflect the scheduled state in your application.        |
| `broadcast.queued`    | A broadcast entered the delivery queue.        | Treat delivery fanout as started.                       |
| `broadcast.sent`      | The broadcast completed its send lifecycle.    | Record completion and consume final metrics as needed.  |
| `broadcast.failed`    | The broadcast failed.                          | Surface the failure and inspect operational details.    |
| `broadcast.canceled`  | A queued broadcast was canceled.               | Stop treating remaining recipients as pending delivery. |

## Test events

Sending a test from an endpoint creates a `webhook.test` event targeted only to
that endpoint. It uses the canonical envelope with `object_type` set to
`webhook_endpoint`, but it cannot be included in `subscribed_events`.

## Delivery headers and signature

Each request includes:

* `X-Dugble-Event`: event type
* `X-Dugble-Event-Id`: stable event UUID
* `X-Dugble-Delivery-Id`: UUID for this endpoint delivery
* `X-Dugble-Signature`: timestamped HMAC signature

The signature has the form `t=<unix_timestamp>,v1=<hex_digest>`. Compute the
expected digest with HMAC-SHA256, using the endpoint signing secret as the key
and `<unix_timestamp>.<raw_request_body>` as the signed bytes. Compare digests
with a constant-time function and reject timestamps outside your tolerance.

<Card title="Signature verification" icon="key" href="/docs/webhooks/signatures">
  Follow the complete signing contract and verification examples.
</Card>

## Idempotent handling

Your endpoint should:

1. Verify the webhook signature against the raw request body.
2. Store the event ID with a unique constraint.
3. Acknowledge duplicate IDs without repeating side effects.
4. Queue application work and respond quickly.
5. Log unknown event types rather than returning an error.
