Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Webhooks

The webhook channel is a generic inbound/outbound HTTP adapter. It runs its own embedded HTTP server on a port you choose, accepts JSON-shaped messages, hands them to the agent, and (optionally) POSTs the agent’s replies to a URL you specify. Use it as the universal adapter for any system that can produce an HTTP POST.

Not the same as the gateway’s /webhook endpoint. The gateway service has its own POST /webhook for paired clients hitting the agent over HTTP, that lives under [gateway] and is described in Operations → Network deployment. This page documents the [channels.webhook] channel only.

Configuration

auth_header 🔑 secret · default null

Optional Authorization header value for outbound requests.

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.auth_header field.

zerocode

In the Config pane, set the channels.webhook.<alias>.auth_header field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.auth_header    # masked input, stored encrypted

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__auth_header=
excluded_tools string[] · default []

Tools excluded from this channel’s tool spec. When set, these tools are not exposed to the model when responding via this channel.

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.excluded_tools field.

zerocode

In the Config pane, set the channels.webhook.<alias>.excluded_tools field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.excluded_tools <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__excluded_tools=
listen_path string? · default null

URL path to listen on (default: /webhook).

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.listen_path field.

zerocode

In the Config pane, set the channels.webhook.<alias>.listen_path field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.listen_path <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__listen_path=
max_retries integer? · default null

Maximum number of retry attempts for outbound sends on transient failures (network errors, 429, 5xx). Set to 0 to disable retries. Default: 3.

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.max_retries field.

zerocode

In the Config pane, set the channels.webhook.<alias>.max_retries field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.max_retries <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__max_retries=
port integer · default 8090

Port to listen on for incoming webhooks.

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.port field.

zerocode

In the Config pane, set the channels.webhook.<alias>.port field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.port <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__port=
reply_min_interval_secs integer · default 0

Per-(channel, recipient) outbound pacing floor in seconds. Range: 0..=REPLY_MIN_INTERVAL_MAX_SECS (0 disables).

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.reply_min_interval_secs field.

zerocode

In the Config pane, set the channels.webhook.<alias>.reply_min_interval_secs field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.reply_min_interval_secs <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__reply_min_interval_secs=
reply_queue_depth_max integer · default 0

Per-(channel, recipient) outbound pacing queue depth. Range: 0..=REPLY_QUEUE_DEPTH_CEILING. When reply_min_interval_secs > 0 and this value is 0, the pacing wrapper substitutes DEFAULT_REPLY_QUEUE_DEPTH (16). When the queue is full, the newest send is dropped and a WARN is logged.

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.reply_queue_depth_max field.

zerocode

In the Config pane, set the channels.webhook.<alias>.reply_queue_depth_max field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.reply_queue_depth_max <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__reply_queue_depth_max=
retry_base_delay_ms integer? · default null

Base delay in milliseconds for exponential backoff between retries. Default: 500. Values below 1 are clamped to 1ms at runtime to avoid busy-retry loops.

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.retry_base_delay_ms field.

zerocode

In the Config pane, set the channels.webhook.<alias>.retry_base_delay_ms field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.retry_base_delay_ms <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__retry_base_delay_ms=
retry_max_delay_ms integer? · default null

Maximum delay cap in milliseconds for any single retry wait. Default: 30000 (30s). Values below 1 are clamped to 1ms at runtime to avoid busy-retry loops.

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.retry_max_delay_ms field.

zerocode

In the Config pane, set the channels.webhook.<alias>.retry_max_delay_ms field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.retry_max_delay_ms <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__retry_max_delay_ms=
secret 🔑 secret · default

Optional shared secret for webhook signature verification (HMAC-SHA256).

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.secret field.

zerocode

In the Config pane, set the channels.webhook.<alias>.secret field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.secret    # masked input, stored encrypted

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__secret=
send_method string? · default null

HTTP method for outbound messages (POST or PUT). Default: POST.

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.send_method field.

zerocode

In the Config pane, set the channels.webhook.<alias>.send_method field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.send_method <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__send_method=
send_url string? · default null

URL to POST/PUT outbound messages to.

Set it on any surface:

Gateway dashboard

Open /config/channels/webhook and set the channels.webhook.<alias>.send_url field.

zerocode

In the Config pane, set the channels.webhook.<alias>.send_url field.

zeroclaw config

zeroclaw config set channels.webhook.<alias>.send_url <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_channels__webhook__<alias>__send_url=

Full field reference: config reference.

Inbound

The channel binds 0.0.0.0:{port} and routes POST {listen_path}.

Request body (JSON):

{
  "sender": "alice",
  "content": "Hello, agent.",
  "thread_id": "optional-conversation-id"
}
  • sender: required, used as the message’s sender identity.
  • content: required, the user message handed to the agent. Empty content returns 400.
  • thread_id: optional. If set, the agent’s reply targets the same thread; otherwise replies target sender.

Success returns 200 OK. Malformed JSON or empty content returns 400. Backpressure (channel queue full) returns 503.

Signature verification

When secret is set, every inbound request must carry an X-Webhook-Signature header:

X-Webhook-Signature: sha256=<hex-encoded HMAC-SHA256 of the raw body>

The channel computes HMAC-SHA256(secret, raw_body), hex-encodes it, and compares against the header value (the sha256= prefix is stripped before decode). Mismatch or missing header returns 401.

When secret is unset, no verification runs: every request is accepted. Don’t expose an unsecured webhook channel to the public internet; either set secret, restrict access at a reverse proxy, or run the listener bound to a private network only.

Outbound

When send_url is set, every agent reply is delivered as an HTTP request to that URL:

{send_method} {send_url}
Authorization: {auth_header}    # only if auth_header is set
Content-Type: application/json

{
  "content": "agent reply text",
  "thread_id": "optional thread id",
  "recipient": "optional recipient id"
}
  • send_method is POST (default) or PUT. Any other value falls back to POST.
  • auth_header is sent verbatim as the Authorization header value, include the scheme yourself (e.g. Bearer xyz, Basic dXNlcjpwYXNz).
  • recipient is omitted when empty.
  • Non-2xx responses raise an error in logs; the agent reply is considered failed.

When send_url is unset, agent replies are dropped silently (logged at debug). This is the right configuration for fire-and-forget inbound flows where the response is delivered through some other channel.

Public exposure

The channel binds to 0.0.0.0 directly. To expose it on the public internet:

  1. Reverse proxy: terminate TLS at nginx / Caddy / Traefik and proxy to the channel’s port. See Operations → Network deployment.
  2. Tunnel: configure [tunnel] (ngrok, cloudflare, or tailscale) and the daemon brings up the tunnel alongside the channel.
  3. Local-only: run inside a private network and have your producer hit the LAN/loopback address directly.

Always pair public exposure with secret. An unauthenticated webhook listener is an open ingress to the agent.

Outbound retries

When send_url is set, outbound delivery retries transient failures, network errors, HTTP 429, and HTTP 5xx, with exponential backoff (±25% jitter) capped by retry_max_delay_ms. Non-429 4xx responses fail immediately without retrying. When the server returns a Retry-After header on 429 or 503, that value is honored and also clamped by retry_max_delay_ms. Setting max_retries = 0 is fire-and-forget.

See also