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

# webhooks

Subscribe to events, fire test deliveries, and rotate signing secrets.

# `rogeriq webhooks`

**list / get**

```bash
    rogeriq webhooks list
    rogeriq webhooks get wh_xxx
    ```

  **create**

```bash
    rogeriq webhooks create \
      --url https://example.com/rogeriq-hook \
      --events 'conversation.*,message.created'
    ```

    Returns the webhook record **with the secret populated**. Store the
    secret — it is not retrievable later.

  **update**

```bash
    rogeriq webhooks update wh_xxx --status disabled
    rogeriq webhooks update wh_xxx --url https://new-url/hook --events '*'
    ```

  **test**

```bash
    rogeriq webhooks test wh_xxx
    ```

    Fires a `webhook.test` event immediately. Returns delivery status,
    HTTP status code, and duration. Test events skip the long-tail retry
    workflow.

  **deliveries**

```bash
    rogeriq webhooks deliveries wh_xxx
    ```

    Last 50 delivery attempts with status code, duration, attempt number,
    and status (delivered / failed).

  **rotate-secret**

```bash
    rogeriq webhooks rotate-secret wh_xxx
    ```

    Returns a new secret. The old secret stops working immediately, so
    update your receiver first.

  **delete**

```bash
    rogeriq webhooks delete wh_xxx
    ```

## Events

| Event | Fired when |
|-------|-----------|
| `conversation.created` | A new conversation is opened |
| `conversation.updated` | Status, priority, assignee, tags, or subject change |
| `conversation.resolved` | Conversation transitions to `resolved` |
| `message.created` | New customer / agent / AI message posted |
| `contact.created` | New contact created (via API, widget, or form) |
| `contact.updated` | Existing contact fields changed |
| `agent.escalated` | AI agent escalates to a human |
| `agent.action_executed` | Agent performs an automation action |
| `form.submitted` | A public form receives a submission |
| `webhook.test` | Sent by `webhooks test` |

Wildcards supported: `*` (all) and `conversation.*` (prefix).

## Delivery semantics

Inline retries: 1s, 5s, 30s on transient failure (5xx, 408, 425, 429,
network error). Permanent 4xx (except 408/425/429) bails out
immediately.

Long-tail retries: a Cloudflare Workflow re-attempts at 1m, 5m, 30m, 2h,
12h. The workflow re-fetches the webhook row each time, so disabling /
rotating mid-retry behaves correctly.

After 10 consecutive failures the webhook is auto-disabled.

## Verifying signatures

Use [`@rogeriq/sdk`](/sdk/webhooks) for `verifyWebhookSignature`. Works
in Node, Cloudflare Workers, Deno, browsers — uses the Web Crypto API.

Or verify manually:

```ts
import crypto from "node:crypto";

const signature = req.headers["x-rogeriq-signature"]; // "sha256=..."
const expected = "sha256=" + crypto
  .createHmac("sha256", process.env.WEBHOOK_SECRET!)
  .update(rawBody)
  .digest("hex");

if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
  return new Response("invalid signature", { status: 401 });
}
```

Headers on every delivery: `X-RogerIQ-Event`, `X-RogerIQ-Delivery`,
`X-RogerIQ-Signature`, `X-RogerIQ-Timestamp`, `X-RogerIQ-Attempt`.