Published on

Claude-Agenten überwachen: Webhooks statt Dauerabfrage

Authors

Agenten überwachen: der Webhook-Weg

TL;DR

Statt einen Ereignisstrom offenzuhalten oder abzufragen, meldet Anthropic Zustandswechsel an Ihren HTTPS-Endpunkt. Die Nutzlast ist dünn — Typ und Kennungen, sonst nichts —, jede Zustellung ist signiert, und es gibt keine Reihenfolgegarantie. Nach drei Fehlversuchen wird ein Ereignis ohne Signal verworfen.


Wann Webhooks der richtige Weg sind

Ja, wenn: Sitzungen lange laufen und Sie nicht durchgehend eine Verbindung offenhalten wollen. Wenn mehrere Dienste auf Zustandswechsel reagieren sollen. Wenn ein selbst betriebener Arbeiterprozess erst bei Bedarf geweckt werden soll.

Nein, wenn: Sie den Antworttext eines Agenten in Echtzeit anzeigen. Dafür ist der Ereignisstrom da — Webhooks tragen keine Inhalte.

Beides parallel ist üblich: Strom für die laufende Sitzung, Webhook für die Zustandsüberwachung darüber.

Registrierung und Signaturkontrolle

Die Registrierung erfolgt ausschließlich in der Konsole unter Verwalten und Webhooks; eine API dafür gibt es nicht. Der Signierschlüssel mit dem Präfix whsec_ wird einmal angezeigt — legen Sie ihn sofort ab.

Für die Kontrolle nutzen Sie die SDK-Funktion, nicht eine eigene Implementierung:

import anthropic
from flask import Flask, request

client = anthropic.Anthropic()      # liest ANTHROPIC_WEBHOOK_SIGNING_KEY
app = Flask(__name__)
gesehen = set()

@app.route("/webhook", methods=["POST"])
def webhook():
    try:
        ereignis = client.beta.webhooks.unwrap(
            request.get_data(as_text=True),      # ROHDATEN
            headers=dict(request.headers),
        )
    except Exception:
        return "ungültige Signatur", 400

    if ereignis.id in gesehen:      # Wiederholungen entdoppeln
        return "", 204
    gesehen.add(ereignis.id)

    if ereignis.data.type == "session.status_idled":
        sitzung = client.beta.sessions.retrieve(ereignis.data.id)
        benachrichtigen(sitzung)

    return "", 204

unwrap() kontrolliert die Signatur und lehnt Nutzlasten ab, die älter als etwa fünf Minuten sind.

Die Falle: Übergeben Sie den rohen Anfragekörper. Frameworks, die JSON erst einlesen und neu serialisieren — etwa über request.get_json() —, verändern die Bytes und brechen die Signaturkontrolle. Der Fehler sieht dann wie ein Signaturproblem aus und ist ein Serialisierungsproblem.

Die Zustellung trägt drei Kopfzeilen: webhook-id, webhook-timestamp und webhook-signature. Reichen Sie sie unverändert weiter; bauen Sie keine eigene Kontrolle gegen eine einzelne Signaturkopfzeile — das ist nicht das Übertragungsformat.

Die drei Eigenschaften, die den Aufbau bestimmen

1. Die Nutzlast ist dünn. Sie bekommen Ereignistyp und Ressourcenkennung, sonst nichts. Kein stop_reason, keine Bewertungsergebnisse, keine Geheimnisse. Holen Sie die Ressource nach dem Empfang:

{
  "type": "event",
  "id": "whe_9d5c1f7e...",
  "created_at": "2026-08-04T14:05:22Z",
  "data": {
    "type": "session.status_idled",
    "id": "session_01XYZ...",
    "organization_id": "...",
    "workspace_id": "..."
  }
}

2. Es gibt keine Reihenfolgegarantie. Ereignisse kommen nicht in der Reihenfolge ihres Auftretens an. Ein session.status_idled kann vor dem zugehörigen Bewertungsereignis eintreffen, und ein Löschereignis vor dem Archivierungsereignis derselben Ressource.

Leiten Sie Ihren Zustand deshalb aus der abgerufenen Ressource ab, nie aus der Ankunftsreihenfolge.

3. Die gleiche Zustellung kann mehrfach kommen. Jeder Versuch trägt dieselbe Ereigniskennung — sie ist je Ereignis vergeben, nicht je Zustellung. Entdoppeln Sie darüber.

Was schiefgeht

Nach drei Fehlversuchen ist das Ereignis weg. Bis zu drei Zustellversuche mit gestreutem Abstand zwischen 5 und 120 Sekunden. Danach wird verworfen — nicht in eine Warteschlange gelegt, ohne Signal, dass etwas verloren ging.

Webhooks sind kein dauerhaftes Protokoll. Wenn Sie jeden Zustandswechsel sehen müssen, gleichen Sie zusätzlich über die Auflistung oder den Abruf der Ressourcen ab.

Drei Auslöser schalten den Endpunkt automatisch ab:

AuslöserVerhalten
Eine Antwort mit 3xxSofort, beim ersten Versuch. Weiterleitungen werden nie verfolgt.
Adresse löst auf eine nicht öffentliche IP aufSofort
Anhaltende Fehler über längere ZeitAuslöser ist die Dauer, nicht die Anzahl — ein einzelnes 2xx setzt das Fenster zurück

Die erste Zeile trifft überraschend oft: Ein Reverse-Proxy, der von HTTP auf HTTPS umleitet oder einen abschließenden Schrägstrich ergänzt, schaltet den Endpunkt beim ersten Versuch ab.

Während der Abschaltung ausgesendete Ereignisse werden nicht nachgeholt, auch nach dem Wiedereinschalten nicht.

Ereignisse erreichen nur Endpunkte, die zum Zeitpunkt des Auftretens abonniert waren. Ein späteres Abonnement holt nichts nach — abonnieren Sie, bevor Sie es brauchen.

Die Ereignistypen

Ein anderer Namensraum als die Typen im Ereignisstrom — verwechseln Sie sie nicht.

Für Sitzungen: session.status_scheduled, session.status_run_started, session.status_idled, session.status_rescheduled, session.status_terminated, dazu Ereignisse für Unteragenten-Stränge und Bewertungsergebnisse.

Für Ressourcen: Anlegen, Aktualisieren, Archivieren und Löschen von Agenten, Umgebungen, Tresoren, Zugangsdaten und Speicherbereichen — sowie vault_credential.refresh_failed, wenn eine OAuth-Erneuerung scheitert. Der lohnt sich in der Alarmierung: Er meldet einen kaputten Zugang, bevor Nutzer ihn bemerken.

Bei allen Lösch-Ereignissen gibt es nichts mehr abzurufen — behandeln Sie das Ereignis selbst als endgültige Information.

Der Anwendungsfall, der sich besonders lohnt

Einen selbst betriebenen Arbeiterprozess bei Bedarf wecken, statt ihn durchlaufen zu lassen: Auf session.status_run_started abonnieren, die Zustellung kontrollieren und genau ein Arbeitspaket abarbeiten. Die Einrichtung steht im Beitrag zur selbst betriebenen Sandbox.

Häufig gestellte Fragen

Warum scheitert meine Signaturkontrolle?

Meist, weil nicht der rohe Anfragekörper übergeben wurde. Frameworks, die JSON einlesen und neu serialisieren, verändern die Bytes und brechen damit die Prüfsumme. Übergeben Sie die Rohdaten an die SDK-Funktion und reichen Sie alle Kopfzeilen unverändert weiter.

Kann ich Webhook-Endpunkte über die API verwalten?

Nein, die Registrierung erfolgt ausschließlich in der Konsole; eine API dafür gibt es derzeit nicht. Der Signierschlüssel wird bei der Anlage einmal angezeigt — legen Sie ihn sofort ab. Eine Rotation ist über dieselbe Seite möglich.

Kommen Webhook-Ereignisse in der richtigen Reihenfolge?

Nein, eine Reihenfolgegarantie gibt es nicht. Ein Leerlauf-Ereignis kann vor dem zugehörigen Bewertungsergebnis eintreffen, ein Lösch- vor dem Archivierungsereignis. Leiten Sie Ihren Zustand deshalb aus der abgerufenen Ressource ab, nicht aus der Ankunftsreihenfolge.

Was passiert, wenn mein Endpunkt vorübergehend ausfällt?

Es gibt bis zu drei Zustellversuche mit gestreutem Abstand zwischen 5 und 120 Sekunden. Danach wird das Ereignis verworfen — ohne Warteschlange und ohne Signal, dass etwas verloren ging. Wer jeden Zustandswechsel sehen muss, gleicht zusätzlich über den Abruf der Ressourcen ab.

Warum wurde mein Endpunkt automatisch abgeschaltet?

Drei Auslöser kommen infrage: eine Antwort mit einem 3xx-Statuscode, die sofort beim ersten Versuch abschaltet, weil Weiterleitungen nie verfolgt werden; eine Adresse, die auf eine nicht öffentliche IP auflöst; oder anhaltende Fehler über längere Zeit. Die erste Ursache trifft häufig Aufbauten mit einem umleitenden Reverse-Proxy.


Der nächste Schritt

Kontrollieren Sie, ob Ihr Endpunkt bei der Zustelladresse eine Weiterleitung auslöst — etwa von HTTP auf HTTPS oder wegen eines fehlenden Schrägstrichs. Das schaltet ihn beim ersten Versuch ab, und die Ursache ist von außen nicht sichtbar. Beim Aufbau helfen wir gern.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen