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

# Webhooks

<Info>
  **Pre-release** — contact your Fortary account team for access.
</Info>

When something happens in your custody account — a transaction is confirmed, a deposit address is created — Fortary sends a signed HTTP `POST` to an HTTPS endpoint you control.

## The delivery contract

* **At-least-once.** The same event can be delivered more than once — deduplicate on the event `id`.
* **Unordered.** A retried earlier event can arrive after a later one — order by the event's `date`, never by arrival time.
* **Signed.** Always [verify the signature](/api/reference/webhooks/verifying-signatures) before trusting a payload.

## Setting up a webhook

Webhooks can be managed in the Fortary web portal or through the API. When creating one you choose:

* **Entities** — the entity or entities (your organization's operating units in Fortary) whose events the webhook receives.
* **Event types** — an explicit list of the [event kinds](/api/reference/webhooks/event-types) to deliver. There are no wildcards; new kinds are opt-in.
* **Vault filter** *(optional)* — restrict vault-scoped events to specific vaults.
* **Notification email** — where Fortary sends operational notices, for example an [automatic disable](/api/reference/webhooks/delivery-and-retries#automatic-disabling).

The endpoint URL must be **HTTPS**. The signing secret (`whsec_…`) is returned **exactly once** at creation — store it in your secret manager immediately. A lost secret cannot be retrieved, only rotated. An entity can be covered by at most **20 active webhooks**.

## Authorization

Webhook reads require the `webhook:read` scope; mutations require `webhook:manage`. Because changing a webhook's URL redirects custody data, management is restricted to owner-level credentials. A webhook outside the credential's access returns `404`, never `403` — see [Authorization](/api/concepts/authorization).

## Operations

| Operation                                                                      | Path                                                 | Description                                                   |
| ------------------------------------------------------------------------------ | ---------------------------------------------------- | ------------------------------------------------------------- |
| [Create webhook](/api/reference/webhooks/create-webhook)                       | `POST /v1/webhooks`                                  | Create a webhook (returns the signing secret once)            |
| [List webhooks](/api/reference/webhooks/list-webhooks)                         | `GET /v1/webhooks`                                   | List webhooks across accessible entities                      |
| [Get webhook](/api/reference/webhooks/get-webhook)                             | `GET /v1/webhooks/{webhookId}`                       | Retrieve a webhook with its health counters                   |
| [Update webhook](/api/reference/webhooks/update-webhook)                       | `PATCH /v1/webhooks/{webhookId}`                     | Update URL, event kinds, vault filter, status, or description |
| [Rotate webhook secret](/api/reference/webhooks/rotate-webhook-secret)         | `POST /v1/webhooks/{webhookId}/rotate-secret`        | New secret, returned once; 24-hour grace window               |
| [Delete webhook](/api/reference/webhooks/delete-webhook)                       | `DELETE /v1/webhooks/{webhookId}`                    | Delete a webhook (history retained)                           |
| [Ping webhook](/api/reference/webhooks/ping-webhook)                           | `POST /v1/webhooks/{webhookId}/ping`                 | Signed test POST with the live result inline                  |
| [List webhook deliveries](/api/reference/webhooks/list-webhook-deliveries)     | `GET /v1/webhooks/{webhookId}/deliveries`            | Delivery history with per-attempt detail                      |
| [List webhook events](/api/reference/webhooks/list-webhook-events)             | `GET /v1/webhook-events`                             | The event log (31-day retention)                              |
| [Get webhook event](/api/reference/webhooks/get-webhook-event)                 | `GET /v1/webhook-events/{eventId}`                   | Event detail including how many webhooks matched              |
| [List event deliveries](/api/reference/webhooks/list-webhook-event-deliveries) | `GET /v1/webhook-events/{eventId}/deliveries`        | All deliveries of one event                                   |
| [Redeliver](/api/reference/webhooks/redeliver-webhook-delivery)                | `POST /v1/webhook-deliveries/{deliveryId}/redeliver` | Re-send a delivery's event                                    |

## Your first handler

Capture the raw body, verify the signature, acknowledge immediately, process asynchronously:

```typescript theme={null}
import { createServer } from "node:http";
import { verifyWebhookSignature } from "./verify-webhook-signature.js"; // from Verifying signatures

const secret = process.env.FORTARY_WEBHOOK_SECRET ?? ""; // whsec_…

createServer((req, res) => {
  const chunks: Buffer[] = [];
  req.on("data", (chunk) => chunks.push(chunk));
  req.on("end", () => {
    const rawBody = Buffer.concat(chunks).toString("utf8");
    const signature = req.headers["x-fortary-signature"];

    if (typeof signature !== "string" || !verifyWebhookSignature({ secret, signature, rawBody })) {
      res.writeHead(400).end();
      return;
    }

    res.writeHead(200).end(); // acknowledge before doing real work

    const event = JSON.parse(rawBody);
    // hand `event` to your queue / worker here — deduplicate on event.id
  });
}).listen(8080);
```

Respond with a `2xx` within **10 seconds**.

## Guides

* [Event types](/api/reference/webhooks/event-types) — every event kind, the envelope, and payload examples
* [Verifying signatures](/api/reference/webhooks/verifying-signatures) — the signature scheme with working code
* [Delivery & retries](/api/reference/webhooks/delivery-and-retries) — the retry schedule, automatic disabling, and redelivery
