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

# Webhooks

> Learn how to configure webhooks to push changes on access requests.

In this guide, you'll learn how to use **Webhooks** to integrate a custom app with Opal. See the [Custom Integrations overview](https://docs.opal.dev/docs/custom-integrations-overview.md) to learn when to use webhooks.

> [!NOTE]
>
> You can currently only configure one webhook per organization.

## Setup

Under **Configuration** in the left panel, go to the **Webhooks** tab, enter the URL for your webhook endpoint (and optionally provide a custom PEM-encoded TLS CA certificate if your endpoint uses an internal CA), and select **Save Changes**.

![2312](https://mintcdn.com/opalsecurity/odnvD_MsXBxTor9u/images/docs/88aa32b5754e9d1305a4803601e6d0320a3700ae19ee5b43b07218a5ce49c79d-organization-settings-webhooks.png?fit=max\&auto=format\&n=odnvD_MsXBxTor9u\&q=85\&s=7ee7cedcc72503dd86a00358a4badc1e)

A signing secret will be generated. Your system should use this secret to validate the webhook's origin. Please see [this section](https://docs.opal.dev/docs/webhooks.md#verifying-requests-from-opal) for more details.

Next, create or edit a **Push-only app** from the **Inventory**, then toggle **Webhook for access changes**.

![](https://mintcdn.com/opalsecurity/fu-nWazMe1LxLhxi/images/docs/256fe9e1704385b74f4c20e5c2454ce8e5e7709f5d710c2d7d2f621376c9bcc0-webhook-access-changes-option.png?fit=max\&auto=format\&n=fu-nWazMe1LxLhxi\&q=85\&s=c96f89ec1d93fdce96886e4c9c57f8e6)

The webhook endpoint is expected to reply to the HTTP POST request with an HTTP `200`, `201`, or `202` response within 10 seconds of receiving the payload.

## Payload samples

Opal sends different payloads depending on the event type. The following event types are supported.

### Add users to resource

```json json theme={null}
{
  event_ts: 1643355931,
  organization_id: 'eec5dcd9-fb0a-4726-b283-4379b524a772',
  events: [
    {
      event_type: 'USER_ADDED_TO_RESOURCE',
      resource_type: 'CUSTOM',
      user_id: '[email protected]',
      resource_id: '0eb35db24007c8148',
      access_level: 'admin'
    }
  ]
}
```

### Remove users from resource

```json json theme={null}
{
  event_ts: 1643355980,
  organization_id: 'eec5dcd9-fb0a-4726-b283-4379b524a772',
  events: [
    {
      event_type: 'USER_REMOVED_FROM_RESOURCE',
      resource_type: 'CUSTOM',
      user_id: '[email protected]',
      resource_id: '0eb35db24007c8148',
      access_level: 'admin'
    }
  ]
}
```

### Add users to group

```json json theme={null}
{
  event_ts: 1643346009,
  organization_id: 'eec5dcd9-fb0a-4726-b283-4379b524a772',
  events: [
    {
      event_type: 'USER_ADDED_TO_GROUP',
      group_type: 'CONNECTOR_GROUP',
      user_id: '[email protected]',
      group_id: '00g1835ro5hxRmpel5d7'
    }
  ]
}
```

### Remove users from group

```json json theme={null}
{
  event_ts: 1643355811,
  organization_id: 'eec5dcd9-fb0a-4726-b283-4379b524a772',
  events: [
    {
      event_type: 'USER_REMOVED_FROM_GROUP',
      group_type: 'CONNECTOR_GROUP',
      user_id: '[email protected]',
      group_id: '00g1838z8y1VJcoTG5d7'
    }
  ]
}
```

### Add resources to group

```json json theme={null}
{
  event_ts: 1643356058,
  organization_id: 'eec5dcd9-fb0a-4726-b283-4379b524a772',
  events: [
    {
      event_type: 'RESOURCE_ADDED_TO_GROUP',
      group_type: 'CONNECTOR_GROUP',
      resource_type: 'CUSTOM',
      group_id: '00g1838z8y1VJcoTG5d7',
      resource_id: '0eb35db24007c8148'
    }
  ]
}
```

### Remove resources from group

```json json theme={null}
{
  event_ts: 1643356091,
  organization_id: 'eec5dcd9-fb0a-4726-b283-4379b524a772',
  events: [
    {
      event_type: 'RESOURCE_REMOVED_FROM_GROUP',
      group_type: 'CONNECTOR_GROUP',
      resource_type: 'CUSTOM',
      group_id: '00g1838z8y1VJcoTG5d7',
      resource_id: '0eb35db24007c8148'
    }
  ]
}
```

### Add groups to group

```json json theme={null}
{
  event_ts: 1643356120,
  organization_id: 'eec5dcd9-fb0a-4726-b283-4379b524a772',
  events: [
    {
      event_type: 'GROUP_ADDED_TO_GROUP',
      group_type: 'CONNECTOR_GROUP',
      member_group_type: 'CONNECTOR_GROUP',
      group_id: '00g1838z8y1VJcoTG5d7',
      member_group_id: '00g1835ro5hxRmpel5d7'
    }
  ]
}
```

### Remove groups from group

```json json theme={null}
{
  event_ts: 1643356150,
  organization_id: 'eec5dcd9-fb0a-4726-b283-4379b524a772',
  events: [
    {
      event_type: 'GROUP_REMOVED_FROM_GROUP',
      group_type: 'CONNECTOR_GROUP',
      member_group_type: 'CONNECTOR_GROUP',
      group_id: '00g1838z8y1VJcoTG5d7',
      member_group_id: '00g1835ro5hxRmpel5d7'
    }
  ]
}
```

## Verify requests from Opal

Verify requests from Opal with confidence by checking signatures using your signing secret.

Opal includes an `X-Opal-Signature` HTTP header on each HTTP request sent. The signature is created by combining the signing secret with the timestamp and the raw HTTP request body using a standard HMAC-SHA256 keyed hash.

Here is an example with Node to compute the signature using your signing secret and raw request body (`request.rawBody`). You can compare it against the value retrieved from the `X-Opal-Signature` header.

```js js theme={null}
const timestamp = request.header('X-Opal-Request-Timestamp')
const signingSecret = 'SIGNING_SECRET'
const sigBaseString = 'v0:' + timestamp + ':' + request.rawBody
const hmac = crypto.createHmac('sha256', signingSecret)
hmac.update(sigBaseString)
console.log(hmac.digest('hex'))
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.