netclaw webhooks
netclaw webhooks manages inbound webhook routes. External services POST to a route, netclaw verifies the signature, runs a session with the route’s prompt, and posts results to Slack if configured.
Routes live as individual JSON files in ~/.netclaw/config/webhooks/. CLI management (list, set, validate, etc.) doesn’t need a running daemon. Actually receiving webhook requests does — start the daemon with netclaw daemon start or netclaw init.
netclaw webhooks [subcommand] [options]netclaw webhooks list [--json] [--all]| Flag | Description | Default |
|---|---|---|
--json | JSON output | Off |
--all | Include disabled routes | Off |

With no routes configured, you see the storage path. Once routes exist, the table shows status, audience, verification kind, and delivery requirement per route.
netclaw webhooks show <route> [--json] [--show-secret]Displays full configuration for a single route. Also validates the route file — exits with code 1 if the route has schema errors.
| Flag | Description | Default |
|---|---|---|
--json | JSON output | Off |
--show-secret | Reveal the verification secret | Off |
Secrets are redacted by default. Pass --show-secret when you need to copy the secret to a third-party service.
Creates or updates a route. Route names must be lowercase alphanumeric with single dashes between segments (github-issues, deploy-v2). Regex: ^[a-z0-9]+(?:-[a-z0-9]+)*$.
netclaw webhooks set <route> [options]Prompt and secret
Section titled “Prompt and secret”New routes require a prompt (choose one) and a secret (choose one):
| Flag | Description |
|---|---|
--prompt <text> | Prompt text injected into webhook sessions |
--prompt-file <path> | Read prompt from a file |
--secret <value> | Verification secret — visible in shell history; prefer --secret-file or --secret-env |
--secret-file <path> | Read secret from a file |
--secret-env <VAR> | Read secret from an environment variable |
Verification
Section titled “Verification”| Flag | Description | Default |
|---|---|---|
--verification-kind <kind> | hmac or header-secret | hmac |
--signature-header <name> | Header containing the HMAC signature | — |
--signature-prefix <prefix> | Prefix on the signature value (e.g. sha256=) | — |
--secret-header <name> | Header containing the secret (header-secret mode) | — |
--event-header <name> | Header with the event type name | — |
--delivery-header <name> | Header with the unique delivery ID (for deduplication) | — |
Behavior
Section titled “Behavior”--audience controls which tool audience the webhook session runs under. public gets the most restricted tool access, personal gets the most permissive.
| Flag | Description | Default |
|---|---|---|
--events <list> | Comma-separated event type allow-list (empty = all) | All |
--audience <level> | public, team, or personal | public |
--max-body <bytes> | Maximum request body size | 1048576 (1 MB) |
--rate-limit <N> | Requests per minute | 30 |
--enabled / --disabled | Enable or disable the route | Enabled |
Notifications
Section titled “Notifications”When a notification target is configured, the agent posts results to that Slack channel. This requires Slack to be configured in netclaw.
| Flag | Description | Default |
|---|---|---|
--notify-instructions <text> | Instructions for agent notification behavior | — |
--notify-instructions-file <path> | Read notification instructions from a file | — |
--delivery-required / --no-delivery-required | Require notification delivery | true |
--notification-channel <id> | Slack channel ID for notifications | — |
Modifiers
Section titled “Modifiers”| Flag | Description |
|---|---|
--dry-run | Validate and print the route without saving |
--create-only | Fail if the route already exists |
--update-only | Fail if the route doesn’t exist |
Examples
Section titled “Examples”GitHub issues route
Section titled “GitHub issues route”netclaw webhooks set github-issues \ --prompt "Triage this GitHub issue. Summarize it and suggest a priority label." \ --secret-env GITHUB_WEBHOOK_SECRET \ --verification-kind hmac \ --signature-header X-Hub-Signature-256 \ --signature-prefix "sha256=" \ --event-header X-GitHub-Event \ --delivery-header X-GitHub-Delivery \ --events "issues,issue_comment" \ --audience team \ --notification-channel C0123SLACKPreview without saving
Section titled “Preview without saving”netclaw webhooks set github-issues --rate-limit 10 --dry-runCreate-only (fail if exists)
Section titled “Create-only (fail if exists)”netclaw webhooks set deploy-notify \ --prompt "Summarize this deployment and post a status update." \ --secret-env DEPLOY_SECRET \ --create-onlydelete
Section titled “delete”netclaw webhooks delete <route> [--force | -f]Prompts for confirmation unless --force is passed.
validate
Section titled “validate”netclaw webhooks validate <route>Checks the route file for syntax errors and schema violations. These are the same checks netclaw doctor runs across all routes automatically. The backtick-quoted names below are JSON fields in the route file:
- Route name must match
^[a-z0-9]+(?:-[a-z0-9]+)*$ Promptis required and non-emptyVerificationsection is required with a non-emptySecretMaxBodyBytesandRateLimitPerMinutemust be >= 1Eventslist can’t contain blank entries- If
DeliveryRequiredis true andNotifyInstructionsis set,NotificationTargetis required - If
NotificationTarget.KindisSlack,NotificationTarget.ChannelIdis required
Route files
Section titled “Route files”Each route is stored as ~/.netclaw/config/webhooks/<route-name>.json. A GitHub Issues route looks like this:
{ "Enabled": true, "Prompt": "Triage this GitHub issue. Summarize it and suggest a priority label.", "Verification": { "Kind": "Hmac", "HmacAlgorithm": "Sha256", "Secret": "whsec_abc123...", "SignatureHeaderName": "X-Hub-Signature-256", "SignaturePrefix": "sha256=", "EventHeaderName": "X-GitHub-Event", "DeliveryIdHeaderName": "X-GitHub-Delivery" }, "Events": ["issues", "issue_comment"], "Audience": "Team", "MaxBodyBytes": 1048576, "RateLimitPerMinute": 30, "DeliveryRequired": true, "NotifyInstructions": "Post a summary to the triage channel.", "NotificationTarget": { "Kind": "Slack", "ChannelId": "C0123SLACK" }}Note the casing difference: CLI flags use lowercase (--verification-kind hmac, --audience team) while route files use PascalCase ("Kind": "Hmac", "Audience": "Team").
Route files contain secrets in plaintext. Keep ~/.netclaw/config/webhooks/ mode 700 and don’t commit these files to source control.
Request lifecycle
Section titled “Request lifecycle”When a POST hits /api/webhooks/{routeName}:
- The daemon loads the route file (hot-reloaded per request — no restart needed after changes)
- Verifies the request using the route’s HMAC signature or header secret
- Checks rate limits and body size constraints
- Filters by event type if the route has an allow-list
- Creates a new
Webhooksession with the route’s prompt injected as context - If a notification target is configured, the agent posts results to that Slack channel. Without a notification target, the session still runs — output is stored in the session log
Rejected requests return the appropriate HTTP status. Missing or malformed route files return 404. To see delivery and rejection counts, run netclaw stats.
Finding your webhook URL
Section titled “Finding your webhook URL”After creating a route, you need the full URL to give your external service. Run netclaw status — the output includes your webhook base URL (set during netclaw init). Your route’s endpoint is:
<your-webhook-base-url>/api/webhooks/<route-name>The webhook URL depends on how you’ve exposed your daemon. Tailscale Serve or Cloudflare Tunnel are the two supported options for making your daemon reachable from external services.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 | Success |
1 | Route not found, validation error, or other failure |
What’s next
Section titled “What’s next”After setting up a route, restart the daemon and run netclaw status to confirm the webhook endpoint is healthy. Then paste the full webhook URL into your external service’s webhook settings.
To debug webhook issues: netclaw stats shows delivery counts and rejection breakdowns, and netclaw doctor validates all route files.
Related commands
Section titled “Related commands”netclaw doctor— validates all webhook route files and flags format issuesnetclaw stats— webhook delivery counts and rejection breakdownsnetclaw init— sets up webhook URL identity during onboardingnetclaw status— live daemon health including webhook endpoint availability
Resources
Section titled “Resources”- GitHub webhook documentation — setting up webhooks on the GitHub side
- GitLab webhook documentation — GitLab’s webhook configuration
- HMAC signature verification — how GitHub’s
X-Hub-Signature-256works - Tailscale Serve — expose your webhook endpoint without a public IP
- Cloudflare Tunnel — alternative to Tailscale for public webhook ingress