> For the complete documentation index, see [llms.txt](https://docs.icepanel.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.icepanel.io/integrations/webhooks.md).

# Webhooks

{% hint style="info" %}
Webhooks are only available on Scale and Enterprise plans
{% endhint %}

IcePanel can notify your server in real time whenever model objects or model connections change in your organization. You register a subscription pointing to a public HTTPS endpoint, and IcePanel will POST a signed JSON payload to that URL for every matching event.

### Subscriptions

A subscription tells IcePanel where to deliver events. All webhook subscriptions live under your organization settings. To create one, navigate to your organization settings, select **Webhooks**, then select **Create webhook**. Fill in the dialog , adding a custom name for your webhook so you can identify and add the endpoint URL.&#x20;

<figure><img src="/files/duDTq6lLBiPbTg3PMOZN" alt=""><figcaption></figcaption></figure>

Select **Create webhook**, and copy the signing secret displayed as it will not be shown again.

<figure><img src="/files/HUj3n4NwxEHPR19cFl0y" alt=""><figcaption></figcaption></figure>

### Events

When model object or connection data in your organization changes, IcePanel fires an event for each enabled subscription and sends a \`POST\` request with \`Content-Type: application/json\` to the endpoint configured on each subscription.

The request body looks like this:

```json
{
  "collection": "model-object",
  "operation": "updated",
  "organizationId": "0JnNFdtmTTDTZbH0NLLR",
  "subscriptionId": "nzIKI2OkmMm1z3KcqHNl",
  "resourceId": "nzIKI2OkmMm1z3KcqHNl",
  "before": {
    "id": "0kaIAscJNGbY4zdwZUXp",
    "versionId": "OPMle3buwNOgEbXkCvBm",
    "landscapeId": "87OkRSC8YfyyUZswblF0"
  },
  "after": {
    "id": "0kaIAscJNGbY4zdwZUXp",
    "versionId": "OPMle3buwNOgEbXkCvBm",
    "landscapeId": "87OkRSC8YfyyUZswblF0"
  }
}
```

Consumers should consider that the `before` and `after` values will vary depending on the collection the operation was executed on, while the top-level fields are always present.&#x20;

Each field in the payload is described below:

<table><thead><tr><th width="162.3046875">Field</th><th width="152.53125">Type</th><th>Description</th></tr></thead><tbody><tr><td>collection</td><td>string</td><td>Check table bellow</td></tr><tr><td>operation</td><td>string</td><td>Check table bellow</td></tr><tr><td>organizationId</td><td>string</td><td>Organization the event belongs to</td></tr><tr><td>subscriptionId</td><td>string</td><td>Subscription that dispatched this event</td></tr><tr><td>resourceId</td><td>string</td><td>ID of the affected resource</td></tr><tr><td>before</td><td>object | null</td><td>State before the change. <code>null</code> for <code>created</code> events</td></tr><tr><td>after</td><td>object | null</td><td>State after the change. <code>null</code> for <code>deleted</code> events</td></tr></tbody></table>

Webhook consumers are encouraged to call back the IcePanel API to fetch the full, up-to-date state of the affected resource. The following table describes the collections and operations that are currently supported by IcePanel webhooks.

| Collection         | Operations                    | API reference                                                                              |
| ------------------ | ----------------------------- | ------------------------------------------------------------------------------------------ |
| `model object`     | `created` `updated` `deleted` | [Get model object ](https://developer.icepanel.io/api-reference/model/objects/get)         |
| `model connection` | `created` `updated` `deleted` | [Get model connection ](https://developer.icepanel.io/api-reference/model/connections/get) |

### Signature Validation

Signature validation is a way to verify that an incoming HTTP request was genuinely sent by\
IcePanel and has not been tampered with in transit. IcePanel signs each request using a shared\
secret known only to IcePanel and the user who created the webhook subscription.

Each incoming webhook request sent by IcePanel includes headers that should be used to perform\
signature validation:

* `X-IcePanel-Signature`— an HMAC-SHA256 hex digest
* `X-IcePanel-Timestamp` — a Unix timestamp in seconds

To verify the received webhook request, check the `X-IcePanel-Timestamp` header and reject requests older than 5 minutes to prevent replay attacks. Then recompute the **HMAC-SHA256** signature using the received timestamp, body and your subscription secret. Compare the recomputed signature against the received `X-IcePanel-Signature` header value. Both should be equal for the signature validation to pass.&#x20;

Below is an example of how to verify using Node.js:

```javascript
// Shared secret from the IcePanel webhook subscription, used to verify request authenticity
const WEBHOOK_SUBSCRIPTION_SECRET = process.env.WEBHOOK_SUBSCRIPTION_SECRET

// Requests with a timestamp outside this window are rejected to prevent replay attacks
const WEBHOOK_TIMESTAMP_TOLERANCE = process.env.WEBHOOK_TIMESTAMP_TOLERANCE

/**
 * Validates an incoming webhook request by verifying the HMAC-SHA256 signature
 * @param {{ timestamp: string, body: string, signature: string }} options
 * @returns {boolean}
 */
function validateSignature(options) {
  // Reject requests older than WEBHOOK_TIMESTAMP_TOLERANCE
  const requestTimeMs = parseInt(options.timestamp, 10) * 1000
  if (Math.abs(Date.now() - requestTimeMs) > WEBHOOK_TIMESTAMP_TOLERANCE) {
    return false
  }

  // Compute the HMAC-SHA256 signature
  const expectedSignature = crypto
    .createHmac('sha256', WEBHOOK_SUBSCRIPTION_SECRET)
    // Interpolate timestamp and body using a dot character
    .update(`${options.timestamp}.${options.body}`)
    .digest('hex')

  // Compare the received signature with the computed signature
  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature),
    Buffer.from(options.signature)
  )
}
```

### Disabling webhooks

IcePanel allows you to disable webhooks that have been created. This means that if you wish to stop receiving events to a particular endpoint temporarily, you can disable the active webhook for as long as desired, then re-enable it when ready. This prevents you needing to completely delete the webhook, and is designed to give you greater control.&#x20;

To disable a webhook, select the ellipsis button that appears when you hover over a webhook. Here you can select “Disable webhook”. To re-enable it follow the same steps, but instead select the updated button “Enable webhook”.

<figure><img src="/files/U0kCyN50elw2P6vGMXav" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.icepanel.io/integrations/webhooks.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
