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

# Webhooks

> Custral posts a signed JSON payload to your endpoint when something happens in a workspace. No polling, no socket to hold open.

A webhook is a standing instruction: *when this event happens in my workspace,
POST it to my URL*. You register the URL once, Custral signs and delivers every
matching event, and your endpoint runs on your own infrastructure.

```http theme={null}
POST https://api.yourapp.com/hooks/custral
X-Custral-Event: record.updated
X-Custral-Signature: t=1789412334,v1=4f3c9a…
Content-Type: application/json

{
  "id": "whd_3JAx8Qm2r",
  "event": "record.updated",
  "createdAt": "2026-09-11T14:18:54.201Z",
  "data": {
    "recordId": "rec_3Ab9xK2mQ7",
    "objectId": "obj_2Zc7pL",
    "propertyId": "prop_5Nd3kR",
    "previous": ["opt_qualified"],
    "current": ["opt_negotiation"],
    "record": {"name": "Ravenna Foods", "stage": ["opt_negotiation"]}
  }
}
```

## When to reach for one

<CardGroup cols={3}>
  <Card title="Webhooks" icon="webhook">
    You want to be **told** when something changes, and you own a server that
    can receive an HTTP request.
  </Card>

  <Card title="The API" icon="right-left" href="/dev/api-reference/requests">
    You want a **snapshot right now**, or you are catching up after downtime.
  </Card>

  <Card title="Workflows" icon="diagram-project" href="/automation/workflows/overview">
    The reaction lives **inside Custral**: send an email, create a task, move a
    stage. No endpoint to run.
  </Card>
</CardGroup>

Webhooks and workflows are not rivals. A workflow is the right tool when the
whole reaction happens in the workspace; a webhook is the right tool when your
own system has to know.

## How a delivery works

<Steps>
  <Step title="An event fires">
    Somebody creates a record, submits a form, completes a task. Custral emits a
    domain event, which you can also browse under [Settings → Events](/dev/events).
  </Step>

  <Step title="Custral matches your subscriptions">
    Every active subscription in the workspace whose event list matches is
    selected. One event can fan out to several endpoints.
  </Step>

  <Step title="A delivery is recorded, then queued">
    Each match gets a `whd_…` delivery row before anything leaves the building,
    so a delivery survives a worker restart.
  </Step>

  <Step title="Custral POSTs it, signed">
    The body is signed with your endpoint's secret and sent with a 10 second
    timeout. Any `2xx` is success. Anything else is
    [retried](/dev/webhooks/delivery).
  </Step>
</Steps>

## What you can subscribe to

Nineteen events across records, forms, tasks, email, the chat widget and
conversations, and every one of them actually emits.

| Resource                                            | Events                                                                                                                  |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| [Records](/dev/webhooks/events/records)             | `record.created`, `record.updated`, `record.deleted`                                                                    |
| [Forms](/dev/webhooks/events/forms)                 | `form.submitted`                                                                                                        |
| [Tasks](/dev/webhooks/events/tasks)                 | `task.completed`                                                                                                        |
| [Email](/dev/webhooks/events/email)                 | `email.received`, `email.replied`, `email.sent`, `email.opened`, `email.clicked`, `email.bounced`, `email.unsubscribed` |
| [Widget](/dev/webhooks/events/widget)               | `widget.conversation.started`, `widget.visitor.identified`, `widget.keyword.matched`                                    |
| [Conversations](/dev/webhooks/events/conversations) | `conversation.assigned`, `conversation.completed`, `conversation.deleted`, `conversation.outcome_set`                   |

You can also subscribe with `*` for everything, or a prefix glob like
`record.*`. See the [event catalog](/dev/webhooks/events/overview) for when each
one fires and the exact payload it carries.

<Note>
  If an event you want is not on that list, tell us which one at
  [hello@custral.com](mailto:hello@custral.com).
</Note>

## Start here

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/dev/webhooks/quickstart">
    Register an endpoint and receive your first event.
  </Card>

  <Card title="Payload format" icon="code" href="/dev/webhooks/payload">
    The envelope and the headers on every delivery.
  </Card>

  <Card title="Verify signatures" icon="shield-check" href="/dev/webhooks/security">
    The one thing you must not skip.
  </Card>

  <Card title="Delivery and retries" icon="arrows-rotate" href="/dev/webhooks/delivery">
    What happens when your endpoint is down.
  </Card>
</CardGroup>


## Related topics

- [TypeScript SDK](/dev/sdks/typescript.md)
- [Events](/dev/events.md)
- [Event catalog](/dev/webhooks/events/overview.md)
- [API Reference](/dev/api-reference/overview.md)
- [Real-time updates](/dev/realtime/overview.md)
