> ## Documentation index
> Fetch the complete documentation index at: https://developer.rhombus.com/llms.txt
> Use it to discover all available pages before exploring further.

# Rhombus Webhooks

> Configure Rhombus webhooks to receive real-time HTTP POST notifications for camera alerts, door events, sensor thresholds, and button presses without polling.

Rhombus webhooks deliver real-time HTTP POST notifications to your server when events occur — door opens, camera alerts, sensor threshold breaches, button presses, and more. Instead of polling the API, your application receives events as they happen.

## How webhooks work

1. **Add a Webhook**

   Add a webhook URL in the console (**Settings → Integrations & Developer Resources → Webhooks**, with **Trigger Type** **Activity** or **Diagnostic**), or add a webhook action to a rule.

2. **Events Occur**

   When a subscribed event happens in your Rhombus environment (e.g., a door is forced open), the system generates an event payload.

3. **Receive Notifications**

   Rhombus sends an HTTP POST request to your registered URL with the event details as a JSON payload.

4. **Process & Respond**

   Your server returns `200 OK` within a few seconds and processes the event afterward. Rhombus doesn't retry a failed delivery; see [Delivery](https://developer.rhombus.com/webhooks#delivery).

## Event types

Rhombus supports webhook notifications for a wide range of events across your security infrastructure:

- **Camera Events**: Motion detection, analytics alerts, video clips saved, AI-powered detections
- **Access Control Events**: Door open/close, forced entry, access granted/denied, credential scans
- **Sensor Events**: Temperature, humidity, and air quality threshold alerts
- **Device Events**: Button presses, device online/offline status changes

## Sample webhook payload

When an event triggers a webhook, Rhombus sends a POST request to your URL with a JSON payload. The body depends on the webhook type.

### Rule webhook action

```json
{
  "uuid": "event-uuid-here",
  "orgUuid": "org-uuid-here",
  "ruleUuid": "rule-uuid-here",
  "triggeredTimestampMs": 1712678400000,
  "deviceEvents": [
    {
      "eventUuid": "device-event-uuid-here",
      "deviceUuid": "camera-uuid-here",
      "deviceType": "CAMERA",
      "locationUuid": "location-uuid-here",
      "timestampMs": 1712678400000,
      "activities": ["MOTION_HUMAN"]
    }
  ],
  "ruleTriggers": [
    {
      "type": "DEVICE_ACTIVITY_EVENT"
    }
  ]
}
```

> **Note**: This is the payload of a webhook action on a rule. It identifies the rule that fired (`ruleUuid`), the triggers that matched (`ruleTriggers`), and the underlying device events (`deviceEvents`). The specific fields present depend on the triggering event type, so set up a test webhook endpoint to inspect the full payload for your rules.

### Organization webhook (Activity and Diagnostic)

```json
{
  "version": "2",
  "activityTrigger": "MOTION_HUMAN",
  "summary": "One-line summary of the event",
  "deviceUuid": "camera-uuid-here",
  "location": "location-uuid-here",
  "deviceType": "CAMERA",
  "timestampMs": 1712678400000,
  "alertUuid": "alert-uuid-here",
  "durationSec": 10,
  "thumbnailLocation": "storage-region-here",
  "clipLocationMap": {
    "camera-uuid-here": "storage-region-here"
  }
}
```

> **Note**: Organization webhooks send one flat object per notification. An Activity webhook carries `activityTrigger` (comma-separated when several activities fired) and `alertUuid`; a Diagnostic webhook carries `diagnosticTrigger` and `diagnosticUuid` instead. The device fields, `durationSec`, `thumbnailLocation` and `clipLocationMap` appear only when they apply to the event.

## Delivery

The two kinds of webhook are delivered differently:

|                     | Rule webhook action          | Organization webhook (Activity or Diagnostic)                                                                                             |
| ------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| Set up in           | A rule's webhook action      | **Settings → Integrations & Developer Resources → Webhooks**, up to four URLs per trigger type                                            |
| Sent when           | The rule fires               | Rhombus sends a notification of that trigger type. There's no per-webhook event filter: every URL receives every notification of its type |
| Signature headers   | `x-rhombus-signature-sha256` | `x-rhombus-signature-sha256`, and also `x-rhombus-signature-sha1`                                                                         |
| Counts as delivered | `200` or `202`               | Any `2xx`                                                                                                                                 |
| Time limits         | 2 seconds to connect         | 5 seconds to connect, 60 seconds to respond                                                                                               |
| Retries             | None                         | None                                                                                                                                      |

Rhombus makes **one delivery attempt**. A delivery that fails (your server is down, slow to connect, or answers with another status) isn't sent again, and a failed rule webhook is recorded as an `EXTERNAL_WEBHOOK_FAILURE` diagnostic event in your organization. Build your receiver for that:

- **Acknowledge first, work later.** Return `200` as soon as the signature checks out, and process the event in a queue or background job.
- **Reconcile after an outage.** Webhooks are a fast path, not a record. After your endpoint has been unavailable, read what you missed from the API, for example policy alerts with [`getPolicyAlerts`](https://developer.rhombus.com/api-reference/event-webservice/get-recent-policy-alerts-for-organization) (see [Pagination](https://developer.rhombus.com/pagination#policy-alerts)).
- **De-duplicate and order by the payload.** Use the IDs in the body (`alertUuid`, the event `uuid`) to ignore repeats, and `timestampMs` rather than arrival order to sequence events.
- **Use HTTPS** with a certificate from a public certificate authority.

## Verifying webhook signatures

Rhombus signs webhook deliveries so you can confirm that a request came from Rhombus and that the body wasn't changed in transit. Every signed delivery carries `x-rhombus-signature-sha256`: the HMAC-SHA256 of the raw request body, keyed with that webhook's secret, in lowercase hexadecimal. Verify that header.

| Webhook type                                    | Where it's configured                                                                                                                                                                                                                               | Signature headers                                                                           |
| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| Organization webhooks (Activity and Diagnostic) | Console: **Settings → Integrations & Developer Resources → Webhooks**, or [`POST /api/integrations/webhooks/updateWebhookIntegrationV2`](https://developer.rhombus.com/api-reference/webhook-integrations-webservice/update-webhook-integration-v2) | `x-rhombus-signature-sha256` (HMAC-SHA256), and also `x-rhombus-signature-sha1` (HMAC-SHA1) |
| Rule webhook actions                            | The webhook action on a rule ([`POST /api/rules/createRule`](https://developer.rhombus.com/api-reference/rules-webservice/create-rule), [`POST /api/rules/updateRule`](https://developer.rhombus.com/api-reference/rules-webservice/update-rule))   | `x-rhombus-signature-sha256` (HMAC-SHA256)                                                  |

The `x-rhombus-signature-sha1` header on organization webhooks is an HMAC-SHA1 of the same body with the same secret. You don't need it when you verify `x-rhombus-signature-sha256`.

For both types:

- **Signed content:** the exact bytes of the HTTP request body (UTF-8 JSON). Verify the signature before you parse or re-serialize the body.
- **Key:** the webhook secret string, used as-is (its UTF-8 bytes). Secrets are 22-character base64url strings. Don't decode them.
- **Encoding:** lowercase hexadecimal.
- **Scope:** only the body is signed. There's no signed timestamp, so de-duplicate deliveries using IDs in the payload, such as `alertUuid` or the event `uuid`.
- **One secret per URL:** each webhook URL has its own secret. If you register several URLs, store a secret for each.

### Find your secret

**Organization webhooks.** Rhombus creates a secret when you add a webhook URL, and every organization webhook delivery is signed.

- In the console, open **Settings → Integrations & Developer Resources → Webhooks** and copy the value in the **Webhook Secret** column.
- With the API, [`POST /api/integrations/webhooks/updateWebhookIntegrationV2`](https://developer.rhombus.com/api-reference/webhook-integrations-webservice/update-webhook-integration-v2) returns `webhookSecret` when you add a `webhookUrl`.
- [`POST /api/integrations/webhooks/getWebhookIntegration`](https://developer.rhombus.com/api-reference/webhook-integrations-webservice/get-webhook-integration) returns each URL's `webhookSecret` under `orgIntegrationV2.activityWebhooksV2` and `orgIntegrationV2.diagnosticWebhooksV2`.

**Rule webhook actions.** When you create or update a rule with webhook actions, the response includes `webhookSecrets`, a map from each webhook URL to its secret. Store it securely.

- Updating a rule keeps the existing secret for URLs that already have one, and creates a secret for new URLs.
- Rhombus always generates these secrets. A secret sent in the request is ignored.
- A webhook action without a secret is delivered without a signature header. Update the rule to assign one.

### Verify a request

1. Read the raw request body as bytes, before any JSON parsing.
2. Read the `x-rhombus-signature-sha256` header.
3. Compute the HMAC-SHA256 of the raw body with your secret, hex-encode it in lowercase, and compare it with the header **in constant time**.
4. If the header is missing or doesn't match, respond `401` and discard the request. Otherwise process the event and return `200 OK` quickly. Rule webhook actions treat only `200` and `202` as delivered.

```python Python (Flask)
import hashlib
import hmac
import os

from flask import Flask, abort, request

app = Flask(__name__)
WEBHOOK_SECRET = os.environ["RHOMBUS_WEBHOOK_SECRET"]


def rhombus_signature_is_valid(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature.strip().lower())  # constant time


@app.post("/rhombus-webhook")
def rhombus_webhook():
    raw_body = request.get_data()  # raw bytes, exactly as sent
    signature = request.headers.get("x-rhombus-signature-sha256", "")  # empty when unsigned
    if not rhombus_signature_is_valid(raw_body, signature, WEBHOOK_SECRET):
        abort(401)
    event = request.get_json()
    # ... handle the event ...
    return "", 200
```

```javascript Node.js (Express)
const crypto = require("crypto");
const express = require("express");

const app = express();
const WEBHOOK_SECRET = process.env.RHOMBUS_WEBHOOK_SECRET;

function rhombusSignatureIsValid(rawBody, signature, secret) {
  if (!signature) return false; // unsigned request
  const expected = Buffer.from(crypto.createHmac("sha256", secret).update(rawBody).digest("hex"), "utf8");
  const received = Buffer.from(signature.trim().toLowerCase(), "utf8");
  return expected.length === received.length && crypto.timingSafeEqual(expected, received); // constant time
}

// express.raw keeps the body as a Buffer, so the bytes match what Rhombus signed.
app.post("/rhombus-webhook", express.raw({ type: "application/json" }), (req, res) => {
  if (!rhombusSignatureIsValid(req.body, req.get("x-rhombus-signature-sha256"), WEBHOOK_SECRET)) {
    return res.sendStatus(401);
  }
  const event = JSON.parse(req.body.toString("utf8"));
  // ... handle the event ...
  res.sendStatus(200);
});

app.listen(8080);
```

> **Tip**: To test your implementation, use the secret `AAAAAAAAAAAAAAAAAAAAAA` and the body `{"version":"2","summary":"Test webhook"}`. The expected `x-rhombus-signature-sha256` is `5d3808f7c72ed8b6e52c12cf3ae13e72667d316178c6110081d58282828b2482`, and the expected `x-rhombus-signature-sha1` is `7c67f32d7b1320f76fa6d171a1a54dd6808570b6`.

## Managing webhooks via the API

Organization webhooks are managed with the Webhook Integrations operations:

- [`getWebhookIntegration`](https://developer.rhombus.com/api-reference/webhook-integrations-webservice/get-webhook-integration) reads the configured URLs.
- [`updateWebhookIntegrationV2`](https://developer.rhombus.com/api-reference/webhook-integrations-webservice/update-webhook-integration-v2) sets the URLs for each trigger type (Activity or Diagnostic).
- [`deleteWebhookIntegrationV2`](https://developer.rhombus.com/api-reference/webhook-integrations-webservice/delete-webhook-integration-v2) removes them.

Each URL receives every notification of its trigger type; there's no filter to set. Rule webhook actions belong to their rule and are managed with the Rules operations in the [API Reference](https://developer.rhombus.com/api-reference/overview).

## Implementation guide

[Webhook receivers](https://developer.rhombus.com/implementations/webhook-listener) builds a complete receiver: signature checks on the raw body, queuing, reaching systems on a private network without opening it to the internet, and local testing.

## No-code alternatives

If you prefer a visual workflow builder over writing custom webhook handlers, Rhombus integrates with:

- [Zapier](https://developer.rhombus.com/low-code-no-code/zapier) — instant triggers for rule events, button presses, door events, and sensor alerts
- [Make.com](https://developer.rhombus.com/low-code-no-code/make) — webhook triggers with advanced data routing
- [n8n](https://developer.rhombus.com/low-code-no-code/n8n) — self-hosted webhook processing with AI agent capabilities
