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

# Webhooks Overview

> Receive real-time notifications when database events occur

Webhooks allow you to receive HTTP POST notifications when events occur in your database. Instead of polling for changes, you can subscribe to specific events and receive instant updates.

## Event Types

Webhooks support the following event types:

### Record Events

| Event            | Description                       |
| ---------------- | --------------------------------- |
| `record.created` | A new record was added to a table |
| `record.updated` | An existing record was modified   |
| `record.deleted` | A record was deleted from a table |

### Table Events

| Event           | Description                                   |
| --------------- | --------------------------------------------- |
| `table.created` | A new table was added to the database         |
| `table.updated` | A table's properties (like name) were changed |
| `table.deleted` | A table was deleted                           |

### Field Events

| Event           | Description                                        |
| --------------- | -------------------------------------------------- |
| `field.created` | A new field was added to a table                   |
| `field.updated` | A field's properties or configuration were changed |
| `field.deleted` | A field was removed from a table                   |

## Webhook Payload

When an event occurs, we send an HTTP POST request to your webhook URL with a JSON payload:

```json theme={null}
{
  "id": "evt_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "type": "record.created",
  "timestamp": "2025-01-15T10:30:00.000Z",
  "data": {
    "tableId": "tbl_abc123",
    "recordIds": ["rec_xyz789"],
    "records": [
      {
        "id": "rec_xyz789",
        "data": {
          "Name": "John Doe",
          "Email": "john@example.com"
        }
      }
    ]
  },
  "metadata": {
    "webhookId": 123,
    "organizationId": 456,
    "baseId": "base_def456",
    "attempt": 1,
    "source": "ui"
  }
}
```

### Payload Fields

| Field                     | Type   | Description                                                                  |
| ------------------------- | ------ | ---------------------------------------------------------------------------- |
| `id`                      | string | Unique event ID for idempotency                                              |
| `type`                    | string | The event type (e.g., `record.created`)                                      |
| `timestamp`               | string | ISO 8601 timestamp of when the event occurred                                |
| `data`                    | object | Event-specific data (see below)                                              |
| `metadata.webhookId`      | number | ID of the webhook subscription                                               |
| `metadata.organizationId` | number | Your organization ID                                                         |
| `metadata.baseId`         | string | The database ID                                                              |
| `metadata.attempt`        | number | Delivery attempt number (1 for first attempt)                                |
| `metadata.source`         | string | Where the change originated (`ui`, `public_api`, `zapier`, `make`, `import`) |

### Record Event Data

For record events (`record.created`, `record.updated`, `record.deleted`):

```json theme={null}
{
  "tableId": "tbl_abc123",
  "recordIds": ["rec_xyz789"],
  "records": [...],
  "previousRecords": [...]  // Only for record.updated
}
```

### Table Event Data

For table events (`table.created`, `table.updated`, `table.deleted`):

```json theme={null}
{
  "tableId": "tbl_abc123",
  "table": {
    "id": "tbl_abc123",
    "name": "Customers",
    "order": 0,
    "primaryFieldId": "fld_xyz"
  },
  "previousTable": {...}  // Only for table.updated
}
```

### Field Event Data

For field events (`field.created`, `field.updated`, `field.deleted`):

```json theme={null}
{
  "tableId": "tbl_abc123",
  "fieldId": "fld_xyz789",
  "field": {
    "id": "fld_xyz789",
    "name": "Email",
    "type": "email",
    "order": 1
  },
  "previousField": {...}  // Only for field.updated
}
```

## Verifying Webhook Signatures

Each webhook request includes an `X-Webhook-Signature` header containing an HMAC-SHA256 signature. Verify this signature to ensure the request came from Zite.

```javascript theme={null}
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler
app.post('/webhooks/zite', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const isValid = verifyWebhookSignature(req.body, signature, YOUR_WEBHOOK_SECRET);

  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  // Process the webhook...
  res.status(200).send('OK');
});
```

## Request Headers

Each webhook request includes these headers:

| Header                | Description                             |
| --------------------- | --------------------------------------- |
| `Content-Type`        | `application/json`                      |
| `X-Webhook-Signature` | HMAC-SHA256 signature of the payload    |
| `X-Webhook-Event`     | The event type (e.g., `record.created`) |
| `X-Webhook-ID`        | The unique event ID                     |
| `User-Agent`          | `Zite-Webhooks/1.0`                     |

## Retry Policy

If your webhook endpoint returns a non-2xx status code or times out, we'll retry the delivery:

* **Maximum retries**: 5
* **Retry delays**: 5s, 10s, 20s, 40s, 80s (exponential backoff)
* **Timeout**: 30 seconds per request

<Note>
  Your endpoint should return a 2xx status code within 30 seconds to acknowledge receipt. Process the webhook asynchronously if needed.
</Note>

## Limits

| Limit                     | Value            |
| ------------------------- | ---------------- |
| Max webhooks per database | 100              |
| Max events per webhook    | 20               |
| Max URL length            | 2,048 characters |
| Max payload size          | 256 KB           |
| Delivery timeout          | 30 seconds       |

## Best Practices

1. **Respond quickly**: Return a 2xx status immediately, then process asynchronously
2. **Handle duplicates**: Use the event `id` for idempotency in case of retries
3. **Verify signatures**: Always verify the `X-Webhook-Signature` header
4. **Use HTTPS**: Webhook URLs must use HTTPS for security
5. **Store your secret**: Save the webhook secret securely - it's only shown once on creation
