Skip to content

Create and rotate webhooks

Webhooks are the outbound integration surface — Slack, PagerDuty, SIEM collectors, anything that accepts an HTTPS POST. NovaVMS signs every delivery with HMAC-SHA256 so the receiver can verify the payload came from you and was not tampered with in transit. The signing secret is the single most sensitive item in a webhook definition: anyone with it can forge deliveries that look authentic. Operators create webhook definitions (URL, events filter, name); admins and owners are the only roles that can view or rotate the secret (D81).

Procedure

Create a webhook

  1. Open Settings -> Webhooks from the left nav.
  2. Click + Create Webhook.

Webhooks page with Create Webhook button highlighted top-right

  1. Fill in the form:
    • Name — human-readable label, for example Slack SOC channel.
    • URL — must be HTTPS. HTTP is rejected with a validation error.
    • Event types — tick any of alert, event, camera_status, gateway_status.
    • Enabled — leave on unless you want to stage first.
  2. Click Create.
  1. The secret is shown once in a modal. Copy it into your downstream integration’s secret store now — you cannot retrieve it later.

The secret is 32 random bytes hex-encoded (64-character lowercase ASCII; cloud/internal/alerts/webhook_service.go:263-269). The Create response only includes the plaintext secret when the caller is admin or owner (per D81 — webhook_handler.go:84-87). Operators who create the webhook see the definition without the secret field.

Signature verification contract: the receiver computes HMAC-SHA256(secret, body) and compares (constant-time) against the lowercase hex digest in the X-Webhook-Signature header (which has the literal prefix sha256=). Each delivery also carries X-Webhook-ID (unique webhook UUID) and X-Webhook-Timestamp (RFC 3339) for idempotency and replay protection.

Rotate a secret

  1. Open Settings -> Webhooks.
  2. Click Edit on the webhook.
  3. Click Rotate Secret.
  1. A new secret appears in a modal. Copy it immediately and update your downstream integration.

The old secret is invalidated on save — not when the modal closes. Anything still posting with the old secret will see signature-verification failures from the next delivery onward.

The audit log records action rotate_secret (entity_type webhook) with the actor user_id and a timestamp. (Note: the action name in v1 is the bare verb rotate_secret, not the webhook.secret_rotated form used elsewhere in the audit catalogue. Audit GAP-7-26 logs this naming drift for a future cleanup.)

Common variations

  • Rolling rotation (no downtime). Create a second webhook with the same URL but the new secret. Update the receiver to accept either secret during a migration window. Verify new deliveries signed with the new secret arrive. Delete the old webhook. This pattern avoids any window where deliveries are rejected.
  • Test a delivery without waiting for a real event. Click Test on the webhook row. NovaVMS sends a canned payload with is_test: true inside the data object using the current secret. The delivery appears in the delivery history.
  • Auto-disable after failure. After 5 consecutive failed deliveries (any non-2xx after retries, or network error), NovaVMS sets the webhook enabled=false. The UI badge shows Failing or Disabled. Fix the downstream issue, then flip the toggle back on. (401 / 403 short-circuit retries within a single delivery but still each count as one failure toward the threshold.)

If this didn’t work

  • URL rejected with validation error — the URL must be HTTPS. HTTP endpoints, localhost without TLS, and self-signed certs without a valid CA chain all fail.
  • Create returns 409 “Max webhooks reached” — you are at 20 webhooks per org. Delete unused ones or consolidate event filters onto fewer webhooks.
  • Downstream integration starts returning 401 right after rotation — it is still signing with the old secret. Update its configuration and retry. The delivery history shows signature_invalid as the failure class.
  • Rotate button not visible — your role is operator, not admin or owner. Webhook secret rotation is governance (D81). See Roles and permissions.