Hermes-Webhooks anbinden: Business-Systeme pushen Alerts an Telegram, Discord und Slack


Die meisten Business-Systeme brauchen irgendwann dieselbe Automatisierung: Wenn sich ein Bestellstatus ändert, eine Zahlung erfolgreich ist, ein Monitor anschlägt oder eine CI-Pipeline fertig wird, soll eine Nachricht in einem Team-Kanal landen. Die schnellste erste Version ist meist ein Skript, das eine Datenbank oder API pollt und die Nachricht dann in Telegram, Discord, Slack oder einer anderen Chat-Plattform abwirft.

Polling funktioniert, hat aber echte langfristige Kosten:

  • Latenz und API-Quota. Wenn du jede Minute abfragst, liefern die meisten Requests nichts; ein Wechsel auf Sekunden-Takt multipliziert API-Last und Kosten.
  • Kopplung. Das Business-System wird mit Message-Templates und Chat-Plattform-Tokens hart verdrahtet. Ein Kanal- oder Gruppenwechsel erfordert eine Codeänderung.
  • Erweiterbarkeit. Derselbe Alert muss vielleicht an Telegram, Slack oder erst von einer KI zusammengefasst werden. Polling-Skripte werden schnell komplex.

Hermes Agent bringt eine Webhook-Plattform mit – einen HTTP-Event-Receiver. Dein Business-System POSTet ein Event, Hermes validiert die Signatur, rendert ein Template und pusht die Nachricht an die Chat-Plattform, die du konfiguriert hast. Ist das Event eine reine Benachrichtigung ohne KI-Logik, kannst du den Direct-Delivery-Modus aktivieren: kein LLM-Aufruf, keine Agent-Schleife, Zustellung in unter einer Sekunde und keine Token-Kosten.

Dieser Beitrag ist ein praktischer Leitfaden, um Business-Systeme an Hermes-Webhooks anzubinden: Plattform aktivieren, Routes konfigurieren, drei vollständige Praxis-Szenarien und Security-Härtung.

Zwei Modi: Agent-Verarbeitung vs. Direct Delivery

Hermes-Webhooks unterstützen zwei Zustellpfade. Die richtige Wahl zu treffen, ist entscheidend.

Modus Ruft das LLM auf? Am besten für Latenz Kosten
Agent-Verarbeitung Ja Events, die Verständnis, Zusammenfassung oder eine Entscheidung brauchen, bevor geantwortet oder weitergeleitet wird Sekunden Token-Kosten
Direct Delivery Nein Reine Benachrichtigungen: Bestellungen, Zahlungen, Alerts, CI-Status Unter einer Sekunde Keine LLM-Kosten

Hier steht Direct Delivery im Fokus. Der Ablauf ist einfach:

  1. Das Business-System signiert und POSTet ein JSON-Payload an https://your-server:8644/webhooks/<route-name>.
  2. Hermes validiert die HMAC-Signatur, um zu bestätigen, dass der Absender vertrauenswürdig ist.
  3. Ein Template rendert die JSON-Felder zu einer lesbaren Nachricht.
  4. Die Nachricht wird direkt an Telegram, Discord, Slack, Feishu usw. zugestellt, und Hermes antwortet mit 200 OK.

Es ist kein LLM beteiligt, daher liegen Geschwindigkeit, Kosten und Zuverlässigkeit näher an einem klassischen Message-Gateway – Konfiguration und Erweiterbarkeit bleiben aber so flexibel wie der Rest von Hermes.

Schritt 1: Die Webhook-Plattform aktivieren

Du kannst Webhooks für einen schnellen Start über Umgebungsvariablen oder für langfristige Deployments über config.yaml aktivieren.

Umgebungsvariablen (am schnellsten)

Füge diese Zeilen zu ~/.hermes/.env hinzu:

WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644        # default
WEBHOOK_SECRET=your-global-secret

Starte das Gateway neu:

hermes gateway restart

Prüfe, ob der Server lauscht:

curl http://localhost:8644/health

Eine Antwort von {"status": "ok", "platform": "webhook"} bedeutet, dass er läuft.

Config-Datei (für die Produktion empfohlen)

Deklariere den Block platforms.webhook in ~/.hermes/config.yaml:

platforms:
  webhook:
    enabled: true
    extra:
      port: 8644
      secret: "your-global-secret"

Nach dem Neustart des Gateways lauscht Hermes auf Port 8644. Steht der Server im öffentlichen Internet, stelle sicher, dass die Firewall diesen Port erlaubt. Steht er hinter NAT oder hat keine öffentliche IP, exponiere ihn über einen Cloudflare Tunnel oder ngrok.

Schritt 2: Eine Business-Notification-Route konfigurieren

Routes liegen unter platforms.webhook.extra.routes. Jede Route hat einen Namen, einen Event-Filter, ein Secret, ein Message-Template und ein Zustellziel. Unten siehst du ein vollständiges E-Commerce-Bestellbenachrichtigungs-Beispiel, das neue Bestellungen an Telegram pusht.

platforms:
  webhook:
    enabled: true
    extra:
      port: 8644
      secret: "global-fallback-secret"
      routes:
        order-notify:
          events: ["order.created"]
          secret: "shopify-webhook-secret"
          prompt: |
            🛒 New order #{order.id}
            Amount: {order.total_price} {order.currency}
            Customer: {order.customer.email}
            Item: {order.line_items[0].title}
          deliver: "telegram"
          deliver_only: true
          deliver_extra:
            chat_id: "-1001234567890"

Die wichtigsten Punkte:

  • events ist optional. Wenn dein Business-System einen Event-Typ über X-Webhook-Event oder event_type sendet, kannst du die Route auf order.created beschränken.
  • secret wird für die HMAC-Signaturvalidierung verwendet. Hat die Route kein Secret, fällt sie auf das globale secret zurück.
  • deliver_only: true aktiviert Direct Delivery und überspringt das LLM.
  • prompt ist ein Template. Verwende Punktnotation wie {order.total_price}, um auf JSON-Felder zuzugreifen. {__raw__} gibt das gesamte Payload aus.
  • deliver_extra.chat_id zielt auf eine bestimmte Gruppe. Fehlt der Wert, liefert Hermes an den konfigurierten Home-Channel der Plattform (dafür muss die Plattform aktiviert und verbunden sein).

Schritt 3: Events aus deinem Business-System senden

Dein Business-System POSTet an die richtige URL. Für das obige Beispiel:

POST https://your-server:8644/webhooks/order-notify

Verwende Generic-V2-Signing: Verkette timestamp.body, berechne HMAC-SHA256 und sende das Ergebnis im Header X-Webhook-Signature-V2 zusammen mit X-Webhook-Timestamp. Das Zeitfenster beträgt ±300 Sekunden, wodurch Replay-Angriffe blockiert werden.

import hmac
import hashlib
import time
import json
import requests

secret = b"shopify-webhook-secret"
body = json.dumps({
    "event_type": "order.created",
    "order": {
        "id": 10086,
        "total_price": "199.00",
        "currency": "USD",
        "customer": {"email": "[email protected]"},
        "line_items": [{"title": "Hermes sticker pack"}]
    }
}).encode()

timestamp = str(int(time.time()))
signature = hmac.new(secret, f"{timestamp}.{body.decode()}".encode(), hashlib.sha256).hexdigest()

requests.post(
    "https://your-server:8644/webhooks/order-notify",
    data=body,
    headers={
        "Content-Type": "application/json",
        "X-Webhook-Signature-V2": signature,
        "X-Webhook-Timestamp": timestamp,
    }
)

GitHub- und GitLab-Signaturen werden ebenfalls automatisch erkannt. Für eigene Business-Systeme bevorzuge Generic V2.

Schritt 4: Die Route testen

Du musst nicht warten, bis das Business-System live geht. Teste zuerst lokal:

hermes webhook test order-notify \
  --payload '{"event_type":"order.created","order":{"id":10086,"total_price":"199.00","currency":"USD","customer":{"email":"[email protected]"},"line_items":[{"title":"Hermes sticker pack"}]}}'

hermes webhook test simuliert einen POST, damit du Template-Rendering und Zustellung verifizieren kannst. Kommt die Nachricht nicht an, prüfe gateway.log oder starte hermes gateway run im Vordergrund, um zu sehen, ob die Signatur fehlgeschlagen ist, das Event gefiltert wurde oder das Zustellziel nicht verbunden ist.

Szenario 1: E-Commerce-Bestellbenachrichtigungen → Telegram

Das Beispiel order-notify oben ist bereits vollständig. Ein paar Details, die hervorgehoben werden sollten:

  • chat_id-Werte von Telegram-Gruppen sind in der Regel negativ und beginnen mit -100.
  • Um ein bestimmtes Forum-Thema anzusprechen, füge message_thread_id: "42" in deliver_extra hinzu.
  • {order.line_items[0].title} zeigt nur den ersten Artikel. Um alles aufzulisten, verarbeite das Payload entweder im Business-System vor oder nutze den Agent-Modus mit {__raw__} und lass das LLM zusammenfassen.

Szenario 2: Zahlungserfolg → Discord

Zahlungssysteme wie Stripe senden bereits Webhooks. Binde das Erfolgs-Event von Stripe an eine Discord-Nachricht:

routes:
  payment-success:
    events: ["payment_intent.succeeded"]
    secret: "stripe-webhook-secret"
    prompt: |
      💰 Payment received: {amount} {currency}
      Order: {metadata.order_id}
      Customer: {receipt_email}
    deliver: "discord"
    deliver_only: true
    deliver_extra:
      chat_id: "123456789012345678"

Stripe sendet type statt event_type. Wenn Hermes den Event-Header nicht erkennt, wickle das Payload entweder in deinem Business-System ein oder lass events leer und verwende filters:

routes:
  payment-success:
    secret: "stripe-webhook-secret"
    filters:
      - field: "type"
        equals: "payment_intent.succeeded"
    prompt: "..."
    deliver: "discord"
    deliver_only: true

Szenario 3: Monitoring-Alerts → Slack

Grafana, Datadog oder jedes eigene Monitor-System kann Alerts senden. Pushe nur kritische Alerts an Slack:

routes:
  critical-alert:
    events: ["alert"]
    secret: "monitoring-webhook-secret"
    filters:
      - field: "severity"
        equals: "critical"
    prompt: |
      🚨 Critical alert
      Service: {service}
      Metric: {metric}
      Current value: {current_value}
      Threshold: {threshold}
    deliver: "slack"
    deliver_only: true
    deliver_extra:
      chat_id: "your-slack-channel-id"

Slack muss im Gateway aktiviert und verbunden sein. Wenn du Slack nur für Webhook-Benachrichtigungen nutzt, brauchst du es nicht als primäre Chat-Plattform; konfiguriere einfach platforms.slack mit einem Home-Channel oder gib die chat_id in deliver_extra an.

Fortgeschritten: Payloads mit Skripten filtern und transformieren

Wenn das JSON des Business-Systems unübersichtlich ist oder du nur unter bestimmten Bedingungen benachrichtigen willst, schreibe ein Vorverarbeitungsskript. Skripte müssen unter ~/.hermes/scripts/ liegen; relative Pfade werden dort aufgelöst.

# ~/.hermes/scripts/alert-filter.py
import json
import sys

payload = json.load(sys.stdin)
if payload.get("severity") != "critical":
    print("[SILENT]")
    raise SystemExit(0)

payload["body"] = f"{payload['service']} critical: {payload['metric']}"
print(json.dumps(payload))

Referenziere es in der Route:

routes:
  critical-alert:
    events: ["alert"]
    secret: "monitoring-webhook-secret"
    script: "alert-filter.py"
    prompt: "{body}"
    deliver: "slack"
    deliver_only: true

JSON-Stdout ersetzt das Payload; reiner Text-Stdout wird als script_output injiziert; leere Ausgabe oder [SILENT] führt dazu, dass Hermes den Webhook ignoriert.

Sicherheit: Verlass dich nicht allein auf HMAC

HMAC beweist, dass der Absender vertrauenswürdig ist – nicht, dass der Inhalt des Payloads sicher ist. PR-Titel, Issue-Bodies, Bestellnotizen und Alert-Nachrichten stammen von Dritten und könnten injizierte Anweisungen enthalten. Also:

  1. Isoliere die Laufzeit. Ist der Webhook im Internet exponiert, betreibe das Gateway mit einem Docker- oder SSH-Terminal-Backend; exponiere den Host nicht direkt gegenüber Events.
  2. Direct Delivery ist von Natur aus sicherer. Da es das LLM überspringt, gibt es kein Prompt-Injection-Risiko, das Agent-Aktionen auslösen könnte.
  3. Begrenze das Toolset. Muss eine Route in den Agent-Modus, deaktiviere gefährliche Tools wie terminal und file für diese Route.
  4. Lass Approvals aktiviert. Wenn der webhook-ausgelöste Agent Befehle ausführen soll, lass die Freigaben aktiviert, damit injizierte Anweisungen nicht unbeaufsichtigt ausgeführt werden können.
  5. Templating eng halten. Vermeide den Missbrauch von {__raw__}; nimm in prompt nur die Felder auf, die du brauchst.

Hermes bringt außerdem Guardrails mit: standardmäßig 30 Requests pro Minute pro Route, ein Body-Limit von 1 MB und ein 1-Stunden-Idempotenz-Cache. Diese Standardwerte reichen für die meisten Benachrichtigungen, du kannst sie aber in extra anpassen:

extra:
  rate_limit: 60
  max_body_bytes: 2097152

Troubleshooting-Checkliste

Symptom Wahrscheinliche Ursache Was du prüfen solltest
POST des Business-Systems schlägt fehl Port/Firewall nicht geöffnet curl http://your-server:8644/health
401 Unauthorized Signatur stimmt nicht Prüfe Secret und HMAC-Algorithmus; lies die Gateway-Logs
200 OK, aber keine Nachricht Event-Typ passt nicht Prüfe die events-Liste und das Feld event_type
Doppelte Nachrichten Retries + verfehlte Idempotenz Stelle sicher, dass der Absender X-Request-ID oder X-GitHub-Delivery sendet
Template-Variablen nicht expandiert Falsche Feldnamen Iteriere mit hermes webhook test

Dynamische Subscriptions vs. Config-Datei-Routes

Neben statischen Routes in config.yaml kannst du Subscriptions auch dynamisch per CLI anlegen:

hermes webhook subscribe order-notify \
  --events "order.created" \
  --prompt "New order #{order.id}, amount {order.total_price} {order.currency}" \
  --deliver telegram \
  --deliver-chat-id "-1001234567890" \
  --deliver-only \
  --description "E-commerce order notifications"

Dynamische Subscriptions werden in ~/.hermes/webhook_subscriptions.json gespeichert und vom Gateway heiß nachgeladen – kein Neustart erforderlich. Statische Routes mit demselben Namen haben Vorrang. Die vollständige Befehlsreferenz findest du auf unserer hermes webhook-Befehlsseite.

Zusammenfassung

Die Webhook-Plattform von Hermes ist kein Chatbot; sie ist ein eventgesteuerter Message-Router. Für Business-Systeme liegt ihr Hauptwert darin:

  • Polling in Push zu verwandeln, API-Quota zu sparen und Latenz zu senken.
  • Message-Templates und Zustellziele in Hermes zu zentralisieren, sodass ein Wechsel der Chat-Plattform oder Gruppe keinen Business-System-Deploy erfordert.
  • Den Direct-Delivery-Modus für Token-freie Benachrichtigungen in unter einer Sekunde.

Wenn du Hermes bereits für tägliche Aufgaben nutzt, ist ein zusätzlicher Webhook-Endpoint fast kostenlos: Das Gateway läuft ohnehin schon – es lauscht nur auf einem weiteren Port. Deine Business-Systeme können proaktiv sprechen, und du entscheidest, was sie sagen und wo.

Neu bei Hermes? Starte mit dem Installations-Leitfaden. Die vollständige Webhook-Befehlsreferenz findest du auf der hermes webhook-Befehlsseite. Wenn du dich für eventgesteuerte Automatisierung interessierst, lies auch unseren Cron-Skript-Only-Leitfaden und den Yolo-Modus-Erklärer.