Webhooks
Rhombus Webhooks
Configure Rhombus webhooks to receive real-time HTTP POST notifications for camera alerts, door events, sensor thresholds, and button presses without polling.
On this page
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
- 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.
- Events Occur
When a subscribed event happens in your Rhombus environment (e.g., a door is forced open), the system generates an event payload.
- Receive Notifications
Rhombus sends an HTTP POST request to your registered URL with the event details as a JSON payload.
- Process & Respond
Your server returns
200 OKwithin a few seconds and processes the event afterward. Rhombus doesn't retry a failed delivery; see Delivery.
Event types
Rhombus supports webhook notifications for a wide range of events across your security infrastructure:
Motion detection, analytics alerts, video clips saved, AI-powered detections
Door open/close, forced entry, access granted/denied, credential scans
Temperature, humidity, and air quality threshold alerts
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
{
"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"
}
]
}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)
{
"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"
}
}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
200as 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(see Pagination). - De-duplicate and order by the payload. Use the IDs in the body (
alertUuid, the eventuuid) to ignore repeats, andtimestampMsrather 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 | x-rhombus-signature-sha256 (HMAC-SHA256), and also x-rhombus-signature-sha1 (HMAC-SHA1) |
| Rule webhook actions | The webhook action on a rule (POST , POST ) | 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
alertUuidor the eventuuid. - 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/updateWebhookIntegrationV2returnswebhookSecretwhen you add awebhookUrl. POST /api/integrations/webhooks/getWebhookIntegrationreturns each URL'swebhookSecretunderorgIntegrationV2.activityWebhooksV2andorgIntegrationV2.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
- Read the raw request body as bytes, before any JSON parsing.
- Read the
x-rhombus-signature-sha256header. - 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.
- If the header is missing or doesn't match, respond
401and discard the request. Otherwise process the event and return200 OKquickly. Rule webhook actions treat only200and202as delivered.
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 "", 200const 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);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:
getWebhookIntegrationreads the configured URLs.updateWebhookIntegrationV2sets the URLs for each trigger type (Activity or Diagnostic).deleteWebhookIntegrationV2removes 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.
Implementation guide
Webhook receivers 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: