Webhooks

Das Gateway kann einen kleinen HTTP-Webhook-Endpunkt für externe Trigger bereitstellen.

Aktivieren

{
  hooks: {
    enabled: true,
    token: "shared-secret",
    path: "/hooks",
    // Optional: explizites `agentId`-Routing auf diese Allowlist beschränken.
    // Weglassen oder "*" einfügen, um jeden Agent zu erlauben.
    // Auf [] setzen, um jedes explizite `agentId`-Routing zu verweigern.
    allowedAgentIds: ["hooks", "main"],
  },
}

Hinweise:

  • hooks.token ist erforderlich, wenn hooks.enabled=true.
  • hooks.path hat den Standard /hooks.

Authentifizierung

Jede Anfrage muss das Hook-Token enthalten. Bevorzuge Header:

  • Authorization: Bearer <token> (empfohlen)
  • x-openclaw-token: <token>
  • Query-String-Tokens werden abgelehnt (?token=... gibt 400 zurück).

Endpunkte

POST /hooks/wake

Payload:

{ "text": "System line", "mode": "now" }
  • text erforderlich (string): Die Beschreibung des Events (z.B. “Neue E-Mail eingegangen”).
  • mode optional (now | next-heartbeat): Ob ein sofortiger Heartbeat ausgelöst (Standard now) oder auf die nächste periodische Prüfung gewartet werden soll.

Wirkung:

  • Reiht ein System-Event für die Main-Session ein
  • Bei mode=now wird ein sofortiger Heartbeat ausgelöst

POST /hooks/agent

Payload:

{
  "message": "Run this",
  "name": "Email",
  "agentId": "hooks",
  "sessionKey": "hook:email:msg-123",
  "wakeMode": "now",
  "deliver": true,
  "channel": "last",
  "to": "+15551234567",
  "model": "openai/gpt-5.2-mini",
  "thinking": "low",
  "timeoutSeconds": 120
}
  • message erforderlich (string): Der Prompt oder die Nachricht, die der Agent verarbeiten soll.
  • name optional (string): Menschenlesbarer Name für den Hook (z.B. “GitHub”), wird als Präfix in Session-Zusammenfassungen verwendet.
  • agentId optional (string): Diesen Hook an einen bestimmten Agent routen. Unbekannte IDs fallen auf den Standard-Agent zurück. Wenn gesetzt, nutzt der Hook den Workspace und die Konfiguration des aufgelösten Agents.
  • sessionKey optional (string): Der Schlüssel zur Identifizierung der Agent-Session. Standardmäßig wird dieses Feld abgelehnt, es sei denn hooks.allowRequestSessionKey=true.
  • wakeMode optional (now | next-heartbeat): Ob ein sofortiger Heartbeat ausgelöst (Standard now) oder auf die nächste periodische Prüfung gewartet werden soll.
  • deliver optional (boolean): Wenn true, wird die Antwort des Agents an den Messaging-Channel gesendet. Standard ist true. Antworten, die nur Heartbeat-Bestätigungen sind, werden automatisch übersprungen.
  • channel optional (string): Der Messaging-Channel für die Zustellung. Einer von: last, whatsapp, telegram, discord, slack, mattermost (Plugin), signal, imessage, msteams. Standard ist last.
  • to optional (string): Die Empfänger-Kennung für den Channel (z.B. Telefonnummer für WhatsApp/Signal, Chat-ID für Telegram, Channel-ID für Discord/Slack/Mattermost (Plugin), Konversations-ID für MS Teams). Standard ist der letzte Empfänger in der Main-Session.
  • model optional (string): Modell-Override (z.B. anthropic/claude-3-5-sonnet oder ein Alias). Muss in der erlaubten Modellliste stehen, falls eingeschränkt.
  • thinking optional (string): Thinking-Level-Override (z.B. low, medium, high).
  • timeoutSeconds optional (number): Maximale Dauer für den Agent-Run in Sekunden.

Wirkung:

  • Führt einen isolierten Agent-Turn aus (eigener Session-Key)
  • Postet immer eine Zusammenfassung in die Main-Session
  • Bei wakeMode=now wird ein sofortiger Heartbeat ausgelöst

Session-Key-Policy (Breaking Change)

/hooks/agent Payload-sessionKey-Overrides sind standardmäßig deaktiviert.

  • Empfohlen: Einen festen hooks.defaultSessionKey setzen und Request-Overrides ausgeschaltet lassen.
  • Optional: Request-Overrides nur bei Bedarf erlauben und Präfixe einschränken.

Empfohlene Konfiguration:

{
  hooks: {
    enabled: true,
    token: "${OPENCLAW_HOOKS_TOKEN}",
    defaultSessionKey: "hook:ingress",
    allowRequestSessionKey: false,
    allowedSessionKeyPrefixes: ["hook:"],
  },
}

Kompatibilitätskonfiguration (Legacy-Verhalten):

{
  hooks: {
    enabled: true,
    token: "${OPENCLAW_HOOKS_TOKEN}",
    allowRequestSessionKey: true,
    allowedSessionKeyPrefixes: ["hook:"], // dringend empfohlen
  },
}

POST /hooks/<name> (gemappt)

Benutzerdefinierte Hook-Namen werden über hooks.mappings aufgelöst (siehe Konfiguration). Ein Mapping kann beliebige Payloads in wake- oder agent-Aktionen umwandeln, mit optionalen Templates oder Code-Transforms.

Mapping-Optionen (Zusammenfassung):

  • hooks.presets: ["gmail"] aktiviert das eingebaute Gmail-Mapping.
  • hooks.mappings erlaubt dir, match, action und Templates in der Konfiguration zu definieren.
  • hooks.transformsDir + transform.module lädt ein JS/TS-Modul für benutzerdefinierte Logik.
    • hooks.transformsDir (falls gesetzt) muss innerhalb des Transforms-Root unter deinem OpenClaw-Konfigurationsverzeichnis bleiben (typischerweise ~/.openclaw/hooks/transforms).
    • transform.module muss innerhalb des effektiven Transform-Verzeichnisses aufgelöst werden (Traversal/Escape-Pfade werden abgelehnt).
  • Nutze match.source, um einen generischen Ingest-Endpunkt beizubehalten (Payload-gesteuertes Routing).
  • TS-Transforms erfordern einen TS-Loader (z.B. bun oder tsx) oder vorkompiliertes .js zur Laufzeit.
  • Setze deliver: true + channel/to auf Mappings, um Antworten an eine Chat-Oberfläche zu routen (channel hat den Standard last und fällt auf WhatsApp zurück).
  • agentId routet den Hook an einen bestimmten Agent; unbekannte IDs fallen auf den Standard-Agent zurück.
  • hooks.allowedAgentIds beschränkt explizites agentId-Routing. Weglassen (oder * einfügen) erlaubt jeden Agent. Auf [] setzen verweigert explizites agentId-Routing.
  • hooks.defaultSessionKey setzt die Standard-Session für Hook-Agent-Runs, wenn kein expliziter Key angegeben wird.
  • hooks.allowRequestSessionKey steuert, ob /hooks/agent-Payloads sessionKey setzen dürfen (Standard: false).
  • hooks.allowedSessionKeyPrefixes beschränkt optional explizite sessionKey-Werte aus Request-Payloads und Mappings.
  • allowUnsafeExternalContent: true deaktiviert den Sicherheits-Wrapper für externen Content bei diesem Hook (gefährlich; nur für vertrauenswürdige interne Quellen).
  • openclaw webhooks gmail setup schreibt hooks.gmail-Konfiguration für openclaw webhooks gmail run. Siehe Gmail Pub/Sub für den vollständigen Gmail-Watch-Flow.

Antworten

  • 200 für /hooks/wake
  • 200 für /hooks/agent (Asynchroner Run akzeptiert)
  • 401 bei Auth-Fehler
  • 429 nach wiederholten Auth-Fehlern von der gleichen Client-Adresse (prüfe Retry-After)
  • 400 bei ungültigem Payload
  • 413 bei übergroßen Payloads

Beispiele

curl -X POST http://127.0.0.1:18789/hooks/wake \
  -H 'Authorization: Bearer SECRET' \
  -H 'Content-Type: application/json' \
  -d '{"text":"New email received","mode":"now"}'
curl -X POST http://127.0.0.1:18789/hooks/agent \
  -H 'x-openclaw-token: SECRET' \
  -H 'Content-Type: application/json' \
  -d '{"message":"Summarize inbox","name":"Email","wakeMode":"next-heartbeat"}'

Anderes Modell verwenden

Füge model zum Agent-Payload (oder Mapping) hinzu, um das Modell für diesen Lauf zu überschreiben:

curl -X POST http://127.0.0.1:18789/hooks/agent \
  -H 'x-openclaw-token: SECRET' \
  -H 'Content-Type: application/json' \
  -d '{"message":"Summarize inbox","name":"Email","model":"openai/gpt-5.2-mini"}'

Wenn du agents.defaults.models erzwingst, stelle sicher, dass das Override-Modell dort enthalten ist.

curl -X POST http://127.0.0.1:18789/hooks/gmail \
  -H 'Authorization: Bearer SECRET' \
  -H 'Content-Type: application/json' \
  -d '{"source":"gmail","messages":[{"from":"Ada","subject":"Hello","snippet":"Hi"}]}'

Sicherheit

  • Halte Hook-Endpunkte hinter Loopback, Tailnet oder einem vertrauenswürdigen Reverse-Proxy.
  • Verwende ein eigenes Hook-Token; verwende keine Gateway-Auth-Tokens wieder.
  • Wiederholte Auth-Fehler werden pro Client-Adresse rate-limitiert, um Brute-Force-Versuche zu verlangsamen.
  • Wenn du Multi-Agent-Routing nutzt, setze hooks.allowedAgentIds, um explizite agentId-Auswahl einzuschränken.
  • Lasse hooks.allowRequestSessionKey=false, es sei denn du brauchst Aufrufer-gewählte Sessions.
  • Wenn du Request-sessionKey aktivierst, beschränke hooks.allowedSessionKeyPrefixes (zum Beispiel ["hook:"]).
  • Vermeide es, sensible Roh-Payloads in Webhook-Logs aufzunehmen.
  • Hook-Payloads werden als nicht vertrauenswürdig behandelt und standardmäßig mit Sicherheitsgrenzen umschlossen. Wenn du das für einen bestimmten Hook deaktivieren musst, setze allowUnsafeExternalContent: true in dessen Mapping (gefährlich).