Skip to main content
The Rhombus WebSocket event stream delivers real-time notifications about everything happening in your organization. This guide covers the event structure, available entity types, and patterns for filtering and processing events.

Event Topic

All organizational events are published to a single topic:
/topic/change/{orgUuid}
Every create, update, and delete operation across your Rhombus organization emits an event on this topic.

Event Payload Structure

Each MESSAGE frame contains a JSON body with the following fields:
{
  "entity": "POLICY_ALERT",
  "entityUuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "update": { },
  "type": "CREATE",
  "deviceUuid": "d1e2f3a4-b5c6-7890-abcd-ef1234567890",
  "targetUsers": [],
  "targetRoles": [],
  "subLocationsHierarchyKey": ""
}

Core Fields

FieldTypeDescription
entitystringThe type of entity that changed
entityUuidstringUnique identifier for the specific entity
updateobjectEntity-specific payload. Its contents vary by entity type and are not a fixed schema — inspect the keys present for each entity type you handle
typestringChange type: CREATE, UPDATE, DELETE, or REFRESH
deviceUuidstringAssociated device UUID (when applicable)
targetUsersarrayUsers this change is targeted to
targetRolesarrayRoles this change is targeted to
subLocationsHierarchyKeystringSub-location hierarchy key for the change
Event-specific detail (for example, the particulars of a policy alert) lives inside the update object. Its shape depends on the entity type, so read the keys present on update rather than assuming a fixed structure.

Change Types

TypeDescriptionExample
CREATEA new entity was createdNew policy alert triggered
UPDATEAn existing entity was modifiedAlert status changed
DELETEAn entity was removedAlert dismissed or cleared
REFRESHA general “re-fetch this entity” signal with no specific change semantics. This is the default when a producer doesn’t set a more specific type, so expect to receive itEntity changed in a way that isn’t a discrete create/update/delete

Entity Types

The entity field indicates what kind of object changed. Common entity types include:
EntityDescription
POLICY_ALERTSecurity policy violation alert
DEVICEA camera, sensor, or NVR device changed
The entity types available depend on your organization’s configured devices and policies. Subscribe to /topic/change/{orgUuid} and log the entity field of each event to discover all available event types.
Start by filtering for POLICY_ALERT events, which are the most common use case. Every entity type is delivered on the same /topic/change/{orgUuid} topic — there is no server-side entity filter on the subscription, so filter client-side by inspecting the entity field in your message handler and ignoring the types you don’t need.

Inspecting Policy Alerts

When an event has entity: "POLICY_ALERT", the alert-specific detail is carried inside the update object. The shape of update depends on the entity type and is not a fixed public schema, so inspect the keys present on each alert rather than assuming particular fields:
def inspect_alert(payload):
    if payload.get("entity") != "POLICY_ALERT":
        return
    update = payload.get("update", {})
    # `update` is entity-specific. Discover its keys at runtime
    # instead of assuming a fixed structure.
    print(f"Alert {payload.get('entityUuid')} update keys: {list(update.keys())}")
To learn the structure of update for the entity types you care about, connect, subscribe, and log a few real events. The keys present depend on the entity type and may evolve, so treat update defensively.

Filtering Events

By Entity Type

Filter for specific event types to reduce noise:
def handle_message(payload):
    entity = payload.get("entity")

    if entity == "POLICY_ALERT":
        handle_alert(payload)
    elif entity == "DEVICE":
        handle_device_change(payload)
    else:
        # Log or ignore other entity types
        pass

By Change Type

React differently based on whether an event was created, updated, or deleted:
def handle_alert(payload):
    change_type = payload.get("type")

    if change_type == "CREATE":
        # New alert - send notification
        send_notification(payload)
    elif change_type == "UPDATE":
        # Alert updated - refresh dashboard
        refresh_dashboard(payload)
    elif change_type == "DELETE":
        # Alert cleared - close ticket
        close_ticket(payload)

By Device

Filter events for a specific camera or sensor:
WATCHED_DEVICES = {
    "camera-uuid-lobby",
    "camera-uuid-parking-lot",
}

def handle_message(payload):
    device_uuid = payload.get("deviceUuid")
    if device_uuid in WATCHED_DEVICES:
        process_event(payload)

By Entity and Change Type

React to specific kinds of security events by combining the entity and type fields:
def handle_alert(payload):
    if payload.get("entity") == "POLICY_ALERT" and payload.get("type") == "CREATE":
        # A new policy alert was raised. Alert-specific detail is in `update`;
        # inspect its keys to decide how to route the notification.
        send_urgent_notification(payload)

Enriching Events with REST API Data

WebSocket events contain minimal data for efficiency. Use the REST API to fetch additional details when needed:

Get Camera Name from Device UUID

import requests

def get_camera_name(api_token, device_uuid):
    """Fetch camera name for display purposes."""
    response = requests.post(
        "https://api2.rhombussystems.com/api/camera/getMinimalCameraStateList",
        headers={
            "x-auth-apikey": api_token,
            "Content-Type": "application/json"
        },
        json={}
    )
    cameras = response.json().get("cameraStates", [])
    for camera in cameras:
        if camera.get("uuid") == device_uuid:
            return camera.get("name", "Unknown Camera")
    return "Unknown Camera"

Get Alert Details

def get_alert_details(api_token, alert_uuid):
    """Fetch full policy-alert details from the REST API."""
    response = requests.post(
        "https://api2.rhombussystems.com/api/event/getPolicyAlertDetails",
        headers={
            "x-auth-apikey": api_token,
            "Content-Type": "application/json"
        },
        json={"policyAlertUuid": alert_uuid}
    )
    return response.json().get("policyAlert")
Cache camera names locally to avoid excessive REST API calls. Camera names change infrequently, so a cache with a 5-minute TTL works well.

Output Formats

Formatted Alert Display

def display_alert(payload, camera_name=""):
    entity = payload.get("entity", "UNKNOWN")
    change = payload.get("type", "UNKNOWN")
    update = payload.get("update", {})

    print(f"{change} {entity}  camera={camera_name}")
    print(f"  device={payload.get('deviceUuid', 'N/A')}")
    print(f"  uuid={payload.get('entityUuid', 'N/A')}")
    # `update` is entity-specific; print its keys to discover available detail.
    if update:
        print(f"  update keys={list(update.keys())}")
    print()

Raw JSON Output

For piping to other tools or logging systems:
import json

def output_json(payload):
    print(json.dumps(payload, indent=2))

Integration Patterns

Webhook Relay

Forward Rhombus events to your own webhook endpoint:
import requests

WEBHOOK_URL = "https://your-server.com/webhooks/rhombus"

def relay_to_webhook(payload):
    try:
        requests.post(WEBHOOK_URL, json=payload, timeout=5)
    except requests.RequestException as e:
        print(f"Webhook relay failed: {e}")

Slack Notifications

Send high-priority alerts to a Slack channel:
def send_slack_alert(payload, webhook_url):
    entity = payload.get("entity", "UNKNOWN")
    change = payload.get("type", "UNKNOWN")
    message = {
        "text": f":rotating_light: *Security Alert*\n"
                f"{change} {entity}\n"
                f"Entity: {payload.get('entityUuid', 'N/A')}  "
                f"Device: {payload.get('deviceUuid', 'N/A')}"
    }
    try:
        requests.post(webhook_url, json=message, timeout=5)
    except requests.RequestException as e:
        print(f"Slack notification failed: {e}")

Database Logging

Persist events for historical analysis:
import sqlite3
import json

def log_event(db_path, payload):
    conn = sqlite3.connect(db_path)
    conn.execute("""
        INSERT INTO events (entity, entity_uuid, change_type, device_uuid, payload)
        VALUES (?, ?, ?, ?, ?)
    """, (
        payload.get("entity"),
        payload.get("entityUuid"),
        payload.get("type"),
        payload.get("deviceUuid"),
        json.dumps(payload)
    ))
    conn.commit()
    conn.close()
Last modified on July 8, 2026