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

# Webhooks: real-time event notifications

> Receive signed HTTP notifications when things happen in your Scribe workspace — conversions recorded, signatures published, teammates changed, campaigns going live.

Webhooks push events from your Scribe workspace to your own systems the moment they happen. Instead of polling the API, you register an HTTPS endpoint, subscribe to the [event types](/api-reference/webhooks/events) you care about, and Scribe sends a signed `POST` request for each event.

Typical uses: syncing conversions into your CRM or data warehouse, alerting on signature installation failures, mirroring teammate changes into internal tools, and reacting to campaigns going live.

<Note>
  Webhooks are part of the Scribe API and require a plan with API access. Only workspace owners and admins can manage webhook endpoints.
</Note>

## Setting up an endpoint

Webhook endpoints are managed from the Scribe dashboard:

1. Open **Settings → Webhooks** (in the Technical section).
2. Click **Manage webhooks**. This opens your workspace's webhook portal.
3. Add your HTTPS endpoint URL and pick the event types to subscribe to — or subscribe to all events.

The portal is also where you inspect delivery logs, replay failed deliveries, test endpoints, and rotate signing secrets. Everything in the portal is scoped to your workspace.

## Receiving events

Every delivery is an HTTP `POST` with a JSON body. The `type` field tells you which event you received; the rest of the payload is event-specific (see the [event catalog](/api-reference/webhooks/events)):

```json theme={null}
{
  "type": "conversion.recorded",
  "name": "purchase",
  "value": 99.0,
  "currency": "USD",
  "occurred_at": "2026-08-11T09:30:00Z",
  "...": "..."
}
```

Respond with any `2xx` status code to acknowledge the delivery. Anything else — including timeouts — counts as a failure and triggers retries.

## Verifying signatures

Every delivery is signed so you can verify it genuinely came from Scribe and was not tampered with. Each request carries three headers:

| Header           | Purpose                                            |
| ---------------- | -------------------------------------------------- |
| `svix-id`        | Unique id for this message (stable across retries) |
| `svix-timestamp` | Unix timestamp of the delivery attempt             |
| `svix-signature` | HMAC signature of the payload                      |

Scribe webhooks are powered by [Svix](https://www.svix.com/) and follow the widely-used signing scheme of the [Standard Webhooks](https://www.standardwebhooks.com/) specification. The easiest way to verify is an official Svix library — your endpoint's signing secret is shown in the webhook portal:

```javascript theme={null}
import { Webhook } from "svix";

const wh = new Webhook(WEBHOOK_SECRET);

// Throws if the signature is invalid or the timestamp is too old.
const payload = wh.verify(req.body, req.headers);
```

Verification libraries exist for most languages — see the [Svix documentation](https://docs.svix.com/receiving/verifying-payloads/how) for the full list and for manual verification details. Always verify signatures before trusting a payload, and reject deliveries with timestamps older than a few minutes to prevent replay.

## Delivery, retries and ordering

* **Retries** — failed deliveries are retried automatically with exponential backoff over roughly a day. Endpoints that keep failing are eventually disabled; you can re-enable them and replay missed deliveries from the portal.
* **At-least-once** — a delivery can occasionally arrive more than once. Handle deliveries idempotently: the `webhook-id` header is stable across retries of the same message and is the right dedup key.
* **Ordering is not guaranteed** — events are delivered independently and can arrive out of order. Use the payload's `occurred_at` when sequence matters.
* **Semantics** — most events are emitted on state *transitions*, not on every write. For example, `signature.installation.failed` fires once when an installation breaks, not daily while it stays broken, and `visitor.identified` fires only the first time a person is identified.

## Endpoint requirements

* HTTPS only, reachable from the public internet.
* Respond within 15 seconds — do your processing asynchronously if it can take longer.
* Deliveries originate from Svix; if you need IP allowlisting, the current address list is published in the [Svix documentation](https://docs.svix.com/receiving/source-ips).
