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

# Webhooks

> Receive call lifecycle events with optional signature verification.

In **Workers & Lines → Integration**, enter the webhook URL and select **Update**. New integrations default to unsigned delivery. Enable signing to authenticate deliveries, configure your receiver with the one-time secret, and complete the signing setup before assigning the integration. Other lines and existing calls keep their original webhook. A saved URL does not verify delivery.

## Event types

| Event           | Fires when                                | Notes                                                                         |
| --------------- | ----------------------------------------- | ----------------------------------------------------------------------------- |
| `call.incoming` | An inbound call is detected               | Your response accepts or declines customer\_decides calls within five seconds |
| `call.started`  | The call is answered and media is bridged |                                                                               |
| `call.ended`    | A call ends                               | Includes duration and terminal\_reason                                        |
| `call.failed`   | A call cannot be completed                | Includes a named failure reason                                               |

<a id="signature" />

## Signature verification

When signing is enabled, each delivery includes `X-Chert-Signature: sha256=<hex>`, the HMAC-SHA256 of the raw request body.

```javascript theme={null}
import { createHmac, timingSafeEqual } from "node:crypto";

const expected = "sha256=" + createHmac("sha256", WEBHOOK_SECRET)
  .update(rawBody)
  .digest("hex");

const actual = Buffer.from(signatureHeader ?? "", "utf8");
const wanted = Buffer.from(expected, "utf8");
if (actual.length !== wanted.length || !timingSafeEqual(actual, wanted)) {
  throw new Error("Invalid webhook signature");
}
```

<a id="delivery" />

## Delivery semantics

* Delivery is at least once; deduplicate on `event_id`.
* Timestamps are ISO-8601 UTC.
* Non-2xx responses retry with backoff.
* `call.incoming` does not retry past its decision deadline and fails closed.
