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

# Webhooks

> Receive HTTP callbacks when message and RCS events happen on your Clerk Chat workspace

## Overview

Webhooks let your application subscribe to events on your Clerk Chat workspace and receive an HTTP `POST` whenever those events occur — for example, when a message is sent, delivered, or received, or when a contact taps an RCS suggestion.

You register a URL, choose which event types you care about, and Clerk Chat delivers a JSON payload to that URL with retries and signature headers.

## Register a webhook

Webhooks are managed from the Clerk Chat dashboard:

1. Sign in at [clerk.ai](https://clerk.ai).
2. Open **Settings → Webhooks**.
3. Click **Add webhook** and fill in:
   * **Name** — a human-friendly label.
   * **URL** — the `https://` endpoint Clerk Chat will POST to.
   * **Event types** — the events you want to subscribe to (see below).
   * **Auth header** *(optional)* — a custom header name and value that Clerk Chat will send with each delivery so you can verify requests on your side. Defaults to `Authorization` if you only provide a value.
4. Save. The webhook is enabled immediately.

From the same screen you can edit a webhook, toggle it on/off, delete it, or open a webhook to inspect recent delivery attempts.

## Event types

| Event                 | When it fires                                                |
| --------------------- | ------------------------------------------------------------ |
| `message.sent`        | An outbound message has been accepted by the carrier.        |
| `message.delivered`   | An outbound message was delivered to the recipient's device. |
| `message.failed`      | An outbound message failed to send.                          |
| `message.read`        | A recipient has read an outbound message (where supported).  |
| `message.received`    | An inbound message arrived in one of your inboxes.           |
| `rcsPostbackReceived` | A contact tapped an RCS suggestion (quick reply or action).  |

## Payload

Every delivery is a `POST` with `Content-Type: application/json` and a body shaped like:

```json theme={null}
{
  "eventId": "5b8c4f1e-2c3a-4f1e-9d8a-7e6b5a4c3d2f",
  "type": "message.received",
  "teamId": "f1e2d3c4-b5a6-7890-1234-56789abcdef0",
  "occurredAt": "2026-05-08T17:42:11.123Z",
  "data": {
    "conversationId": "...",
    "inboxId": "...",
    "channel": "sms",
    "direction": "inbound",
    "from": "+15551234567",
    "to": "+15557654321",
    "body": "Hello!",
    "status": "received"
  }
}
```

The shape of `data` depends on `type`. Message events carry conversation, inbox, channel, direction, addresses, body, and status. RCS postbacks carry the suggestion id, suggestion text, template id, and the `messageId` that was tapped.

### Headers

Each request includes:

| Header                    | Description                                       |
| ------------------------- | ------------------------------------------------- |
| `User-Agent`              | `ClerkChat-Webhooks/1`                            |
| `X-ClerkChat-Event-Id`    | Stable id for this event — use it to deduplicate. |
| `X-ClerkChat-Event-Type`  | Same value as `type` in the body.                 |
| `X-ClerkChat-Delivery-Id` | Unique id for this delivery attempt.              |
| `X-ClerkChat-Attempt`     | Zero-based attempt index (`0` on the first try).  |

If you configured an auth header, it is included on every request — verify it on your side before trusting the payload.

## Responding to deliveries

* Reply with any `2xx` status code to acknowledge the delivery.
* Anything else (non-2xx, network error, or redirect) is treated as a failure.
* Requests time out after **10 seconds**, so do any heavy work asynchronously and respond quickly.
* Redirects are not followed — give us the final URL.

## Retries and auto-disable

Failed deliveries are retried up to **5 times** with exponential backoff, starting at \~2 minutes. You can see each attempt and its status under the webhook's deliveries view in the dashboard.

If a webhook accumulates **5 consecutive failed deliveries** (each having exhausted its retries), Clerk Chat automatically disables it so we stop hammering a broken endpoint. Re-enable it from **Settings → Webhooks** once your endpoint is healthy.

A successful delivery resets the failure counter, so transient blips won't disable a webhook on their own.

## Idempotency

Use `eventId` (also sent as `X-ClerkChat-Event-Id`) as your idempotency key. Clerk Chat won't deliver the same `eventId` to the same webhook twice, but retries reuse the same `eventId`, so your handler should be safe to invoke more than once per event.
