Docs / Monitoring
Alerts and webhooks
What raises an alert, how alerts are grouped, and how to send them to email, Telegram, Slack or Teams and signed webhooks, with the payload and signature check.
XiroLink tells you when something needs attention: a maker down or silent, a symbol without prices, a taker that will not start, blocked IPs and failed sign-ins. Alerts appear in the dashboard and can go to email, Telegram, Slack or Teams, and your own systems by webhook.
In the dashboard
The Alerts page lists every alert with its severity, type and when it was last seen, under Open, Critical, Unread and All. Acknowledge all clears them for everyone. The bell opens the latest, warnings and critical alerts also pop up, and you can turn on desktop notifications per browser.
What raises an alert
| Alert | Severity |
|---|---|
| A maker disconnected, after 30 seconds down | Critical |
| A maker is connected but silent | Warning |
| An LP rejected some symbols | Warning |
| No prices for a symbol | Critical |
| A symbol moved to a backup maker | Warning |
| Back on the main maker, prices back, maker recovered | Info |
| A taker could not start | Critical |
| An IP was blocked automatically | Warning |
| Repeated failed sign-ins | Warning |
Under Settings → Alerts you can also turn on checks for taker disconnects, high price latency and buffer overflow, with their thresholds, how often to check and a cooldown.
Fewer, better alerts
- A repeat of the same alert within a short window updates the existing one, with a count, instead of sending again.
- One silent LP raises one alert, not one per symbol. Stale symbols are grouped into one alert that names them.
- Closed markets raise no stale or silent alerts.
- Nothing is sent in the first 90 seconds after the bridge starts.
Channels
Set channels up under Settings → Notifications. Each channel has its own switch, a minimum severity (Info and above, Warning and above or Critical only) and Send test.
| Channel | Set up |
|---|---|
| Alerts go to the Admin address under Settings → Email | |
| Telegram | A Bot token and Chat ID. Create a bot with @BotFather, add it to your group, then use the group's chat ID. |
| Slack / Teams | An Incoming webhook URL that accepts a text message: Slack, Mattermost, Discord's Slack URL or a Teams workflow |
| Webhook | An Endpoint URL and an optional Signing secret, for your own systems |
Channel secrets are stored encrypted, and changes to channels are recorded in the audit log.
Webhooks
Each alert is sent as a POST with a JSON body:
{
"instance": "My Bridge",
"sent_at": 1762156800,
"notification": {
"id": 42,
"kind": "maker_down",
"severity": "critical",
"title": "Maker LP1 disconnected",
"body": "Down for over 30s (error). The bridge will keep reconnecting.",
"entity_type": "maker",
"entity_id": "3",
"count": 1,
"created_at": "2026-11-03T08:00:00",
"updated_at": "2026-11-03T08:00:00",
"acknowledged_at": null,
"acknowledged_by": null
}
}| Field | Contents |
|---|---|
instance |
Your bridge's name |
sent_at |
When it was sent, Unix seconds |
kind, severity |
What happened, and info, warning or critical |
title, body |
The alert as shown in the dashboard |
entity_type, entity_id |
What it is about, such as a maker |
count |
How many times it has happened in its window |
created_at, updated_at |
UTC times |
Send test sends a notification with "kind": "test".
Verify the signature
With a Signing secret set, every request carries:
X-Bridge-Signature: sha256=<hex digest>The digest is HMAC-SHA256 of the raw request body with your secret. Compute it over the exact bytes you received and compare in constant time:
import hashlib, hmac
def is_valid(body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header)Use sent_at to reject old requests. Answer with a 2xx status within 8 seconds. Failed deliveries are not retried, so the Alerts page stays the record of everything that happened.
Something unclear or out of date? Email [email protected].