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

# Webhooks

> Get events pushed to your server, signed.

Subscribe a URL to the events you care about. HueChat posts a JSON body for
each one and signs it with a secret only you and HueChat know.

## Create a subscription

```bash theme={null}
curl -X POST https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/outbound-webhooks \
  -H "Authorization: Bearer $HUECHAT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CRM sync",
    "url": "https://your-server.example/webhooks/huechat",
    "events": ["message.created", "conversation.created", "conversation.status_changed", "contact.created", "contact.updated"]
  }'
```

The response carries the `secret` **once**. Store it next to your token.

## Events

| Event                         | Fires when                                |
| ----------------------------- | ----------------------------------------- |
| `conversation.created`        | A new conversation starts                 |
| `conversation.updated`        | Labels or custom attributes change        |
| `conversation.status_changed` | Open, pending, resolved                   |
| `conversation.assigned`       | Assigned to an agent or team              |
| `message.created`             | A message is sent or received             |
| `message.updated`             | A message is edited or its status changes |
| `message.delivered`           | Delivery confirmed by the channel         |
| `message.read`                | Read by the recipient                     |
| `message.failed`              | Delivery failed                           |
| `contact.created`             | A contact is added                        |
| `contact.updated`             | A contact's profile changes               |
| `agent.assigned`              | An agent takes a conversation             |
| `agent.available`             | An agent comes online                     |
| `automation.triggered`        | An automation rule fires                  |
| `sla.breached`                | An SLA policy is breached                 |
| `webhook.test`                | You call the test endpoint                |

## What a delivery looks like

Headers:

| Header                | Example               |
| --------------------- | --------------------- |
| `X-HueChat-Signature` | `sha256=a1b2c3…`      |
| `X-HueChat-Event`     | `message.created`     |
| `X-HueChat-Delivery`  | `12345`               |
| `X-HueChat-Timestamp` | `1712345678`          |
| `User-Agent`          | `HueChat-Webhook/2.0` |

Body:

```json theme={null}
{
  "event": "message.created",
  "timestamp": "2026-04-05T12:00:00Z",
  "account_id": 3,
  "data": {
    "id": 789,
    "content": "Hi, I need help with my order",
    "message_type": 0,
    "conversation_id": 123,
    "sender": { "id": 456, "name": "Ahmed", "type": "contact" },
    "created_at": 1712345678
  }
}
```

## Verify the signature

<Warning>
  Always verify `X-HueChat-Signature` before acting on a delivery. Anyone who
  finds your URL can post to it; only HueChat can sign with your secret.
</Warning>

The signature is `sha256=` followed by the hex HMAC-SHA256 of the raw request
body, keyed with the subscription secret.

<CodeGroup>
  ```javascript Node.js theme={null}
  import crypto from "node:crypto";

  export function verify(rawBody, header, secret) {
    const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
    return expected.length === header.length &&
      crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
  }
  ```

  ```python Python theme={null}
  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)
  ```

  ```go Go theme={null}
  func verify(body []byte, header, secret string) bool {
  	mac := hmac.New(sha256.New, []byte(secret))
  	mac.Write(body)
  	expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
  	return hmac.Equal([]byte(expected), []byte(header))
  }
  ```
</CodeGroup>

Compute the HMAC over the **raw** bytes, before any JSON parsing or
re-serialisation.

## Responding

Return `200` within a few seconds and do the real work asynchronously. Any
other status counts as a failure and is retried. After 10 consecutive
failures the subscription is switched off; re-enable it with a `PATCH` once
your endpoint is healthy.

Use `X-HueChat-Delivery` to drop duplicates, and reject deliveries whose
`X-HueChat-Timestamp` is more than a few minutes old.

## Test, inspect, rotate

| Action                                | Call                                                                          |
| ------------------------------------- | ----------------------------------------------------------------------------- |
| Send a `webhook.test` event           | `POST /api/v2/accounts/{account_id}/outbound-webhooks/{id}/test`              |
| Delivery log with status and response | `GET /api/v2/accounts/{account_id}/outbound-webhooks/{id}/logs`               |
| New secret                            | `POST /api/v2/accounts/{account_id}/outbound-webhooks/{id}/regenerate-secret` |

## Account webhooks (v1)

`/core/accounts/{account_id}/webhooks` is the older subscription list used
by the dashboard's Settings → Integrations page. It posts a flat event
object with underscore event names such as `message_created` and carries
**no signature header**. It still works; for anything new, use the signed
subscriptions above.
