Connect AstraNetmon with Slack, Discord, Microsoft Teams, and other services using webhooks
Webhooks allow you to receive real-time notifications when events occur in your network monitoring. Send alerts to Slack, Discord, Microsoft Teams, PagerDuty, or any custom HTTP endpoint.
Webhooks are configured from Dashboard → Settings → Alerts
Triggered when an agent goes online or offline
Triggered when a new agent registers
Triggered when a speed test finishes
Triggered when a traceroute finishes
Triggered when a service test fails
Triggered when a threshold alert fires
All webhooks receive a JSON payload:
{
"event": "agent.status_changed",
"timestamp": "2025-12-17T10:30:00Z",
"data": {
"agent_id": "agent-123",
"hostname": "server-01",
"previous_status": "online",
"current_status": "offline",
"tenant_id": "tenant-abc"
}
}The data object structure varies based on the event type.
When you enable a webhook secret, AstraNetmon signs each request with an HMAC-SHA256 signature in the X-Webhook-Signature header.
const crypto = require('crypto');
function verifySignature(body, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(body))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
app.post('/webhook', (req, res) => {
const signature = req.headers['x-webhook-signature'];
if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook...
res.json({ status: 'received' });
});import hmac
import hashlib
import json
def verify_signature(request_data, signature, secret):
expected_signature = hmac.new(
secret.encode(),
request_data,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)
@app.route('/webhook', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-Webhook-Signature')
if not verify_signature(request.data, signature, WEBHOOK_SECRET):
return jsonify({'error': 'Invalid signature'}), 401
# Process webhook...
return jsonify({'status': 'received'}), 200To send alerts to Slack, you'll need a transformation middleware since Slack expects a different format. See our webhook examples repository for ready-to-use middleware.
For detailed Slack integration instructions, see the WEBHOOK_TEMPLATES.md file in the project repository.
Similar to Slack, Discord requires message transformation. Example middleware:
// discord-webhook-transformer.js
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
const DISCORD_WEBHOOK_URL = 'YOUR_DISCORD_WEBHOOK_URL';
app.post('/webhook/discord', async (req, res) => {
const { event, timestamp, data } = req.body;
if (event === 'agent.status_changed') {
const isOffline = data.current_status === 'offline';
await axios.post(DISCORD_WEBHOOK_URL, {
username: 'AstraNetmon',
embeds: [{
title: `${isOffline ? '🔴' : '🟢'} Agent Status Changed`,
color: isOffline ? 0xdc2626 : 0x16a34a,
fields: [
{ name: 'Agent', value: data.hostname, inline: true },
{ name: 'Status', value: data.current_status.toUpperCase(), inline: true }
],
timestamp: timestamp
}]
});
}
res.status(200).send('OK');
});
app.listen(3000);Teams uses MessageCard format for incoming webhooks:
app.post('/webhook/teams', async (req, res) => {
const { event, timestamp, data } = req.body;
if (event === 'agent.status_changed') {
const isOffline = data.current_status === 'offline';
await axios.post(TEAMS_WEBHOOK_URL, {
'@type': 'MessageCard',
'@context': 'https://schema.org/extensions',
summary: `Agent ${data.hostname} is ${data.current_status}`,
themeColor: isOffline ? 'dc2626' : '16a34a',
sections: [{
activityTitle: `${isOffline ? '🔴' : '🟢'} Agent Status Changed`,
facts: [
{ name: 'Agent:', value: data.hostname },
{ name: 'Status:', value: data.current_status.toUpperCase() }
]
}]
});
}
res.status(200).send('OK');
});For custom endpoints, you can receive webhooks directly:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def handle_webhook():
payload = request.json
event = payload.get('event')
data = payload.get('data')
if event == 'agent.status_changed':
if data.get('current_status') == 'offline':
# Send alert, create ticket, etc.
print(f"ALERT: {data['hostname']} is offline!")
return jsonify({'status': 'received'}), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)Test your webhook endpoints before deploying: