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

# Webhooks

> Receive real-time HTTP callbacks when events happen in InboxMate.

Webhooks let you receive HTTP POST callbacks whenever something happens in your workspace — a new ticket is created, a chat requests human handover, a scheduled task fails. Point a webhook at any HTTPS endpoint you control and InboxMate will deliver signed JSON payloads as events occur.

## Setting up a webhook

1. Open **Settings** > **Webhooks**.
2. Click **Add webhook**.
3. Enter a **name**, the **URL** of your endpoint, and select the **events** you want to receive.
4. Save. InboxMate generates a signing secret — copy it immediately, it is shown only once.

You can rotate the secret at any time from the webhook's detail page. The old secret stops working the moment the new one is generated.

## Delivery format

Every event is delivered as an HTTP POST with a JSON body:

```json theme={null}
{
  "id": "evt_01HW...",
  "type": "ticket.created",
  "accountId": "9ab33ff6-c80e-4e87-933c-d77ddc5ae0cd",
  "occurredAt": "2026-04-18T12:30:00.000Z",
  "actorUserAccountId": "bb...",
  "subjectUserAccountId": null,
  "payload": {
    "ticketId": "...",
    "subject": "Sample ticket",
    "createdByUserAccountId": "bb..."
  }
}
```

Request headers:

| Header                 | Value                                                         |
| ---------------------- | ------------------------------------------------------------- |
| `Content-Type`         | `application/json`                                            |
| `User-Agent`           | `AgentHub-Notifications/1.0`                                  |
| `X-AgentHub-Event`     | Event type, e.g. `ticket.created`                             |
| `X-AgentHub-Event-Id`  | Unique event ID — use this for idempotency                    |
| `X-AgentHub-Signature` | `sha256=<hex>` — HMAC-SHA256 of the raw body with your secret |

## Verifying the signature

Compute HMAC-SHA256 over the **raw request body** using your webhook secret, prefix with `sha256=`, and compare against the `X-AgentHub-Signature` header in constant time.

```js theme={null}
import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(rawBody, headerSignature, secret) {
  const expected = 'sha256=' + createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  const a = Buffer.from(headerSignature);
  const b = Buffer.from(expected);
  return a.length === b.length && timingSafeEqual(a, b);
}
```

Reject any request whose signature does not verify.

## Supported events

| Event                           | When it fires                                                                          |
| ------------------------------- | -------------------------------------------------------------------------------------- |
| `ticket.created`                | A new ticket is created                                                                |
| `ticket.assigned`               | A ticket is assigned to a user                                                         |
| `ticket.commented`              | A comment is added to a ticket                                                         |
| `ticket.status_changed`         | A ticket status transitions                                                            |
| `ticket.deadline_approaching`   | A ticket deadline is within 7, 3, or 1 day                                             |
| `chat.started`                  | A new chat is started with one of your agents                                          |
| `chat.human_handover_requested` | A chat requests human handover                                                         |
| `email.received`                | A new inbound email arrives                                                            |
| `scheduled_task.completed`      | A scheduled task finishes successfully                                                 |
| `scheduled_task.failed`         | A scheduled task fails                                                                 |
| `contact.created`               | A new contact was added (see `payload.source`: `widget`, `inbound_email`, or `manual`) |

Each payload includes the IDs you need to look up further context through the API.

## Retries and dead-lettering

* Responses in the **2xx** range are treated as success.
* **4xx** responses are treated as permanent failures (no retry) — fix your endpoint and replay from the UI.
* **5xx**, timeouts, and network errors are retried with exponential backoff. After 3 failed attempts the event is moved to **dead letter**.
* Request timeout is **10 seconds**.

Your endpoint should respond quickly (ideally under 1 second) and do heavy processing asynchronously. Return a `200` as soon as you have accepted the payload.

## Delivery log and replay

Every attempt — successful or not — is recorded in the webhook's **delivery log** for 30 days. For each row you see the event type, HTTP status code, duration, response excerpt, and attempt number.

If a delivery fails permanently or dead-letters, click **Replay** on the failed row to re-queue the event. The dispatcher picks it up within 10 seconds and a new log entry appears when the retry lands.

## Idempotency

Replays and retries send the **same event ID** (`X-AgentHub-Event-Id`). Keep a short-lived cache of processed IDs on your side so repeated deliveries are safe.

## Limits

Webhooks are available on **Business** plans. Each workspace can configure up to 20 active webhook endpoints.
