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

# Webhooks

> Subscribe to 73 events and DMLY posts to your endpoint as they happen.

Rather than polling the API, register an endpoint and DMLY will `POST` to it whenever
something happens — a message arrives, an invoice is paid, an appointment is booked.

## Setting one up

<Steps>
  <Step title="Add a webhook integration">
    Go to **Salesbot → Integrations → Webhooks** and add your endpoint URL. It must be
    publicly reachable over HTTPS.
  </Step>

  <Step title="Choose events">
    Subscribe to the topics you care about, then select **Connect**. Subscribe narrowly:
    every event you accept and discard is a request your server paid for.
  </Step>

  <Step title="Copy the signing secret">
    DMLY generates a signing secret for you — you don't supply one. Once connected, the
    **Signing secret** panel appears: select **Reveal**, then **Copy**. Every delivery to
    your own endpoint is signed, so verify it — see [Verifying](#verifying-a-delivery).
  </Step>

  <Step title="Send a test">
    Use the test ping to confirm your endpoint is reachable and your signature check works
    before relying on it.
  </Step>
</Steps>

## The payload

Every delivery has the same envelope. Only `data` varies by topic:

```json theme={"dark"}
{
  "id": "9f1c4b6e-3a2d-4f8b-9c1e-2a7d5e8b0c31",
  "event": "contact.created",
  "occurred_at": "2026-07-14T09:30:00+00:00",
  "workspace_id": 42,
  "data": {
    "contact": { "id": "…", "name": "Ada Lovelace", "phone": "+15551230001" }
  }
}
```

Test pings carry an extra `"test": true` so you can ignore them in production logic.

## Headers

| Header                 | Value                                                                                            |
| ---------------------- | ------------------------------------------------------------------------------------------------ |
| `X-Salesbot-Event`     | The topic, e.g. `contact.created`                                                                |
| `X-Salesbot-Delivery`  | Id for this delivery. **Stable across retries** — for your own endpoints it is the envelope `id` |
| `X-Salesbot-Signature` | `sha256=<hmac>` — sent on every delivery to your own endpoints                                   |
| `User-Agent`           | `Salesbot-Webhooks/1.0`                                                                          |

## Verifying a delivery

The signature is an HMAC-SHA256 of the **raw request body**, keyed by your secret. Compute
it over the bytes exactly as received — parsing and re-serialising the JSON first will
change the bytes and the signature will never match.

```python theme={"dark"}
import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)
```

<Warning>
  Always compare with a constant-time function (`hmac.compare_digest`, `crypto.timingSafeEqual`).
  A plain `==` leaks timing information that can be used to forge a signature.
</Warning>

<Note>
  Zapier hook URLs are not signed. Their URLs are unguessable capability URLs, so they carry
  no `X-Salesbot-Signature` header. Signing applies to your own webhook endpoints.
</Note>

## Responding

Return any `2xx` to acknowledge. DMLY allows **8 seconds** before it treats the delivery as
failed, so acknowledge immediately and do the real work asynchronously — do not process the
event inline and then respond.

Failed deliveries are retried twice more, after roughly **10s** then **60s** — three
attempts in total. After that the delivery is logged as failed and dropped.

<Tip>
  Deliveries are at-least-once, not exactly-once: a timeout on your side can produce a
  retry for an event you already handled. Deduplicate on the envelope's `id` (or the
  identical `X-Salesbot-Delivery` header), which is stable across retries of the same
  event.
</Tip>

## Events

There are 73 topics across contacts, conversations, calls, message lifecycle,
appointments, classes, invoices, orders, payments, subscriptions, credits, the store,
automations and broadcasts.

Each one is documented with its full payload in the sidebar under this section — the list
is generated from the API itself, so it is never out of date.
