Alert Monitoring

Updated

This recipe shows how to build a complete alert monitoring system: create subscriptions for different alert types, stream triggered events in real-time, and receive push notifications via webhooks with signature verification.

[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop

Full Example

alert-monitoring.ts
import { Chaos } from '@chaoslabs/ai-sdk';
 
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
 
// Step 1: Create a price alert
const priceAlert = await chaos.alerts.subscriptions.create({
  alert: {
    alert_type: 'price_change',
    asset: 'ETH',
    target_price: 3000,
    condition: 'below',
  },
});
console.log(`Created alert: ${priceAlert.id} (${priceAlert.name})`);
 
// Step 2: Create a whale watch alert with webhook delivery
const whaleAlert = await chaos.alerts.subscriptions.create({
  alert: {
    alert_type: 'whale_watch',
    chain: 'ethereum',
    min_balance: 1_000_000,
    profit_type: 'realized',
  },
  webhook: {
    url: 'https://your-api.com/alerts/webhook',
    secret: 'your-hmac-secret',
  },
});
 
// Step 3: Stream alerts in real-time
const stream = chaos.alerts.connect();
 
stream.on('alert', (event) => {
  console.log(`[${event.severity}] ${event.title}`);
  console.log(`Summary: ${event.summary}`);
 
  // Access evidence data
  for (const point of event.evidence.dataPoints) {
    console.log(`  ${point.label}: ${point.value}${point.unit ?? ''}`);
  }
});
 
stream.on('connected', () => console.log('Listening for alerts...'));
stream.on('error', (err) => console.error('Stream error:', err));
 
// Step 4: Poll inbox for any missed alerts
const { events } = await chaos.alerts.inbox.list({
  readState: 'unread',
  severity: ['warning', 'critical'],
});
 
for (const event of events) {
  console.log(`Missed: ${event.title} (${event.triggeredAt})`);
  await chaos.alerts.inbox.markRead(event.id);
}

Step-by-Step Breakdown

1. Create Alerts from Templates

Browse available templates and create alerts from them instead of building configs manually.

from-templates.ts
// Browse available templates
const { templates } = await chaos.alerts.templates.list();
 
for (const t of templates) {
  console.log(`${t.name} (${t.category}): ${t.description}`);
  console.log(`  Required: ${t.requiredParams.map((p) => p.key).join(', ')}`);
}
 
// Find a specific template
const priceTemplates = await chaos.alerts.templates.list(undefined, 'price');

2. Create Alerts from Natural Language

Let the AI parse a plain-English alert description into a typed subscription.

from-natural-language.ts
const result = await chaos.alerts.fromQuery({
  query: 'Alert me when ETH drops 10% in a day',
  userId: 'user-123',
});
 
switch (result.mode) {
  case 'created':
    console.log('Alert created:', result.alert?.name);
    break;
  case 'interactive':
    console.log('Needs clarification — show options to user');
    break;
  case 'form':
    console.log('Needs more info — show form to user');
    break;
  case 'error':
    console.error('Failed:', result.error);
    break;
}

3. Manage Alert Lifecycle

Snooze, mute, update, and clean up alerts.

lifecycle.ts
// List all active subscriptions
const subs = await chaos.alerts.subscriptions.list();
console.log(`${subs.length} active alerts`);
 
// Snooze an alert for 1 day
await chaos.alerts.subscriptions.snooze(subs[0].id, '1d');
 
// Mute indefinitely
await chaos.alerts.subscriptions.mute(subs[0].id);
 
// Update channels — add email delivery
await chaos.alerts.subscriptions.update(subs[0].id, {
  channels: { inApp: true, push: true, telegram: false, email: true },
});
 
// Check trigger history for a subscription
const { events, total } = await chaos.alerts.subscriptions.getEvents(subs[0].id);
console.log(`Fired ${total} times`);
 
// Delete an alert
await chaos.alerts.subscriptions.delete(subs[0].id);

4. Webhook Signature Verification

When Chaos delivers alerts to your webhook, each request includes an X-Chaos-Signature header containing an HMAC-SHA256 signature of the request body, signed with the secret you provided when creating the subscription.

webhook-server.ts
import { createHmac, timingSafeEqual } from 'crypto';
import express from 'express';
 
const WEBHOOK_SECRET = 'your-hmac-secret';
const app = express();
 
app.post('/alerts/webhook', express.text({ type: '*/*' }), (req, res) => {
  const signature = req.headers['x-chaos-signature'] as string;
  const expected = createHmac('sha256', WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex');
 
  if (!timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send('Invalid signature');
  }
 
  const alert = JSON.parse(req.body);
  console.log(`[${alert.severity}] ${alert.title}`);
  console.log(`Summary: ${alert.summary}`);
 
  res.status(200).send('OK');
});
 
app.listen(3000, () => console.log('Webhook server on :3000'));
webhook_server.py
import hmac
import hashlib
import json
from flask import Flask, request, abort
 
WEBHOOK_SECRET = "your-hmac-secret"
app = Flask(__name__)
 
@app.route("/alerts/webhook", methods=["POST"])
def handle_alert():
    signature = request.headers.get("X-Chaos-Signature", "")
    expected = hmac.new(
        WEBHOOK_SECRET.encode(), request.data, hashlib.sha256
    ).hexdigest()
 
    if not hmac.compare_digest(signature, expected):
        abort(401, "Invalid signature")
 
    alert = json.loads(request.data)
    print(f"[{alert['severity']}] {alert['title']}")
    print(f"Summary: {alert['summary']}")
    return "OK", 200
[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop

5. Configure Notification Settings

Set up global notification preferences including Do Not Disturb hours and severity-based channel routing.

settings.ts
// Set up DND hours and severity routing
await chaos.alerts.settings.update({
  channels: { inApp: true, push: true, telegram: true, email: false },
  dnd: {
    enabled: true,
    startTime: '22:00',
    endTime: '08:00',
    timezone: 'America/New_York',
  },
});
 
// Check current settings
const settings = await chaos.alerts.settings.get();
console.log('DND:', settings.dnd?.enabled ? 'on' : 'off');
console.log('Channels:', settings.channels);
[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop
Was this helpful?