Subscribe to alerts
This document describes the MQTT messaging interface for the Angible Edge Backend service.
Table of Contents
Connection Information
MQTT Broker
| Parameter | Value |
|---|---|
| Host | The AI Box's IP address on your store network |
| Port | 1883 |
| Protocol | MQTT v3.1.1 |
| TLS | Disabled |
| QoS | 0 |
| Client ID | Your sco_id |
Topic Structure
Available Topic List (AI Box -> SCOs)
The transaction event scan-completed triggers the AI to review the transaction, you can expect a message on exactly one of these two topics after sending out the request.
| Topic | Description |
|---|---|
angible/v1/events/{sco_id}/alerts | AI alert events for an SCO |
angible/v1/events/{sco_id}/no-alert | No alert events for an SCO |
Message Schema
AI Alerts
Topic: angible/v1/events/{sco_id}/alerts
Format: JSON
The most useful thing in this payload is the image — enough to show staff or the customer what the AI flagged. For your resolution popup, use issue_items[].image_path — fetch it with Get an image, passing your session token header. (additional_info.image_urls is a separate, older field kept for compatibility with a previous alert format — see the field tables below; don't treat it as an equivalent substitute for issue_items[].image_path.) The rest of the fields mostly just help you match the alert back to your own transaction records.
If you'd rather not make a separate call per image, we can instead embed it directly in this payload as base64 — ask us to enable base64 image embedding, which adds image_base64 (and scanned_image_base64, images_base64) alongside the path fields, no extra API call needed.
Schema
{
"alert_id": "555499d2-f8d9-49f3-ada8-434901657976",
"alert_type": "Item Left",
"transaction_id": "6ae1a7e792f350bcfcdc0ca8",
"sco_transaction_id": "txn-987654",
"description": "Alert: item_left",
"severity": "high",
"timestamp": 1742355063000,
"video_url": null,
"issue_items": [
{
"item_id": "123",
"item_name": null,
"image_path": "/v1/images/sco_popup_850228_0_3699.jpg",
"timestamp": 1742355063000,
"scanned_item_id": null,
"scanned_item_name": null,
"scanned_image_path": null
}
],
"sco_id": "SCO_ID_1",
"sco_name": "Self-Checkout 1",
"additional_info": {
"camera_id": "camera_1",
"image_urls": ["/v1/images/alert_850228_0_3699.jpg"],
"video_url": null
}
}
Field Definitions
| Field | Type | Description |
|---|---|---|
alert_id | string | Unique identifier for the alert |
alert_type | string | Type of alert, as a display label (e.g., Item Left) — not a fixed enum, so don't match on exact casing |
transaction_id | string | Internal transaction identifier |
sco_transaction_id | string | null | Transaction identifier assigned by the SCO. null if the matching transaction record could no longer be found when the alert was published (e.g. reset or expired) |
description | string | Human-readable explanation of the alert |
severity | string | Always high today; the field exists for future differentiation |
timestamp | integer | Timestamp in milliseconds since the Unix epoch |
video_url | string | null | For older integrations only. Always null for new integrations |
issue_items | array | List of items that triggered the alert |
sco_id | string | Identifier of the SCO |
sco_name | string | Display name of the SCO |
additional_info | object | null | Camera/media context for the alert |
Issue Item Object
| Field | Type | Description |
|---|---|---|
item_id | string | An AI-tracking ID for this flagged item. Not the same item_id you sent via item-added — treat it as an opaque token and echo it back as-is when reporting the resolution (Update Alert) |
item_name | string | null | Name of the item |
image_path | string | The image to show in your resolution popup for this item. Uses the AI's zoomed-in popup crop when available; falls back to the original (un-cropped) image if no crop was captured |
image_base64 | string | null | Base64-encoded item image. Omitted when not enabled |
timestamp | integer | Timestamp in milliseconds since the Unix epoch |
scanned_item_id | string | null | Reserved for a future feature. Always null for now |
scanned_item_name | string | null | Reserved for a future feature. Always null for now |
scanned_image_path | string | null | Reserved for a future feature. Always null for now |
scanned_image_base64 | string | null | Reserved for a future feature. Always omitted for now |
Note: The
scanned_*fields above are reserved for a feature that isn't available yet — no need to handle them differently fromnull/absent today.
Additional Info Object
| Field | Type | Description |
|---|---|---|
camera_id | string | Identifier of the camera that captured the event |
image_urls | array of string | null | Kept for compatibility with an older alert format; has no item ID of its own. Same order as issue_items, but always the original (un-cropped) image, never the popup crop. Use issue_items[].image_path for your resolution popup instead — don't treat this as an equivalent |
video_url | string | null | For older integrations only. Always null for new integrations |
images_base64 | array of string | null | List of base64-encoded images. Omitted when not enabled |
Note:
image_base64andimages_base64are only present when base64 image embedding is enabled in the edge settings; otherwise they are omitted from the payload.
No Alert
Topic: angible/v1/events/{sco_id}/no-alert
Format: JSON
Schema
{
"transaction_id": "txn-123456",
"sco_transaction_id": "sco-txn-987654",
"timestamp": 1742355063000
}
Field Definitions
| Field | Type | Description |
|---|---|---|
transaction_id | string | Unique identifier for the transaction |
sco_transaction_id | string | null | Transaction identifier assigned by the SCO |
timestamp | integer | Timestamp in milliseconds since the Unix epoch |
Python Example
This section demonstrates how to connect to the MQTT broker and subscribe to alert events using the paho-mqtt library.
Prerequisites
- Python 3.11 or higher
paho-mqttlibrary
Subscriber Example
import json
import paho.mqtt.client as mqtt
# Configuration
MQTT_HOST = "x.x.x.x" # Replace with the AI Box's IP address on your store network
MQTT_PORT = 1883 # Default MQTT port
SCO_ID = "SCO_ID_1" # Your SCO device ID
CLIENT_ID = SCO_ID # Use your sco_id as the client ID
TOPIC = f"angible/v1/events/{SCO_ID}/alerts" # Subscribe to alerts for your SCO
def on_connect(client, userdata, flags, rc, properties=None):
if rc == 0:
client.subscribe(TOPIC, qos=0)
def on_message(client, userdata, msg):
payload = json.loads(msg.payload.decode("utf-8"))
# Process the alert payload here
def on_disconnect(client, userdata, rc, properties=None):
pass
def main():
client = mqtt.Client(
client_id=CLIENT_ID,
protocol=mqtt.MQTTv311,
callback_api_version=mqtt.CallbackAPIVersion.VERSION2,
)
client.on_connect = on_connect
client.on_message = on_message
client.on_disconnect = on_disconnect
client.connect(MQTT_HOST, MQTT_PORT, keepalive=60)
client.loop_forever()
if __name__ == "__main__":
main()