{
  "title": "Webhooks",
  "content": "Gateway can expose a small HTTP webhook endpoint for external triggers.\n\n* `hooks.token` is required when `hooks.enabled=true`.\n* `hooks.path` defaults to `/hooks`.\n\nEvery request must include the hook token. Prefer headers:\n\n* `Authorization: Bearer <token>` (recommended)\n* `x-openclaw-token: <token>`\n* `?token=<token>` (deprecated; logs a warning and will be removed in a future major release)\n\n### `POST /hooks/wake`\n\n* `text` **required** (string): The description of the event (e.g., \"New email received\").\n* `mode` optional (`now` | `next-heartbeat`): Whether to trigger an immediate heartbeat (default `now`) or wait for the next periodic check.\n\n* Enqueues a system event for the **main** session\n* If `mode=now`, triggers an immediate heartbeat\n\n### `POST /hooks/agent`\n\n* `message` **required** (string): The prompt or message for the agent to process.\n* `name` optional (string): Human-readable name for the hook (e.g., \"GitHub\"), used as a prefix in session summaries.\n* `sessionKey` optional (string): The key used to identify the agent's session. Defaults to a random `hook:<uuid>`. Using a consistent key allows for a multi-turn conversation within the hook context.\n* `wakeMode` optional (`now` | `next-heartbeat`): Whether to trigger an immediate heartbeat (default `now`) or wait for the next periodic check.\n* `deliver` optional (boolean): If `true`, the agent's response will be sent to the messaging channel. Defaults to `true`. Responses that are only heartbeat acknowledgments are automatically skipped.\n* `channel` optional (string): The messaging channel for delivery. One of: `last`, `whatsapp`, `telegram`, `discord`, `slack`, `mattermost` (plugin), `signal`, `imessage`, `msteams`. Defaults to `last`.\n* `to` optional (string): The recipient identifier for the channel (e.g., phone number for WhatsApp/Signal, chat ID for Telegram, channel ID for Discord/Slack/Mattermost (plugin), conversation ID for MS Teams). Defaults to the last recipient in the main session.\n* `model` optional (string): Model override (e.g., `anthropic/claude-3-5-sonnet` or an alias). Must be in the allowed model list if restricted.\n* `thinking` optional (string): Thinking level override (e.g., `low`, `medium`, `high`).\n* `timeoutSeconds` optional (number): Maximum duration for the agent run in seconds.\n\n* Runs an **isolated** agent turn (own session key)\n* Always posts a summary into the **main** session\n* If `wakeMode=now`, triggers an immediate heartbeat\n\n### `POST /hooks/<name>` (mapped)\n\nCustom hook names are resolved via `hooks.mappings` (see configuration). A mapping can\nturn arbitrary payloads into `wake` or `agent` actions, with optional templates or\ncode transforms.\n\nMapping options (summary):\n\n* `hooks.presets: [\"gmail\"]` enables the built-in Gmail mapping.\n* `hooks.mappings` lets you define `match`, `action`, and templates in config.\n* `hooks.transformsDir` + `transform.module` loads a JS/TS module for custom logic.\n* Use `match.source` to keep a generic ingest endpoint (payload-driven routing).\n* TS transforms require a TS loader (e.g. `bun` or `tsx`) or precompiled `.js` at runtime.\n* Set `deliver: true` + `channel`/`to` on mappings to route replies to a chat surface\n  (`channel` defaults to `last` and falls back to WhatsApp).\n* `allowUnsafeExternalContent: true` disables the external content safety wrapper for that hook\n  (dangerous; only for trusted internal sources).\n* `openclaw webhooks gmail setup` writes `hooks.gmail` config for `openclaw webhooks gmail run`.\n  See [Gmail Pub/Sub](/automation/gmail-pubsub) for the full Gmail watch flow.\n\n* `200` for `/hooks/wake`\n* `202` for `/hooks/agent` (async run started)\n* `401` on auth failure\n* `400` on invalid payload\n* `413` on oversized payloads\n\n### Use a different model\n\nAdd `model` to the agent payload (or mapping) to override the model for that run:\n\nIf you enforce `agents.defaults.models`, make sure the override model is included there.\n\n* Keep hook endpoints behind loopback, tailnet, or trusted reverse proxy.\n* Use a dedicated hook token; do not reuse gateway auth tokens.\n* Avoid including sensitive raw payloads in webhook logs.\n* Hook payloads are treated as untrusted and wrapped with safety boundaries by default.\n  If you must disable this for a specific hook, set `allowUnsafeExternalContent: true`\n  in that hook's mapping (dangerous).",
  "code_samples": [
    {
      "code": "Notes:\n\n* `hooks.token` is required when `hooks.enabled=true`.\n* `hooks.path` defaults to `/hooks`.\n\n## Auth\n\nEvery request must include the hook token. Prefer headers:\n\n* `Authorization: Bearer <token>` (recommended)\n* `x-openclaw-token: <token>`\n* `?token=<token>` (deprecated; logs a warning and will be removed in a future major release)\n\n## Endpoints\n\n### `POST /hooks/wake`\n\nPayload:",
      "language": "unknown"
    },
    {
      "code": "* `text` **required** (string): The description of the event (e.g., \"New email received\").\n* `mode` optional (`now` | `next-heartbeat`): Whether to trigger an immediate heartbeat (default `now`) or wait for the next periodic check.\n\nEffect:\n\n* Enqueues a system event for the **main** session\n* If `mode=now`, triggers an immediate heartbeat\n\n### `POST /hooks/agent`\n\nPayload:",
      "language": "unknown"
    },
    {
      "code": "* `message` **required** (string): The prompt or message for the agent to process.\n* `name` optional (string): Human-readable name for the hook (e.g., \"GitHub\"), used as a prefix in session summaries.\n* `sessionKey` optional (string): The key used to identify the agent's session. Defaults to a random `hook:<uuid>`. Using a consistent key allows for a multi-turn conversation within the hook context.\n* `wakeMode` optional (`now` | `next-heartbeat`): Whether to trigger an immediate heartbeat (default `now`) or wait for the next periodic check.\n* `deliver` optional (boolean): If `true`, the agent's response will be sent to the messaging channel. Defaults to `true`. Responses that are only heartbeat acknowledgments are automatically skipped.\n* `channel` optional (string): The messaging channel for delivery. One of: `last`, `whatsapp`, `telegram`, `discord`, `slack`, `mattermost` (plugin), `signal`, `imessage`, `msteams`. Defaults to `last`.\n* `to` optional (string): The recipient identifier for the channel (e.g., phone number for WhatsApp/Signal, chat ID for Telegram, channel ID for Discord/Slack/Mattermost (plugin), conversation ID for MS Teams). Defaults to the last recipient in the main session.\n* `model` optional (string): Model override (e.g., `anthropic/claude-3-5-sonnet` or an alias). Must be in the allowed model list if restricted.\n* `thinking` optional (string): Thinking level override (e.g., `low`, `medium`, `high`).\n* `timeoutSeconds` optional (number): Maximum duration for the agent run in seconds.\n\nEffect:\n\n* Runs an **isolated** agent turn (own session key)\n* Always posts a summary into the **main** session\n* If `wakeMode=now`, triggers an immediate heartbeat\n\n### `POST /hooks/<name>` (mapped)\n\nCustom hook names are resolved via `hooks.mappings` (see configuration). A mapping can\nturn arbitrary payloads into `wake` or `agent` actions, with optional templates or\ncode transforms.\n\nMapping options (summary):\n\n* `hooks.presets: [\"gmail\"]` enables the built-in Gmail mapping.\n* `hooks.mappings` lets you define `match`, `action`, and templates in config.\n* `hooks.transformsDir` + `transform.module` loads a JS/TS module for custom logic.\n* Use `match.source` to keep a generic ingest endpoint (payload-driven routing).\n* TS transforms require a TS loader (e.g. `bun` or `tsx`) or precompiled `.js` at runtime.\n* Set `deliver: true` + `channel`/`to` on mappings to route replies to a chat surface\n  (`channel` defaults to `last` and falls back to WhatsApp).\n* `allowUnsafeExternalContent: true` disables the external content safety wrapper for that hook\n  (dangerous; only for trusted internal sources).\n* `openclaw webhooks gmail setup` writes `hooks.gmail` config for `openclaw webhooks gmail run`.\n  See [Gmail Pub/Sub](/automation/gmail-pubsub) for the full Gmail watch flow.\n\n## Responses\n\n* `200` for `/hooks/wake`\n* `202` for `/hooks/agent` (async run started)\n* `401` on auth failure\n* `400` on invalid payload\n* `413` on oversized payloads\n\n## Examples",
      "language": "unknown"
    },
    {
      "code": "",
      "language": "unknown"
    },
    {
      "code": "### Use a different model\n\nAdd `model` to the agent payload (or mapping) to override the model for that run:",
      "language": "unknown"
    },
    {
      "code": "If you enforce `agents.defaults.models`, make sure the override model is included there.",
      "language": "unknown"
    }
  ],
  "headings": [
    {
      "level": "h2",
      "text": "Enable",
      "id": "enable"
    },
    {
      "level": "h2",
      "text": "Auth",
      "id": "auth"
    },
    {
      "level": "h2",
      "text": "Endpoints",
      "id": "endpoints"
    },
    {
      "level": "h3",
      "text": "`POST /hooks/wake`",
      "id": "`post-/hooks/wake`"
    },
    {
      "level": "h3",
      "text": "`POST /hooks/agent`",
      "id": "`post-/hooks/agent`"
    },
    {
      "level": "h3",
      "text": "`POST /hooks/<name>` (mapped)",
      "id": "`post-/hooks/<name>`-(mapped)"
    },
    {
      "level": "h2",
      "text": "Responses",
      "id": "responses"
    },
    {
      "level": "h2",
      "text": "Examples",
      "id": "examples"
    },
    {
      "level": "h3",
      "text": "Use a different model",
      "id": "use-a-different-model"
    },
    {
      "level": "h2",
      "text": "Security",
      "id": "security"
    }
  ],
  "url": "llms-txt#webhooks",
  "links": []
}