Webhook event types
This page lists every webhook event type the NovaVMS platform currently emits. Subscribe to an event by including its name in the events array when you create or update a webhook.
Event types
| Event type | Since | Status (audit 2026-05-23) | Description | Sample payload |
|---|---|---|---|---|
alert | v1.0 | Live | An alert rule matched an incoming event and fired. Carries the six current alert display/identity fields. | alert |
event | v1.0 | Rejected (B-7) | Reserved for a future per-event publisher that does not exist yet. The cloud now returns HTTP 400 when this value is submitted to POST /api/v1/webhooks. | event |
camera_status | v1.0 | Rejected (B-7) | Reserved for a camera-online/offline edge-triggered publisher that has not been wired. The cloud now returns HTTP 400 when submitted. | camera_status |
gateway_status | v1.0 | Rejected (B-7) | Reserved for a gateway-online/offline edge-triggered publisher that has not been wired. The cloud now returns HTTP 400 when submitted. | gateway_status |
Only alert is currently accepted by POST /api/v1/webhooks. Submitting any other value (including the three reserved entries above) returns 400 Validation. The reserved rows are documented here so payload shapes are pinned in advance — they will become live once the publishers ship, at which point this status column will flip.
Event types that sound plausible (event.created, alert.fired, clip.exported, user.invited, user.activated) are not emitted by v1.x. Future event types will be added here with the version in which they first ship.
Sample payloads
Every delivery is wrapped in the same envelope:
{ "event_type": "<event-type>", "timestamp": "2026-04-21T14:30:00Z", "data": { }}timestamp is RFC 3339 UTC. X-Webhook-ID is the webhook configuration UUID; the current JSON body does not include a webhook_id field. The per-event data shapes follow.
alert
The current alert wire payload is intentionally narrow. On the compiled-rule
fanout path, event_id, rule_name, and description are populated;
alert_id, camera_name, and severity are currently serialized as empty
strings. It does not embed the rule’s D95 predicates, legacy custom_tags, or
a nested event object.
{ "event_type": "alert", "timestamp": "2026-04-21T14:30:00Z", "data": { "alert_id": "", "rule_name": "Entrance person after hours", "camera_name": "", "event_id": "3c4d5e6f-7a8b-9c0d-1e2f-3a4b5c6d7e8f", "severity": "", "description": "Entrance person after hours", "is_test": false }}is_test:true is set when the payload originates from POST /api/v1/webhooks/{id}/test (use this flag to discard tests in production handlers). For compiled alerts, use event_id as the stable deduplication key and resolve additional rule or event details through the authenticated REST API.
event
Event payloads are D95 universal taxonomy (event_category, trigger_topic, trigger_source). The legacy trigger_type field is no longer present on event records (events.trigger_type was removed in migration 000053).
{ "event_type": "event", "timestamp": "2026-04-21T14:30:00Z", "webhook_id": "2d1e9c8b-7a6f-5e4d-3c2b-1a0f9e8d7c6b", "data": { "event_id": "3c4d5e6f-7a8b-9c0d-1e2f-3a4b5c6d7e8f", "camera_id": "8f2b3a71-0c4e-4b5f-9d1a-2e7c3a4b5d6f", "camera_name": "Lobby Camera", "site_name": "Headquarters", "event_category": "motion", "trigger_topic": "tns1:VideoSource/MotionAlarm", "trigger_source": "onvif", "raw_source": "hikvision", "raw_data": {"State": true, "ChannelID": 1}, "triggered_at": "2026-04-21T14:29:58Z", "description": "Person detected at entrance", "tags": ["person", "entrance"], "ai_severity": "info", "snapshot_url": "https://media.novavms.io/snap/3c4d5e6f-7a8b-9c0d-1e2f-3a4b5c6d7e8f.jpg" }}Universal ONVIF event payloads (D95)
The raw_source and raw_data fields expose the vendor-specific event payload that produced this normalized event, so subscribers can inspect details the gateway classifier did not preserve in tags or description. raw_source identifies the producer (camera vendor slug or software/manual/vlm); raw_data is the un-normalized JSON object the gateway received.
A Tapo tampering-scene event illustrates the shape:
{ "event_type": "event", "timestamp": "2026-04-21T14:31:00Z", "webhook_id": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", "data": { "event_id": "5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b", "camera_id": "8f2b3a71-0c4e-4b5f-9d1a-2e7c3a4b5d6f", "camera_name": "Storage Room", "site_name": "Headquarters", "event_category": "tampering_scene", "trigger_topic": "tns1:VideoSource/ImageTooDark", "trigger_source": "onvif", "raw_source": "tapo", "raw_data": {"Channel": "0", "TamperState": "tooDark", "Threshold": 12}, "triggered_at": "2026-04-21T14:30:58Z", "description": "Image too dark on Storage Room", "tags": ["tamper", "low_light"], "ai_severity": "warning" }}A Hikvision shelter / cover-camera tamper event surfaces with a different trigger_topic and raw_data shape:
{ "event_type": "event", "timestamp": "2026-04-21T14:32:00Z", "webhook_id": "0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d", "data": { "event_id": "7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d", "camera_id": "8f2b3a71-0c4e-4b5f-9d1a-2e7c3a4b5d6f", "camera_name": "Storage Room", "site_name": "Headquarters", "event_category": "tamper", "trigger_topic": "tns1:RuleEngine/TamperDetector/Tamper", "trigger_source": "onvif", "raw_source": "hikvision", "raw_data": {"eventType": "shelteralarm", "channelID": 1, "active": true}, "triggered_at": "2026-04-21T14:31:58Z", "description": "Tamper detected on Storage Room", "tags": ["tamper"], "ai_severity": "warning" }}See Universal ONVIF events for the full topic ladder, classifier rules, and per-vendor raw_data shapes.
camera_status
{ "event_type": "camera_status", "timestamp": "2026-04-21T14:30:00Z", "webhook_id": "5f6a7b8c-9d0e-1f2a-3b4c-5d6e7f8a9b0c", "data": { "camera_id": "8f2b3a71-0c4e-4b5f-9d1a-2e7c3a4b5d6f", "camera_name": "Lobby Camera", "site_name": "Headquarters", "status": "offline", "previous_status": "online", "offline_since": "2026-04-21T14:25:00Z" }}gateway_status
{ "event_type": "gateway_status", "timestamp": "2026-04-21T14:30:00Z", "webhook_id": "0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d", "data": { "gateway_id": "4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f90", "gateway_name": "Site A Gateway", "site_name": "Headquarters", "status": "offline", "previous_status": "online", "cameras_affected": 12 }}Signature header
Every delivery carries an HMAC-SHA256 signature in the X-Webhook-Signature header, computed over the raw request body with the webhook’s secret. See Verify a webhook signature for code samples in TypeScript, Python, and Go.
Delivery semantics
- At-least-once. A compiled alert may arrive more than once after transient network failures. Deduplicate it on
data.event_id;data.alert_idis empty on that path.X-Webhook-IDis the webhook UUID (constant per webhook), not a per-delivery identifier. See Setup for the header-vs-body rule. - Retry policy. A delivery makes one initial attempt plus up to three retries after 1, 5, and 30 seconds. A
401or403short-circuits the remaining retries for that delivery attempt. - Timeout. Each delivery attempt has a 60-second context timeout server-side; receivers should still return 2xx within 10 seconds to leave headroom.
- Auto-disable. After repeated consecutive failed deliveries the webhook is disabled (
enabled=false); admins re-enable it from/settings/webhooks. See Webhook delivery failures. - Ordering. Deliveries are not strictly ordered. Use the envelope
timestampto reorder on the receiver.
Related
- Manage webhooks — create, rotate secrets, and view delivery history from the Admin console
- Set up a webhook receiver — developer-side receive endpoint
- Verify a webhook signature — HMAC-SHA256 verification
- Webhook delivery failures — diagnose failed or disabled webhooks