---
title: "Webhooks"
description: "Subscribe to implemented user, organization, membership, invitation, and SAML certificate events through signed HTTP deliveries."
locale: "en"
---

> Documentation Index
> Fetch the relevant documentation index at: https://vonvon.id/en/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

## Event naming

Implemented events follow the pattern `<object>.<action>`. The vonvon-webhook-event header and body type carry the exact event name; every delivery also has a unique `svix-id`.

| Object | Actions |
| --- | --- |
| `user` | created, updated, deleted, restored, banned, unbanned, deactivated |
| `organization` | created, updated, deleted, restored |
| `organization.auth_policy` | updated |
| `organization.delivery_channels` | updated |
| `organization.social_providers` | updated |
| `organization.outbound_saml_app` | created, deleted |
| `organization.scim_target` | created, deleted |
| `organizationMembership` | created, updated, deleted, restored |
| `organizationInvitation` | created, accepted, revoked |
| `connection` | saml\_certificate\_renewed |
| `user.*` | Subscription wildcard for all implemented user events. |
| `organization.*` | Subscription wildcard for all implemented organization events, including dotted sub-events. |
| `organizationMembership.*` | Subscription wildcard for all implemented organization membership events. |
| `*` | Subscription wildcard for every implemented event. |

## Payload structure

Every webhook delivery is an HTTP POST with `Content-Type: application/json`. The body contains the exact event `type` and its `data`; svix metadata is carried in request headers.

```json
{
  "type": "user.created",
  "data": {
"userId": "user_01abc"
  }
}
```

## Signature verification

Vonvon signs every delivery with HMAC-SHA256. Verify the signature before processing the payload. Reject deliveries older than 5 minutes to prevent replay attacks.

| Header | Description |
| --- | --- |
| `svix-id` | Unique message ID. Use this to deduplicate retried deliveries. |
| `svix-timestamp` | Unix seconds when the message was sent. |
| `svix-signature` | The svix-signature header starts with the literal v1, prefix, followed by the Base64-encoded HMAC-SHA256 of `${svix-id}.${svix-timestamp}.${raw-body}` using the endpoint signing secret. |

```ts
import { verifyWebhook } from '@vonvon-kit/backend'

const result = await verifyWebhook(request, {
  secret: env.VONVON_WEBHOOK_SECRET,
})
if (!result.ok) {
  return new Response('Invalid webhook', { status: 400 })
}
const { type, data } = result.value.payload
```

## Retries and dead letters

- Delivery attempts use exponential backoff and end in dead status. Queue-level exhaustion is persisted as an encrypted dead-letter record for Instance Manager inspection and replay.
- Delivery is decoupled from the authentication path through Cloudflare Queues. A slow or unavailable endpoint does not affect login latency.
- Use the `svix-id` header to deduplicate deliveries on your end. Retries carry the same `svix-id` as the original attempt.

```mermaid
flowchart LR
  Vonvon --> Queue
  Queue -->|HTTPS| Endpoint
  Endpoint -->|2xx| ACK
  Endpoint -->|non-2xx| Retry
  Retry --> Queue
  Retry -->|max_retries| dlq["D1 DLQ"]
```

## Endpoint recovery

Use `POST /v1/webhooks/:id/restore` to reactivate a deleted endpoint and `POST /v1/webhooks/:id/rotate-secret` to replace its signing secret. The new `signing_secret` is returned once. Product-level replay by delivery ID or `time range` is not implemented.

```shell
curl -X POST https://vonvon.id/v1/webhooks/webhook_xxx/rotate-secret \
  -H 'Authorization: Bearer sk_live_xxx'
```

## Delivery history boundary

Vonvon does not expose a pull Events API. Use `GET /v1/webhooks` to manage subscriptions; delivery state and queue dead-letter replay are operational surfaces for Instance Managers, not a tenant event stream.

```shell
curl 'https://vonvon.id/v1/webhooks?limit=100' \
  -H 'Authorization: Bearer sk_live_xxx'
```

Source: https://vonvon.id/webhooks/index.mdx
