
# Webhooks

Add `webhooks` to a table to fire outgoing HTTP `POST` requests when records are created, updated, or deleted. Each webhook is syntactic sugar over automations — internally it expands to a record trigger plus a `webhook.send` action. Webhook names must be unique within the table.

## Webhook Properties

| Property  | Description                                                                                            |
| --------- | ------------------------------------------------------------------------------------------------------ |
| `name`    | **Required.** Unique webhook identifier within the table.                                              |
| `url`     | **Required.** Destination URL. Must be a valid absolute `http(s)` URL.                                 |
| `events`  | **Required.** Record events that trigger delivery: any of `create`, `update`, `delete` (at least one). |
| `enabled` | Boolean. Whether the webhook is active (default `true`).                                               |
| `auth`    | Authentication for the outgoing request (HMAC, API key, or bearer). See below.                         |
| `retry`   | Retry policy for failed deliveries. See below.                                                         |
| `payload` | Payload field selection and metadata options. See below.                                               |

```yaml
webhooks:
  - name: order_created
    url: https://hooks.example.com/orders
    events: [create]
    enabled: true
```

## Authentication

`auth` secures the request. Three types are supported; secrets/keys/tokens support `$env.` references.

| Type     | Properties                                                                                        |
| -------- | ------------------------------------------------------------------------------------------------- |
| `hmac`   | `secret` (required), `algorithm` (`sha256` default, or `sha1`), `header` (signature header name). |
| `apiKey` | `key` (required), `header` (header name to carry the key).                                        |
| `bearer` | `token` (required) sent as a bearer token.                                                        |

```yaml
auth: { type: hmac, secret: '$env.PARTNER_WEBHOOK_SECRET', algorithm: sha256 }
```

```yaml
auth: { type: apiKey, key: '$env.SERVICE_API_KEY', header: X-API-Key }
```

```yaml
auth: { type: bearer, token: '$env.API_BEARER_TOKEN' }
```

## Retry Policy

`retry` controls how failed deliveries are retried.

| Property       | Description                                                                            |
| -------------- | -------------------------------------------------------------------------------------- |
| `maxAttempts`  | Number of retry attempts after the initial failure. `0` disables retries. Default `3`. |
| `backoff`      | Backoff strategy: `exponential` or `fixed`.                                            |
| `initialDelay` | Milliseconds before the first retry (default `1000`).                                  |
| `maxDelay`     | Maximum delay in milliseconds between retries.                                         |

```yaml
retry: { maxAttempts: 5, backoff: exponential, initialDelay: 1000, maxDelay: 300000 }
```

## Payload Selection

`payload` shapes what data is sent. `includeFields` (whitelist) and `excludeFields` (blacklist) are mutually exclusive, and every named field must exist on the table (the implicit `id` is always valid).

| Property                | Description                                              |
| ----------------------- | -------------------------------------------------------- |
| `includeFields`         | Only include these fields (whitelist).                   |
| `excludeFields`         | Exclude these fields (blacklist).                        |
| `includePreviousValues` | Include the record's previous values on `update` events. |
| `includeMetadata`       | Include event metadata in the payload.                   |

```yaml
payload: { includeFields: [customer, status, total], includePreviousValues: true }
```

## Full Example

```yaml
webhooks:
  - name: order_lifecycle
    url: https://hooks.example.com/orders
    events: [create, update, delete]
    enabled: true
    auth: { type: hmac, secret: '$env.ORDER_WEBHOOK_SECRET', algorithm: sha256 }
    retry: { maxAttempts: 5, backoff: exponential, initialDelay: 1000, maxDelay: 300000 }
    payload: { excludeFields: [internal_notes], includePreviousValues: true }
```

:::callout
**Validation.** Webhook `name`s must be unique within a table, and any field referenced by `payload.includeFields` / `excludeFields` must name a real field (or the implicit `id`). Invalid URLs and non-`http(s)` schemes are rejected at config-decode time.
:::
