Skip to main content

Notifications

Nekzus provides a comprehensive notification system for pushing real-time alerts and messages to connected devices. The system supports both immediate delivery via WebSocket and queued delivery for offline devices.


Overview

The notifications system enables:

  • Real-time delivery - Instant WebSocket notifications to connected clients
  • Offline queuing - Automatic queueing for devices that are not currently connected
  • Targeted delivery - Send notifications to specific devices or broadcast to all
  • Activity persistence - Activity notifications are stored in the activity log
  • Queue management - Web UI and API for managing pending notifications
  • Retry mechanism - Automatic and manual retry for failed deliveries

Architecture

Notification Flow

d2

Components

ComponentDescription
Webhook EndpointsHTTP endpoints for external integrations
WebSocket ManagerManages real-time connections and message delivery
Notification QueueSQLite-backed queue for offline device notifications
Activity TrackerPersists activity events for the dashboard

Webhook Endpoints

POST /api/v1/webhooks/activity

Creates an activity event that is displayed in the activity feed and optionally sent to devices.

Authentication: API Key or JWT

FieldTypeRequiredDescription
messagestringYesThe notification message
iconstringNoIcon name (default: "Bell")
iconClassstringNoIcon style: success, warning, danger, info
detailsstringNoAdditional details
deviceIdsarrayNoTarget device IDs (empty = broadcast to all)
curl -X POST https://localhost:8443/api/v1/webhooks/activity \
-H "X-API-Key: nekzus_abc123..." \
-H "Content-Type: application/json" \
-d '{
"message": "Deployment completed",
"icon": "CheckCircle",
"iconClass": "success",
"details": "Version 2.0.0 deployed to production",
"deviceIds": ["device-abc123"]
}'

Behavior:

  • Creates an ActivityEvent with type webhook.activity
  • Persists the event to the activity tracker (visible in dashboard)
  • Broadcasts via WebSocket to all connected clients (if no deviceIds specified)
  • For targeted delivery, sends only to specified devices
  • Queues notifications for offline devices (30-day TTL, 5 max retries)

POST /api/v1/webhooks/notify

Sends an arbitrary notification payload via WebSocket without persisting to the activity log.

Authentication: API Key or JWT

FieldTypeRequiredDescription
typestringNoCustom notification type
dataobjectNoArbitrary JSON payload
deviceIdsarrayNoTarget device IDs (empty = broadcast to all)
curl -X POST https://localhost:8443/api/v1/webhooks/notify \
-H "X-API-Key: nekzus_abc123..." \
-H "Content-Type: application/json" \
-d '{
"type": "custom_alert",
"data": {
"alertType": "cpu_usage",
"threshold": 90,
"current": 95,
"message": "CPU usage critical"
},
"deviceIds": ["device-abc123", "device-def456"]
}'

Behavior:

  • Sends the payload directly via WebSocket (not persisted to activity log)
  • Supports broadcast (empty deviceIds) or targeted delivery
  • Queues notifications for offline devices when deviceIds is specified

Notification Queue Management

The notification queue stores pending notifications for offline devices. These endpoints allow administrators to view, retry, and dismiss queued notifications.

GET /api/v1/notifications

Lists notifications with optional filtering and pagination.

Authentication: IP-based (local) or JWT

ParameterTypeDefaultDescription
statusquery-Filter: pending, delivered, failed, dismissed
device_idquery-Filter by device ID
typequery-Filter by notification type
limitquery50Max results (max: 200)
offsetquery0Pagination offset
curl "https://localhost:8443/api/v1/notifications?status=pending&limit=10"

GET /api/v1/notifications/stats

Returns queue statistics.

Authentication: IP-based (local) or JWT

curl https://localhost:8443/api/v1/notifications/stats

GET /api/v1/notifications/stale

Returns stale notifications grouped by device. A notification is considered stale if it has been pending for more than 24 hours.

Authentication: IP-based (local) or JWT

curl https://localhost:8443/api/v1/notifications/stale

DELETE /api/v1/notifications/{id}

Dismisses a single notification. The notification is marked as dismissed and will not be delivered.

Authentication: IP-based (local) or JWT

curl -X DELETE https://localhost:8443/api/v1/notifications/123

DELETE /api/v1/notifications/device/{deviceId}

Dismisses all pending notifications for a specific device.

Authentication: IP-based (local) or JWT

curl -X DELETE https://localhost:8443/api/v1/notifications/device/device-abc123

POST /api/v1/notifications/{id}/retry

Resets a notification status to pending for retry delivery.

Authentication: IP-based (local) or JWT

curl -X POST https://localhost:8443/api/v1/notifications/123/retry

POST /api/v1/notifications/retry

Bulk retry multiple notifications.

Authentication: IP-based (local) or JWT

curl -X POST https://localhost:8443/api/v1/notifications/retry \
-H "Content-Type: application/json" \
-d '{"ids": [123, 124, 125]}'

DELETE /api/v1/notifications/delivered

Clears all delivered notifications from the queue. This is useful for cleanup after confirming notifications were received.

Authentication: IP-based (local) or JWT

curl -X DELETE https://localhost:8443/api/v1/notifications/delivered

WebSocket Message Types

Notifications are delivered via WebSocket using the following message structure:

Activity Notification (from webhook/activity)

{
"type": "webhook",
"data": {
"id": "webhook-1736949720000000",
"type": "webhook.activity",
"icon": "CheckCircle",
"iconClass": "success",
"message": "Deployment completed",
"details": "Version 2.0.0 deployed",
"timestamp": 1736949720000
},
"timestamp": "2025-01-15T10:30:00Z"
}

Custom Notification (from webhook/notify)

{
"type": "webhook",
"data": {
"type": "custom_alert",
"data": {
"alertType": "cpu_usage",
"threshold": 90,
"current": 95,
"message": "CPU usage critical"
},
"deviceIds": ["device-abc123"]
},
"timestamp": "2025-01-15T10:30:00Z"
}

Notification Statuses

StatusDescription
pendingAwaiting delivery to device
deliveredSuccessfully delivered via WebSocket
failedDelivery failed (will retry if retries remain)
dismissedManually dismissed by administrator

Queue Configuration

Notifications are queued with the following default settings:

SettingValueDescription
TTL30 daysTime-to-live for queued notifications
Max Retries5Maximum delivery attempts
Stale Threshold24 hoursTime after which pending notifications are marked stale

Frontend Integration

NotificationsTab Component

The web dashboard includes a NotificationsTab component that provides:

  • Statistics overview - Pending, delivered, and failed counts
  • Stale warning - Alert when devices have notifications pending > 24 hours
  • Status filtering - Filter by pending, delivered, failed, or dismissed
  • Bulk operations - Retry all failed notifications
  • Individual actions - Retry or dismiss specific notifications

Real-time Updates

The frontend subscribes to WebSocket events to receive notifications in real-time:

// Example: Listening for webhook notifications
websocket.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'webhook') {
// Handle activity event
if (message.data.type === 'webhook.activity') {
showActivityNotification(message.data);
}
// Handle custom notification
else if (message.data.type) {
handleCustomNotification(message.data);
}
}
};

Icon Reference

The icon field supports icon names from the Lucide icon library:

IconUse Case
BellDefault notifications
CheckCircleSuccess messages
AlertTriangleWarnings
AlertCircleErrors
InfoInformational
TargetTargeted actions
RadioBroadcast messages
DatabaseStorage/data events
RefreshUpdate notifications

Icon Classes

The iconClass field controls the color styling:

ClassColorUse Case
successGreenSuccessful operations
warningYellow/OrangeWarnings, attention needed
dangerRedErrors, critical alerts
infoBlueInformational messages
(none)DefaultNeutral notifications

Integration Examples

CI/CD Pipeline Notification

Send deployment notifications from your CI/CD pipeline:

# In your deployment script
curl -X POST https://nekzus.local:8443/api/v1/webhooks/activity \
-H "X-API-Key: ${NEKZUS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"message": "Deployment to production completed",
"icon": "CheckCircle",
"iconClass": "success",
"details": "Commit: '"${GIT_SHA}"' | Duration: '"${DEPLOY_TIME}"'s"
}'

Monitoring Alert Integration

Forward alerts from your monitoring system:

# Prometheus Alertmanager webhook receiver
curl -X POST https://nekzus.local:8443/api/v1/webhooks/notify \
-H "X-API-Key: ${NEKZUS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"type": "prometheus_alert",
"data": {
"alertname": "HighCPUUsage",
"severity": "warning",
"instance": "server-01",
"value": 95,
"summary": "CPU usage is above 90%"
}
}'

Backup Completion Notification

Notify specific devices when backups complete:

# Send to specific admin devices
curl -X POST https://nekzus.local:8443/api/v1/webhooks/activity \
-H "X-API-Key: ${NEKZUS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"message": "Daily backup completed successfully",
"icon": "Database",
"iconClass": "success",
"details": "Size: 2.4GB | Duration: 45s",
"deviceIds": ["admin-device-1", "admin-device-2"]
}'

JavaScript/Node.js Example

const axios = require('axios');

async function sendNotification(message, options = {}) {
const payload = {
message,
icon: options.icon || 'Bell',
iconClass: options.iconClass || '',
details: options.details || '',
deviceIds: options.deviceIds || []
};

try {
const response = await axios.post(
'https://nekzus.local:8443/api/v1/webhooks/activity',
payload,
{
headers: {
'X-API-Key': process.env.NEKZUS_API_KEY,
'Content-Type': 'application/json'
}
}
);
console.log('Notification sent:', response.data.eventId);
return response.data;
} catch (error) {
console.error('Failed to send notification:', error.message);
throw error;
}
}

// Usage
sendNotification('Build completed', {
icon: 'CheckCircle',
iconClass: 'success',
details: 'Build #1234 finished in 5m 32s'
});

Python Example

import requests
import os

def send_notification(message, icon='Bell', icon_class='', details='', device_ids=None):
"""Send a notification via Nekzus webhook."""
payload = {
'message': message,
'icon': icon,
'iconClass': icon_class,
'details': details,
'deviceIds': device_ids or []
}

response = requests.post(
'https://nekzus.local:8443/api/v1/webhooks/activity',
json=payload,
headers={
'X-API-Key': os.environ['NEKZUS_API_KEY'],
'Content-Type': 'application/json'
},
verify=False # Set to True in production with proper certs
)

response.raise_for_status()
return response.json()

# Usage
result = send_notification(
message='Task completed',
icon='CheckCircle',
icon_class='success',
details='Processed 1,000 records in 30 seconds'
)
print(f"Event ID: {result['eventId']}")

Go Example

package main

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)

type ActivityPayload struct {
Message string `json:"message"`
Icon string `json:"icon,omitempty"`
IconClass string `json:"iconClass,omitempty"`
Details string `json:"details,omitempty"`
DeviceIDs []string `json:"deviceIds,omitempty"`
}

func sendNotification(payload ActivityPayload) error {
body, err := json.Marshal(payload)
if err != nil {
return err
}

req, err := http.NewRequest(
"POST",
"https://nekzus.local:8443/api/v1/webhooks/activity",
bytes.NewReader(body),
)
if err != nil {
return err
}

req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-Key", os.Getenv("NEKZUS_API_KEY"))

resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status: %d", resp.StatusCode)
}

return nil
}

func main() {
err := sendNotification(ActivityPayload{
Message: "Service restarted",
Icon: "Refresh",
IconClass: "info",
Details: "All services are now running",
})
if err != nil {
fmt.Printf("Error: %v\n", err)
}
}

Troubleshooting

Notifications Not Received

  1. Check WebSocket connection - Ensure the device is connected via WebSocket
  2. Verify device ID - Confirm the deviceIds array contains valid device IDs
  3. Check queue - Use /api/v1/notifications to see if notification is queued
  4. Review logs - Check server logs for delivery errors

Stale Notifications

Stale notifications indicate devices that have been offline for extended periods:

  1. Check if the device is actually offline
  2. Consider dismissing notifications for inactive devices
  3. Review device activity in the Devices tab

Queue Growing

If the notification queue keeps growing:

  1. Identify offline devices with /api/v1/notifications/stale
  2. Dismiss notifications for devices that are no longer active
  3. Consider revoking inactive device access
  4. Review TTL settings if notifications expire too slowly

API Key Authentication Fails

  1. Verify API key is not revoked
  2. Check key has write:* scope
  3. Ensure key is sent in X-API-Key header
  4. Confirm key format: nekzus_<64-character-hex>