Skip to content

Webhook Notifications

The Telovix Console delivers alert and event notifications to external HTTP endpoints via webhooks. Webhooks are useful when another system (a SIEM, ticketing tool, pager, or custom automation) needs to receive Telovix alerts in near real-time without polling.

Prerequisites

  • admin role to create webhooks
  • Destination URL reachable from the Console host
  • operator role to test webhooks

How delivery works

The Console posts to the configured URL using an HTTP POST with Content-Type: application/json. The request timeout is 10 seconds. If the endpoint returns a non-2xx status or times out, the delivery is recorded as failed and the failure is visible in the webhook's last_delivery_status and last_delivery_error fields.

The Console does not automatically retry failed deliveries with backoff. The delivery state is updated after each attempt and is visible in the Console UI.


Webhook types

The webhook_type field controls how the Console formats the payload for the destination. Supported values:

TypeUse case
genericStandard JSON payload (default)
slackSlack Incoming Webhooks format
discordDiscord webhook format
teamsMicrosoft Teams connector format
pagerdutyPagerDuty Events API format
opsgenieOpsgenie Alert API format

If webhook_type is omitted on creation, it defaults to generic.


Managing webhooks

In the Console, go to Settings > Integrations > Webhooks to create, update, test, enable, disable, or delete webhooks.

Create a webhook

In the Console, go to Settings > Integrations > Webhooks and click Add Webhook. The Console presents these fields:

FieldRequiredDescription
display_nameYesHuman-readable label
target_urlYesMust start with http:// or https://
signing_secretNoSecret used to sign payloads (see Signature verification below)
webhook_typeNoOne of generic, slack, discord, teams, pagerduty, opsgenie (default: generic)
Webhook creation form showing the display name, target URL, webhook type selector, and optional signing secret field.
Webhook creation form showing the display name, target URL, webhook type selector, and optional signing secret field. Click to enlarge

Update a webhook

In the Console, go to Settings > Integrations > Webhooks, click the webhook row, and edit the fields. Omitted fields retain their current values. To clear the signing secret, set it to blank. To keep the existing signing secret, leave the field empty.

Delete a webhook

In the Console, go to Settings > Integrations > Webhooks, click the webhook row, and select Delete.

Test a webhook

In the Console, go to Settings > Integrations > Webhooks, click the webhook row, and click Send Test. The Console sends a test delivery to the configured URL. The test payload is an AlertDeliveryPayload with alert_kind: "test_delivery" and severity: "info". If the webhook has a signing secret configured, the test delivery is signed the same way as live deliveries.


Payload format (generic type)

Alert deliveries use the AlertDeliveryPayload structure. All timestamps are RFC3339. Optional fields are omitted from the JSON if null.

FieldTypeAlways presentDescription
versionStringYesPayload schema version (currently "1")
alert_kindStringYesAlert category (e.g., high_severity_runtime_event, renewal_due, trust_revoked)
severityStringYesinfo, warning, high, or critical
sensor_idStringYesID of the sensor that triggered the alert
node_nameStringYesDisplay name of the sensor node
trust_healthStringYesCurrent trust health of the sensor
headlineStringYesShort human-readable summary
detailStringYesLonger description of the alert
occurred_atString (RFC3339)YesWhen the event occurred
delivered_atString (RFC3339)YesWhen the delivery was sent
sourceStringYesInternal source identifier
pack_idStringNoPolicy pack ID if applicable
event_kindStringNoRuntime event kind that triggered the alert
rule_nameStringNoAlert rule name if applicable
messageStringNoEvent message from the sensor
processStringNoProcess binary path
mitre_techniqueStringNoMITRE ATT&CK technique ID
mitre_tacticStringNoMITRE ATT&CK tactic
observed_atString (RFC3339)NoWhen the underlying event was observed
declared_roleStringNoNF role of the sensor
os_nameStringNoOperating system name
os_versionStringNoOperating system version
architectureStringNoCPU architecture
kernel_versionStringNoKernel version
tagsArrayNoSensor tags (omitted if empty)
is_containedBooleanYesWhether the sensor is in containment
group_idsArrayNoSensor group IDs (omitted if empty)
related_event_countIntegerNoCount of related events
k8s_namespaceStringNoKubernetes namespace
pod_nameStringNoKubernetes pod name
workload_typeStringNoKubernetes workload type
workload_nameStringNoKubernetes workload name
container_idStringNoContainer ID
parent_executableStringNoParent process executable
ancestorsStringNoProcess ancestry chain (JSON string)
telecom_protocol_familyStringNoTelecom protocol family
telecom_interface_contextStringNoTelecom interface context
telecom_transport_contextStringNoTelecom transport context
alert_inbox_urlStringYesDirect URL to the alert in the Console

Example generic payload

The alert_inbox_url in these examples uses port 15483 (Telovix self-hosted default).

json
{
  "version": "1",
  "alert_kind": "high_severity_runtime_event",
  "severity": "high",
  "sensor_id": "sensor_3Tz8mQkLpNvXa1Yw",
  "node_name": "upf-prod-01",
  "trust_health": "healthy",
  "headline": "Privilege escalation detected on UPF node",
  "detail": "Process /opt/open5gs/bin/upf called setuid to root",
  "occurred_at": "2026-04-26T14:22:00Z",
  "delivered_at": "2026-04-26T14:22:01Z",
  "source": "alert_rule",
  "event_kind": "privilege_change",
  "process": "/opt/open5gs/bin/upf",
  "declared_role": "upf",
  "tags": ["site:oslo", "plmn:242-01"],
  "is_contained": false,
  "alert_inbox_url": "https://console.example.com:15483/alerts"
}

Saved search match payload

When a saved search alert fires, the payload format is different:

json
{
  "version": "1",
  "alert_kind": "saved_search_match",
  "search_id": "<id>",
  "search_name": "UPF network anomalies",
  "match_count": 15,
  "window_secs": 3600,
  "threshold": 10,
  "triggered_at": "2026-04-26T14:22:00Z",
  "event_search_url": "https://console.example.com:15483/events?saved_search_id=<id>"
}

Signature verification

When a signing_secret is configured, every delivery includes an X-Telovix-Signature header:

X-Telovix-Signature: sha256=<hex-encoded-hmac-sha256>

The signature is computed as HMAC-SHA256 over the raw JSON request body bytes using the signing secret.

Verifying the signature (Node.js example)

js
import { createHmac } from "crypto";

function verifyTelovixSignature(body, secret, signatureHeader) {
  const expected = "sha256=" + createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return signatureHeader === expected;
}

app.post("/telovix", (req, res) => {
  const sig = req.headers["x-telovix-signature"];
  const raw = JSON.stringify(req.body); // use raw body buffer in production
  if (!verifyTelovixSignature(raw, process.env.WEBHOOK_SECRET, sig)) {
    return res.status(401).send("invalid signature");
  }
  // process the payload
  res.sendStatus(204);
});

Use the raw request body bytes (before any JSON parsing) for signature verification. Parsing and re-serializing may change whitespace and invalidate the HMAC.


Enabling and disabling webhooks

In the Console, go to Settings > Integrations > Webhooks and toggle the enabled state on the webhook row. Disabled webhooks receive no deliveries.


Connecting webhooks to alert rules

Alert rules can route to a webhook destination. When creating or updating an alert rule, set the response_action to "webhook" or "webhook_and_investigate" and provide the response_webhook_id. The "webhook_and_investigate" action delivers the alert to the webhook and simultaneously creates an investigation in the Console.

Valid response_action values: none, webhook, investigate, webhook_and_investigate.


Monitoring delivery health

The webhook row in Settings > Integrations > Webhooks shows delivery health fields:

FieldDescription
last_delivery_atTimestamp of the most recent delivery attempt
last_delivery_statusHTTP status code returned by the endpoint
last_delivery_errorError message if the delivery failed (null on success)

If last_delivery_error is set and last_delivery_status indicates failure, investigate the endpoint's availability and response behavior. Use the test button to re-verify connectivity after resolving the issue.


Operational guidance

Use raw body bytes for signature verification: Many web frameworks parse JSON before the route handler runs and do not expose the original bytes. Buffer the raw body before parsing if you need to verify signatures. The HMAC is computed over the exact bytes sent by the Console, not over a re-serialized JSON object.

Return 2xx quickly: The Console webhook delivery timeout is 10 seconds. If downstream processing takes longer, acknowledge the delivery immediately (HTTP 204) and process the payload asynchronously. Slow endpoints will accumulate delivery failures.

Use the test button before wiring to paging: Always test a new webhook using the test button before connecting it to alert rules that trigger paging. Verify both that the payload arrives and that the signature validates correctly.

Slack and Teams types: When using slack or teams webhook types, the Console formats the payload according to the platform's Incoming Webhook specification. If you configure a signing secret, the Console still applies the X-Telovix-Signature header in the same way.


Further reading

Released under the Telovix Commercial License.