Trigger Claude Code tasks from webhooks. Connect Slack, GitHub, n8n, Zapier — anything that can send an HTTP request — to Claude.
npm install -g claude-webhook
# or run without installing
npx claude-webhook start# Start the server
WEBHOOK_SECRET=mysecret claude-webhook start --port 3847
# In another terminal — run a task
curl -X POST http://localhost:3847/run \
-H "Authorization: Bearer mysecret" \
-H "Content-Type: application/json" \
-d '{"task": "list all TODO comments in the repo", "cwd": "/path/to/repo"}'Server health check and recent execution history.
curl http://localhost:3847/statusResponse:
{
"status": "ok",
"version": "1.0.0",
"startedAt": "2026-02-27T10:00:00.000Z",
"uptime": 42.3,
"recentExecutions": [
{
"id": "exec_1_1740650000000",
"task": "fix the build",
"cwd": "/path/to/repo",
"source": "api",
"status": "success",
"startedAt": "2026-02-27T10:00:05.000Z",
"completedAt": "2026-02-27T10:01:12.000Z",
"durationMs": 67000,
"stdout": "Fixed the failing test in src/auth.js...",
"exitCode": 0
}
]
}Trigger an arbitrary Claude task. Auth via Authorization: Bearer <WEBHOOK_SECRET>.
# Basic task
curl -X POST http://localhost:3847/run \
-H "Authorization: Bearer mysecret" \
-H "Content-Type: application/json" \
-d '{"task": "write a unit test for src/utils.js"}'
# With working directory
curl -X POST http://localhost:3847/run \
-H "Authorization: Bearer mysecret" \
-H "Content-Type: application/json" \
-d '{
"task": "refactor the database connection pool to use async/await",
"cwd": "/Users/nick/repos/my-api"
}'
# With custom timeout (ms)
curl -X POST http://localhost:3847/run \
-H "Authorization: Bearer mysecret" \
-H "Content-Type: application/json" \
-d '{
"task": "audit all dependencies for security vulnerabilities",
"cwd": "/Users/nick/repos/my-api",
"timeout": 600000
}'Response (202 Accepted — task runs async):
{
"accepted": true,
"message": "Task queued — running Claude",
"task": "write a unit test for src/utils.js",
"cwd": "/Users/nick/repos/my-api"
}Poll GET /status to see the result.
GitHub webhook handler. Listens for CI failures (workflow_run or check_run events with conclusion: failure) and auto-triggers Claude to investigate and fix.
Auth via X-Hub-Signature-256 header (GitHub's HMAC-SHA256 format).
GitHub setup:
- Go to your repo → Settings → Webhooks → Add webhook
- Payload URL:
https://your-server.com/webhook/github - Content type:
application/json - Secret: your
WEBHOOK_SECRET - Events: select
Workflow runsandCheck runs
# Simulate a GitHub CI failure webhook
curl -X POST http://localhost:3847/webhook/github \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: workflow_run" \
-H "X-Hub-Signature-256: sha256=$(echo -n '{"action":"completed","workflow_run":{"conclusion":"failure","head_branch":"main","html_url":"https://github.com/org/repo/actions/runs/123"}}' | openssl dgst -sha256 -hmac 'mysecret' | awk '{print $2}')" \
-d '{
"action": "completed",
"workflow_run": {
"conclusion": "failure",
"head_branch": "main",
"html_url": "https://github.com/org/repo/actions/runs/123"
},
"repository": {
"full_name": "org/repo"
}
}'Response:
{
"accepted": true,
"event": "workflow_run",
"repo": "org/repo",
"branch": "main",
"task": "CI failed on org/repo (branch: main). Run URL: https://... Investigate the failure, identify the root cause, and fix it. Run the tests to verify the fix works."
}Non-failure events return 200 { skipped: true } — safe to send all events.
Slack slash command handler. Receives /claude <task> commands from Slack and runs them.
Auth via Slack's X-Slack-Signature HMAC header.
Slack app setup:
- Create a Slack app at api.slack.com/apps
- Add a Slash Command:
/claude - Request URL:
https://your-server.com/webhook/slack - Copy the Signing Secret → set as
WEBHOOK_SECRET
# Simulate a Slack slash command (no auth — for local dev)
curl -X POST http://localhost:3847/webhook/slack \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'text=update the README with the new API endpoints&response_url=https://hooks.slack.com/commands/...'
# JSON format (for n8n / Zapier)
curl -X POST http://localhost:3847/webhook/slack \
-H "Content-Type: application/json" \
-d '{"text": "add error handling to the payment module", "response_url": ""}'Slack receives an immediate 200 (within 3s deadline), then Claude posts the result back via response_url when done.
# Start server
claude-webhook start [options]
-p, --port <number> Port to listen on (default: 3847, env: PORT)
-s, --secret <string> Webhook secret (default: env WEBHOOK_SECRET)
-q, --quiet Suppress request logs
# Check status of running server
claude-webhook status [options]
-p, --port <number> Port to check (default: 3847)
-n, --limit <number> Executions to display (default: 10)| Variable | Description |
|---|---|
WEBHOOK_SECRET |
Shared secret for HMAC auth (required in production) |
PORT |
Default port (overridden by --port) |
Point an HTTP node at POST /run with:
{
"task": "{{ your task description }}",
"cwd": "/path/to/repo"
}Add header Authorization: Bearer <WEBHOOK_SECRET>.
/runuses Bearer token auth (timing-safe comparison)/webhook/githubuses HMAC-SHA256 (X-Hub-Signature-256)/webhook/slackuses Slack's HMAC-SHA256 + replay protection (5-minute window)- Without
WEBHOOK_SECRETset, auth is skipped — fine for local dev, not for production
bin/webhook.js CLI entrypoint
src/index.js Commander CLI (start / status commands)
src/server.js Native http server + routing
src/handlers.js Route handlers (/run, /webhook/github, /webhook/slack, /status)
src/executor.js Claude CLI execution via execFile + in-memory history
src/auth.js HMAC verification (GitHub, Slack, Bearer)
Zero runtime dependencies beyond chalk and commander. No Express.
MIT