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

# Webhooks

> Receive real-time notifications when events occur in your workspace

## Overview

Webhooks let you receive HTTP notifications when events happen in your workspace. Instead of polling the API, you can subscribe to specific events and Voyant will send a POST request to your endpoint.

## Creating a subscription

<Steps>
  <Step title="Create a subscription">
    ```bash theme={null}
    curl -X POST https://api.voyantcloud.com/v1/webhooks/subscriptions \
      -H "Authorization: Bearer $VOYANT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "url": "https://example.com/webhooks/voyant",
        "events": ["booking.created", "booking.updated"]
      }'
    ```

    The response includes a `secret` - store it securely. You'll need it to verify webhook signatures.
  </Step>

  <Step title="Verify signatures">
    Validate incoming webhooks using the `X-Webhook-Signature` header:

    ```javascript theme={null}
    import crypto from "node:crypto"

    function verifyWebhook(payload, signature, secret) {
      const expected = crypto
        .createHmac("sha256", secret)
        .update(payload, "utf8")
        .digest("hex")

      return crypto.timingSafeEqual(
        Buffer.from(signature, "hex"),
        Buffer.from(expected, "hex")
      )
    }
    ```
  </Step>

  <Step title="Handle events">
    Return a `2xx` status to acknowledge receipt. Non-`2xx` responses trigger retries.

    ```javascript theme={null}
    app.post("/webhooks/voyant", (req, res) => {
      const signature = req.get("X-Webhook-Signature")

      if (!verifyWebhook(req.body, signature, process.env.WEBHOOK_SECRET)) {
        return res.status(400).send("Invalid signature")
      }

      const event = req.get("X-Webhook-Event")
      // Handle the event...

      res.status(200).send({ ok: true })
    })
    ```
  </Step>
</Steps>

## Event types

Subscribe to specific events or use wildcards:

| Pattern           | Description        |
| ----------------- | ------------------ |
| `booking.created` | Single event       |
| `booking.*`       | All booking events |
| `*`               | All events         |

### Available events

**Bookings & Payments**

* `booking.created`, `booking.updated`, `booking.cancelled`, `booking.confirmed`
* `booking.payment.success`, `booking.payment.failed`
* `payment.succeeded`, `payment.failed`, `payment.refunded`

**Products & Catalog**

* `product.created`, `product.updated`, `product.deleted`
* `product.published`, `product.archived`

**Inventory**

* `departure.created`, `departure.updated`, `departure.capacity.changed`
* `inventory.updated`

**Customers**

* `customer.created`, `customer.updated`, `customer.deleted`

**Collections & Tags**

* `collection.created`, `collection.updated`, `collection.deleted`
* `tag.created`, `tag.updated`, `tag.deleted`

## Webhook headers

Every webhook request includes these headers:

| Header                | Description                            |
| --------------------- | -------------------------------------- |
| `X-Webhook-Signature` | HMAC-SHA256 signature for verification |
| `X-Webhook-Event`     | Event type (e.g., `booking.created`)   |
| `X-Delivery-Attempt`  | Attempt number (1, 2, 3...)            |

## Retries

Failed deliveries are retried with exponential backoff. Return `2xx` to acknowledge, or `410 Gone` to permanently disable the subscription.

<Warning>
  Implement idempotency in your webhook handler - you may receive the same event more than once.
</Warning>

## Managing subscriptions

```bash theme={null}
# List subscriptions
curl https://api.voyantcloud.com/v1/webhooks/subscriptions \
  -H "Authorization: Bearer $VOYANT_API_KEY"

# Rotate secret (invalidates the old one)
curl -X POST https://api.voyantcloud.com/v1/webhooks/subscriptions/SUBSCRIPTION_ID/rotate-secret \
  -H "Authorization: Bearer $VOYANT_API_KEY"

# Delete subscription
curl -X DELETE https://api.voyantcloud.com/v1/webhooks/subscriptions/SUBSCRIPTION_ID \
  -H "Authorization: Bearer $VOYANT_API_KEY"
```

## Next steps

<CardGroup cols={2}>
  <Card title="Webhooks API" icon="code" href="/api-reference/webhooks/overview">
    Full API reference
  </Card>

  <Card title="Error handling" icon="triangle-exclamation" href="/api-reference/errors">
    Handle webhook failures
  </Card>
</CardGroup>
