Webhooks
Webhooks
Section titled “Webhooks”Gateway can expose a small HTTP webhook endpoint for external triggers.
Enable
Section titled “Enable”{ hooks: { enabled: true, token: "shared-secret", path: "/hooks", // Optional: restrict explicit `agentId` routing to this allowlist. // Omit or include "*" to allow any agent. // Set [] to deny all explicit `agentId` routing. allowedAgentIds: ["hooks", "main"], },}Notes:
hooks.tokenis required whenhooks.enabled=true.hooks.pathdefaults to/hooks.
Every request must include the hook token. Prefer headers:
Authorization: Bearer <token>(recommended)x-coderclaw-token: <token>- Query-string tokens are rejected (
?token=...returns400).
Endpoints
Section titled “Endpoints”POST /hooks/wake
Section titled “POST /hooks/wake”Payload:
{ "text": "System line", "mode": "now" }textrequired (string): The description of the event (e.g., “New email received”).modeoptional (now|next-heartbeat): Whether to trigger an immediate heartbeat (defaultnow) or wait for the next periodic check.
Effect:
- Enqueues a system event for the main session
- If
mode=now, triggers an immediate heartbeat
POST /hooks/agent
Section titled “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}messagerequired (string): The prompt or message for the agent to process.nameoptional (string): Human-readable name for the hook (e.g., “GitHub”), used as a prefix in session summaries.agentIdoptional (string): Route this hook to a specific agent. Unknown IDs fall back to the default agent. When set, the hook runs using the resolved agent’s workspace and configuration.sessionKeyoptional (string): The key used to identify the agent’s session. By default this field is rejected unlesshooks.allowRequestSessionKey=true.wakeModeoptional (now|next-heartbeat): Whether to trigger an immediate heartbeat (defaultnow) or wait for the next periodic check.deliveroptional (boolean): Iftrue, the agent’s response will be sent to the messaging channel. Defaults totrue. Responses that are only heartbeat acknowledgments are automatically skipped.channeloptional (string): The messaging channel for delivery. One of:last,whatsapp,telegram,discord,slack,mattermost(plugin),signal,imessage,msteams. Defaults tolast.tooptional (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.modeloptional (string): Model override (e.g.,anthropic/claude-3-5-sonnetor an alias). Must be in the allowed model list if restricted.thinkingoptional (string): Thinking level override (e.g.,low,medium,high).timeoutSecondsoptional (number): Maximum duration for the agent run in seconds.
Effect:
- Runs an isolated agent turn (own session key)
- Always posts a summary into the main session
- If
wakeMode=now, triggers an immediate heartbeat
Session key policy (breaking change)
Section titled “Session key policy (breaking change)”/hooks/agent payload sessionKey overrides are disabled by default.
- Recommended: set a fixed
hooks.defaultSessionKeyand keep request overrides off. - Optional: allow request overrides only when needed, and restrict prefixes.
Recommended config:
{ hooks: { enabled: true, token: "${CODERCLAW_HOOKS_TOKEN}", defaultSessionKey: "hook:ingress", allowRequestSessionKey: false, allowedSessionKeyPrefixes: ["hook:"], },}Compatibility config (legacy behavior):
{ hooks: { enabled: true, token: "${CODERCLAW_HOOKS_TOKEN}", allowRequestSessionKey: true, allowedSessionKeyPrefixes: ["hook:"], // strongly recommended },}POST /hooks/<name> (mapped)
Section titled “POST /hooks/<name> (mapped)”Custom hook names are resolved via hooks.mappings (see configuration). A mapping can
turn arbitrary payloads into wake or agent actions, with optional templates or
code transforms.
Mapping options (summary):
hooks.presets: ["gmail"]enables the built-in Gmail mapping.hooks.mappingslets you definematch,action, and templates in config.hooks.transformsDir+transform.moduleloads a JS/TS module for custom logic.hooks.transformsDir(if set) must stay within the transforms root under your CoderClaw config directory (typically~/.coderclaw/hooks/transforms).transform.modulemust resolve within the effective transforms directory (traversal/escape paths are rejected).
- Use
match.sourceto keep a generic ingest endpoint (payload-driven routing). - TS transforms require a TS loader (e.g.
bunortsx) or precompiled.jsat runtime. - Set
deliver: true+channel/toon mappings to route replies to a chat surface (channeldefaults tolastand falls back to WhatsApp). agentIdroutes the hook to a specific agent; unknown IDs fall back to the default agent.hooks.allowedAgentIdsrestricts explicitagentIdrouting. Omit it (or include*) to allow any agent. Set[]to deny explicitagentIdrouting.hooks.defaultSessionKeysets the default session for hook agent runs when no explicit key is provided.hooks.allowRequestSessionKeycontrols whether/hooks/agentpayloads may setsessionKey(default:false).hooks.allowedSessionKeyPrefixesoptionally restricts explicitsessionKeyvalues from request payloads and mappings.allowUnsafeExternalContent: truedisables the external content safety wrapper for that hook (dangerous; only for trusted internal sources).coderclaw webhooks gmail setupwriteshooks.gmailconfig forcoderclaw webhooks gmail run. See Gmail Pub/Sub for the full Gmail watch flow.
Responses
Section titled “Responses”200for/hooks/wake202for/hooks/agent(async run started)401on auth failure429after repeated auth failures from the same client (checkRetry-After)400on invalid payload413on oversized payloads
Examples
Section titled “Examples”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-coderclaw-token: SECRET' \ -H 'Content-Type: application/json' \ -d '{"message":"Summarize inbox","name":"Email","wakeMode":"next-heartbeat"}'Use a different model
Section titled “Use a different model”Add model to the agent payload (or mapping) to override the model for that run:
curl -X POST http://127.0.0.1:18789/hooks/agent \ -H 'x-coderclaw-token: SECRET' \ -H 'Content-Type: application/json' \ -d '{"message":"Summarize inbox","name":"Email","model":"openai/gpt-5.2-mini"}'If you enforce agents.defaults.models, make sure the override model is included there.
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"}]}'Security
Section titled “Security”- Keep hook endpoints behind loopback, tailnet, or trusted reverse proxy.
- Use a dedicated hook token; do not reuse gateway auth tokens.
- Repeated auth failures are rate-limited per client address to slow brute-force attempts.
- If you use multi-agent routing, set
hooks.allowedAgentIdsto limit explicitagentIdselection. - Keep
hooks.allowRequestSessionKey=falseunless you require caller-selected sessions. - If you enable request
sessionKey, restricthooks.allowedSessionKeyPrefixes(for example,["hook:"]). - Avoid including sensitive raw payloads in webhook logs.
- Hook payloads are treated as untrusted and wrapped with safety boundaries by default.
If you must disable this for a specific hook, set
allowUnsafeExternalContent: truein that hook’s mapping (dangerous).