API-Cookbook¶
Praktische Snippets für häufige Aufgaben.
1. Host anlegen + Agent-Token generieren¶
JWT="eyJhbGc..."
BASE="https://deine-domain.tld/api/v1"
# Host anlegen ("hostname" ist das Pflichtfeld, nicht "name" —
# der Worker korreliert Check-Ergebnisse über (tenant_id, hostname))
HOST=$(curl -s -X POST "$BASE/hosts/" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"hostname": "web03.acme.local",
"tenant_id": "uuid-of-tenant",
"profile_id": "uuid-of-linux-profile",
"ip_address": "10.10.5.13",
"monitoring_mode": "agent",
"tags": ["production", "web"]
}')
HOST_ID=$(echo "$HOST" | jq -r .id)
# Agent-Token generieren
TOKEN=$(curl -s -X POST "$BASE/hosts/$HOST_ID/agent-token" \
-H "Authorization: Bearer $JWT" | jq -r .token)
# Agent installieren
ssh root@web03.acme.local \
"wget -qO- https://deine-domain.tld/agent/install.sh | bash -s -- $TOKEN https://deine-domain.tld"
import requests
BASE = "https://deine-domain.tld/api/v1"
HEADERS = {"Authorization": f"Bearer {JWT}"}
# Host anlegen
r = requests.post(f"{BASE}/hosts/", json={
"hostname": "web03.acme.local",
"tenant_id": tenant_id,
"profile_id": linux_profile_id,
"ip_address": "10.10.5.13",
"monitoring_mode": "agent",
"tags": ["production", "web"],
}, headers=HEADERS)
host = r.json()
# Agent-Token
token = requests.post(
f"{BASE}/hosts/{host['id']}/agent-token",
headers=HEADERS,
).json()["token"]
print("Token:", token)
Die Antwort auf POST /hosts/ enthält zusätzlich skipped_checks: Checks, die
das gewählte profile_id mitbringen würde, aber wegen des Modus nicht
angelegt werden konnten (z. B. Agent-Check ohne monitoring_mode: "agent") —
nie stiller Verlust, immer im Body sichtbar.
Statt eines lokalen profile_id akzeptiert der Endpoint auch community_id
(ID eines Profils im Community-Hub, siehe Community Hub):
der Server importiert es bei Bedarf automatisch und bindet den Host daran.
2. Bulk-Import aus CSV¶
import csv, requests
with open("hosts.csv") as f:
for row in csv.DictReader(f):
requests.post(f"{BASE}/hosts/", json={
"hostname": row["hostname"],
"tenant_id": row["tenant_id"],
"profile_id": row["profile_id"],
"ip_address": row["ip"],
}, headers=HEADERS)
3. Service zu Host hinzufügen¶
curl -X POST "$BASE/host-services/" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"host_id": "host-uuid",
"tenant_id": "tenant-uuid",
"profile_check_id": "profile-check-uuid",
"display_name": "Disk /var",
"config_overrides": { "path": "/var" },
"interval_override": 60
}'
profile_check_id (aus einem Geräteprofil) und check_type (freier Check
ohne Profil, „Inline-Check" mit config_overrides als komplette Check-Config)
schließen sich gegenseitig aus — genau eines von beiden angeben.
4. Custom Dashboard programmatisch anlegen¶
dashboard = requests.post(f"{BASE}/dashboards/", json={
"tenant_id": tenant_id,
"title": "Acme NOC",
"config": {
"schemaVersion": 1,
"timeSettings": { "from": "now-24h", "to": "now", "refreshInterval": 30 },
"widgets": {
"w1": {
"type": "status_overview",
"title": "Status-Übersicht",
"dataSource": { "type": "summary", "tenant_ids": [tenant_id] },
"options": {}
},
"w2": {
"type": "table",
"title": "Aktive Probleme",
"dataSource": { "type": "status_table", "tenant_ids": [tenant_id] },
"options": {}
}
},
"layout": {
"lg": [
{ "i": "w1", "x": 0, "y": 0, "w": 12, "h": 4 },
{ "i": "w2", "x": 0, "y": 4, "w": 12, "h": 8 }
]
}
}
}, headers=HEADERS).json()
Verfügbare Widget-Typen (stat, gauge, line_chart, table,
status_overview, pie_chart, bar_chart, top_n, heatmap,
log_stream, anomaly_list, prediction_list, check_history,
status_timeline, text) siehe Widget-Auswahl beim Dashboard-Bau in der
Web-App — die API übernimmt exakt dieselbe config-Struktur, die das Frontend
schreibt.
5. Bulk-Tag-Update¶
hosts = requests.get(f"{BASE}/hosts/?tag=legacy", headers=HEADERS).json()
for h in hosts["items"]:
new_tags = [t for t in h["tags"] if t != "legacy"] + ["deprecated"]
requests.patch(f"{BASE}/hosts/{h['id']}", json={"tags": new_tags}, headers=HEADERS)
6. Eigenes Webhook-Empfänger validieren¶
import hmac, hashlib, json
from flask import Flask, request
WEBHOOK_SECRET = "<secret aus channel-config>"
app = Flask(__name__)
@app.route("/vesana-webhook", methods=["POST"])
def receive():
body = request.get_data()
sig = request.headers.get("X-Vesana-Signature", "")
expected = "sha256=" + hmac.new(
WEBHOOK_SECRET.encode(), body, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(sig, expected):
return "bad sig", 401
payload = json.loads(body)
if payload["status"] == "CRITICAL":
send_pager(payload["host"]["name"], payload["service"]["display_name"])
return "ok", 200
7. SLA-Report ziehen¶
curl "$BASE/tenants/acme-uuid/sla-report?from=2026-04-01&to=2026-04-30" \
-H "Authorization: Bearer $JWT" \
| jq '.'
8. Wartungsfenster setzen + auflösen¶
# Wartung für einen Host planen
curl -X POST "$BASE/downtimes/" \
-H "Authorization: Bearer $JWT" \
-d '{
"host_id": "host-uuid",
"start_at": "2026-04-30T22:00:00Z",
"end_at": "2026-04-30T23:30:00Z",
"comment": "Kernel-Update"
}'
# Wiederkehrend (RRULE) statt einmalig: zusätzlich "recurrence" setzen,
# z. B. "FREQ=WEEKLY;BYDAY=MO,WE;UNTIL=20260801T220000Z"
# Für mehrere Checks auf einmal: POST $BASE/downtimes/bulk
# mit { "service_ids": [...], "start_at": ..., "end_at": ... }
# Vorzeitig beenden
curl -X DELETE "$BASE/downtimes/<id>" \
-H "Authorization: Bearer $JWT"
9. AI-Service-Analyse abrufen¶
10. Audit-Export für Compliance¶
curl "$BASE/audit-log/export?from=2026-04-01&format=csv" \
-H "Authorization: Bearer $JWT" \
> audit-april.csv