Appearance
Alerts
How alerts are generated
Alerts originate on the device itself — firmware detects a fault or security-relevant condition (AC power loss, a power meter going offline, the local web-config AP being activated, and similar) and publishes an alert message. From there:
Device
│ Detects fault/warning condition
│ MQTT publish to /cbox/{deviceId}/alerts
▼
AWS IoT Core
│ IoT Rule (writes directly to DynamoDB — no Lambda in this path)
▼
DynamoDB
│ DynamoDB Stream
▼
Lambda (DynamoDB-to-AppSync)
│ GraphQL mutation
▼
AppSync ── WebSocket ──▶ Your application (real-time alert display)An alert also sets hasAlerts: true in the device's regular status packet, and active alerts (state alert or warning) are summarised inline in an alerts object within the heartbeat — so a client watching only the status stream still knows something is wrong, even before/without consuming the alerts topic directly.
Alert payload structure
Fault alert example (AC power loss, critical):
json
{
"deviceId": "CBOX-00001",
"time": "2024-01-15T14:30:45.123Z",
"timeU": 1705329045,
"uptime": 782,
"alert_timestamp": 782,
"alert_id": "AC_POWER_LOSS",
"instance_id": "AC_POWER_LOSS_782",
"priority": "critical",
"state": "alert",
"message": "Lost AC Power Input",
"details": {
"voltage": 45.2,
"meter_type": "internal",
"threshold_low": 50,
"threshold_high": 60
},
"resend_count": 0
}Warning alert example (AP activated — security-relevant, not a fault):
json
{
"deviceId": "CBOX-00001",
"time": "2026-02-24T10:30:00.000Z",
"timeU": 1771933800,
"uptime": 355,
"alert_timestamp": 355,
"alert_id": "AP_ACTIVATED",
"instance_id": "AP_ACTIVATED_355",
"priority": "medium",
"state": "warning",
"message": "AP web server activated",
"details": { "client_count": 0 },
"resend_count": 0
}Fields
| Field | Description |
|---|---|
alert_id | Alert type identifier — see table below |
instance_id | Unique ID for this specific occurrence, format {ALERT_ID}_{device_uptime} |
priority | critical | high | medium | low |
state | Alert lifecycle state — see below |
message | Human-readable description |
details | Alert-type-specific data (varies by alert_id) |
resend_count | Increments each time an unacknowledged alert is resent |
Alert types
alert_id | Priority | Trigger |
|---|---|---|
AC_POWER_LOSS | critical | AC voltage drops below 50V (clears above 60V) |
DC_POWER_LOSS | critical | 12VDC input fault |
EXTERNAL_METER_LOSS | high | External power meter communication lost |
AP_ACTIVATED | medium | Local web-config AP activated (security-relevant, not a fault) |
CERT_AUTH_FAILURE | high | Device re-provisioned after sustained certificate authentication failure (cloud-raised, not device-raised) |
Alert states
| State | Meaning |
|---|---|
alert | Active fault condition |
warning | Active, non-fault, security/informational condition |
alert_cleared | The fault or warning condition has resolved |
inactive | Dormant / no longer relevant |
Resend behaviour
Unacknowledged alerts are resent automatically until acknowledged:
| Priority | Resend interval |
|---|---|
| critical | Every 60 seconds |
| high / medium / low | Every 300 seconds |
Consuming alerts
If you're integrating through the platform's GraphQL API (the supported path for most integrations — see Authentication & Access), subscribe to alert updates rather than the raw MQTT topic:
graphql
subscription OnOrganizationAlerts($organizationId: String!) {
onOrganizationAlerts(organizationId: $organizationId) {
deviceId
organizationId
instance_id
code
priority # CRITICAL | HIGH | MEDIUM | LOW
state # FAULTING | FAULT_CLEARED | DELETED
message
timestamp
faultedAt
clearedAt
acknowledgedAt
}
}Use onOrganizationAlerts to receive every alert across all devices you have visibility of; use onAlertUpdate(deviceId: ...) to scope to a single device. Note that the API surfaces uppercase enum values (FAULTING, FAULT_CLEARED, CRITICAL, HIGH, …) and the field name code, where the raw MQTT/DynamoDB representation documented above uses lowercase strings (alert, alert_cleared, critical) and the field name alert_id. Use the API's field names and enum values when consuming through the API — do not assume the two representations are interchangeable.
If you're subscribing to raw MQTT (device-protocol integrations only — see Authentication & Access), subscribe to /cbox/{DEVICE_ID}/alerts and consume the payloads exactly as documented above.
Acknowledging an alert stops the automatic resend. This is sent as a device command (acknowledge_alert with the alert's instance_id) — via publishDeviceCommand if you're on the API, or directly to /cbox/{DEVICE_ID}/command if you have MQTT access.