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

# Webhook alerts

## 1. Concepts

### What a webhook alert does

A webhook alert sends an HTTP POST request to an endpoint whenever a subscribed event happens in Zenskar, for example when a customer is created or an invoice is approved.

### Event categories and Contracts V3

Webhook events are organized into five categories: Customer, Invoice, Contract, Payment, and Entitlement. Organizations on Contracts V3 can only subscribe to Customer and Payment events. Invoice, Contract, and Entitlement events are not selectable when creating or editing a webhook under Contracts V3.

<Warning>
  The event picker in the webhook form does not currently expose every event Zenskar can send. `invoice.cancelled` and `entitlement.expired` exist but are not selectable when creating or editing a webhook.
</Warning>

### Enabling and disabling a webhook

A webhook can be paused without deleting it, keeping its configuration in place while stopping deliveries until it is resumed.

### Verifying a delivery

Each webhook delivery includes a signature, so the receiving system can confirm it came from Zenskar and was not altered in transit. Validate this signature before acting on a payload.

***

## 2. How-to guides

### Create a webhook

1. Click the account menu at the bottom of the sidebar, and select **Settings**.
2. Open the **Webhook Alerts** tab.
3. Click **Add Webhook Alert**.
4. Enter a **Webhook Name**.
5. Optionally click **Add Description** to add a description.
6. Enter the **Endpoint URL** that should receive the payload.
7. Enter a **Secret Key**. Use a long, random value.
8. Leave **Enable Webhook Alerts** checked to activate the webhook immediately, or uncheck it to create it disabled.
9. Select the events to subscribe to.
10. Click **Create**.

### Edit a webhook

1. Open **Settings > Webhook Alerts**.
2. Open the actions menu on the webhook's row, and select **Edit**.
3. Update any of the fields described in Create a webhook.
4. Click **Update**.

### Pause or resume a webhook

Open the actions menu on the webhook's row, and select **Pause** or **Resume**.

### Delete a webhook

1. Open **Settings > Webhook Alerts**.
2. Open the actions menu on the webhook's row, and select **Delete**.
3. Confirm the deletion.

### View a webhook's delivery history

1. Open **Settings > Webhook Alerts**, and click a webhook's row.
2. The **Alerts History** panel lists past deliveries.
3. Select a delivery to see its **Triggered Webhook Details** (webhook ID, status, and when it was last updated) and its **Event Information** (the JSON payload sent).

### Resend a delivery

Open a delivery's details, and use **Resend** to trigger it again.

### Validate a webhook signature

Compute an HMAC using SHA256 with the secret key over the raw payload body, and compare it against the value in the `X-Signature` header, which is prefixed with `sha256=`.

```python theme={null}
def verify_signature(payload_body, secret_token, signature_header):
    """Verify that the payload was sent from Zenskar by validating SHA256.

    Raise and return 403 if not authorized.

    Args:
        payload_body: original request body to verify (request.body())
        secret_token: Zenskar webhook token (WEBHOOK_SECRET)
        signature_header: header received from Zenskar (X-Signature)
    """
    if not signature_header:
        raise HTTPException(status_code=403, detail="X-Signature header is missing!")
    hash_object = hmac.new(secret_token.encode('utf-8'), msg=payload_body, digestmod=hashlib.sha256)
    expected_signature = "sha256=" + hash_object.hexdigest()
    if not hmac.compare_digest(expected_signature, signature_header):
        raise HTTPException(status_code=403, detail="Request signatures didn't match!")
```

### Troubleshooting

* **Contract, invoice, or entitlement events are not selectable**: these categories are not available in the webhook form for organizations on Contracts V3.
* **A delivery shows Failed**: the endpoint did not return an HTTP 200 response. Confirm the endpoint is reachable and returns 200 on success.
* **The signature does not match**: recompute the hash using the exact raw request body, not a re-serialized version of it. Re-serializing JSON can change the byte-for-byte content and produce a different hash.

***

## 3. Reference

### Location

**Settings > Webhook Alerts**.

### Fields

| Field                 | Required | Notes                                              |
| --------------------- | -------- | -------------------------------------------------- |
| Webhook Name          | Yes      |                                                    |
| Description           | No       | Hidden behind an Add Description action until used |
| Endpoint URL          | Yes      | Receives the payload through an HTTP POST request  |
| Secret Key            | Yes      | Used to sign each payload                          |
| Enable Webhook Alerts | No       | Checked by default                                 |
| Events                | No       | Which events this webhook subscribes to            |

### Event catalog

| Category    | Event                   | Description                                       |
| ----------- | ----------------------- | ------------------------------------------------- |
| Customer    | `customer.created`      | A new customer is created                         |
| Customer    | `customer.updated`      | Customer metadata, phases, or pricing is modified |
| Invoice     | `invoice.created`       | A new invoice is created                          |
| Invoice     | `invoice.updated`       | An invoice status is modified                     |
| Invoice     | `invoice.deleted`       | A draft invoice is deleted                        |
| Invoice     | `invoice.approved`      | An invoice is approved                            |
| Invoice     | `invoice.voided`        | An invoice is voided                              |
| Invoice     | `invoice.cancelled`     | An invoice is cancelled                           |
| Invoice     | `invoice.regenerated`   | An invoice is regenerated                         |
| Contract    | `contract.created`      | A new contract is created                         |
| Contract    | `contract.updated`      | Contract metadata, phases, or pricing is modified |
| Contract    | `contract.activated`    | Contract status changes to active                 |
| Contract    | `contract.deleted`      | A contract is deleted                             |
| Payment     | `payment.created`       | A payment is created                              |
| Payment     | `payment.updated`       | A payment is updated                              |
| Payment     | `payment.succeeded`     | A payment succeeds                                |
| Payment     | `payment.failed`        | A payment fails                                   |
| Payment     | `payment.refunded`      | A payment is refunded                             |
| Entitlement | `entitlement.granted`   | An entitlement is granted                         |
| Entitlement | `entitlement.exhausted` | An entitlement is exhausted                       |
| Entitlement | `entitlement.expired`   | An entitlement expires                            |

### Event availability by contract experience

| Category    | Earlier experience | Contracts V3                       |
| ----------- | ------------------ | ---------------------------------- |
| Customer    | Available          | Available                          |
| Payment     | Available          | Available                          |
| Invoice     | Available          | Not selectable in the webhook form |
| Contract    | Available          | Not selectable in the webhook form |
| Entitlement | Available          | Not selectable in the webhook form |

### Delivery status

| Status    | Meaning                                          |
| --------- | ------------------------------------------------ |
| Succeeded | The endpoint returned an HTTP 200 response       |
| Failed    | The endpoint did not return an HTTP 200 response |

### Signature validation

| Detail    | Value                   |
| --------- | ----------------------- |
| Header    | `X-Signature`           |
| Algorithm | HMAC using SHA256       |
| Format    | Prefixed with `sha256=` |
