Configuring HTTP Webhooks as Hooks in Claude Code: A Complete Guide
Claude Code supports HTTP webhooks as first-class hook types that POST JSON payloads to external URLs when specific tool events occur, enabling real-time integration with CI pipelines, monitoring dashboards, and custom validation services.
Claude Code's extensible hook system allows developers to trigger external services automatically during AI-assisted development workflows. According to the luongnv89/claude-howto repository, configuring HTTP webhooks as hooks in Claude Code requires understanding the JSON schema, security constraints like allowedEnvVars, and the event-driven architecture that routes these requests through the sandbox.
Understanding HTTP Hooks in Claude Code
What Are HTTP Hooks?
HTTP hooks are one of four supported hook types in Claude Code—alongside command, prompt, and agent hooks—that enable external service integration. Unlike command hooks that execute local scripts, HTTP hooks dispatch the same JSON payload via HTTPS POST to a remote endpoint you specify. As documented in 06-hooks/README.md, HTTP hooks were introduced in version 2.1.63 and are uniquely capable of calling out to remote services while respecting Claude Code's security boundaries.
Hook Types Comparison
- Command hooks: Execute local scripts and binaries on your machine
- Prompt hooks: Inject static or dynamic text into the conversation
- Agent hooks: Delegate to specialized sub-agents
- HTTP hooks: POST JSON payloads to external URLs for remote processing
HTTP Hook Configuration Schema
Required Fields
The JSON schema for an HTTP hook follows the same structure as command hooks but requires two additional fields. According to the source documentation in 06-hooks/README.md (lines 95-101), a minimal HTTP hook configuration requires:
{
"type": "http",
"url": "https://my-webhook.example.com/hook",
"matcher": "Write"
}
The matcher field supports exact strings, regex patterns, or wildcards to filter which tool events trigger the hook (e.g., Write, Bash, Read).
Optional Parameters
HTTP hooks support additional configuration for production deployments:
timeout: Integer value in seconds (default: 60 seconds)allowedEnvVars: Array of environment variable names permitted for interpolation in the URL
Security and Sandboxing
Environment Variable Interpolation
Because HTTP hook URLs often contain secrets like API tokens, Claude Code requires explicit authorization for environment variable substitution. As specified in 06-hooks/README.md (lines 88-110), you must declare any variables used in URL templates within the allowedEnvVars array; otherwise, the values are stripped to prevent accidental secret leakage.
Example with secure token interpolation:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "http",
"url": "https://ci.example.com/validate?token=${DEPLOY_TOKEN}",
"allowedEnvVars": ["DEPLOY_TOKEN"],
"timeout": 10
}
]
}
]
}
}
Set the variable in your shell environment (never commit it to the repository):
export DEPLOY_TOKEN=super-secret-token
Network Sandboxing Requirements
HTTP hooks are routed through the Claude Code sandbox when sandboxing is enabled, as noted in 06-hooks/README.md (lines 88-106). This means they cannot reach arbitrary external hosts unless you explicitly enable outbound networking. This security boundary protects against data exfiltration while allowing legitimate webhook integrations to proceed with proper configuration.
Event Flow and Architecture
The Five-Step Dispatch Process
When configuring HTTP webhooks as hooks in Claude Code, the system follows a strict event-driven pipeline:
- Event generation: Claude Code emits a hook event (e.g.,
PreToolUse,PostToolUse) - Matcher evaluation: The
matcherpattern compares against the tool name using exact, regex, or wildcard matching - Hook dispatch: The engine identifies the hook type from the
typefield - HTTP dispatch: The system serializes the hook input to JSON and POSTs it to the configured
url - Response handling: The JSON response merges back into the session context
Response Handling
The remote endpoint must return an HTTP 2xx status code; otherwise, Claude Code treats the hook as a non-blocking error. The response body must be valid JSON and can include the same control fields as command hooks:
continue: Boolean indicating whether to proceed with the tool executionsystemMessage: String message injected into the conversationhookSpecificOutput: Custom data passed back to the session
If the response contains "continue": false or a block decision, Claude Code can abort the tool execution or modify the transcript accordingly.
Practical Implementation Examples
Slack Notification Webhook
Configure a webhook that posts to a Slack-compatible endpoint after every successful Write operation. In your settings.json (project-local or user-wide):
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "http",
"url": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
"timeout": 30,
"allowedEnvVars": []
}
]
}
]
}
}
The payload sent to Slack contains the complete execution context:
{
"session_id": "abc123",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "src/app.py",
"content": "def foo():\n pass\n"
},
"agent_id": "main",
"cwd": "/home/user/project"
}
Secure API Token Integration
For hooks requiring authentication tokens, use environment variable interpolation with explicit allowlisting:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "http",
"url": "https://security.example.com/audit?token=${AUDIT_TOKEN}",
"allowedEnvVars": ["AUDIT_TOKEN"],
"timeout": 15
}
]
}
]
}
}
Local Validation Server
Create a Flask endpoint that validates commands before execution:
# webhook_server.py
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/hook", methods=["POST"])
def hook():
data = request.get_json()
# Block dangerous commands
if data["tool_name"] == "Bash" and "rm -rf" in data["tool_input"].get("command", ""):
return jsonify({
"continue": False,
"systemMessage": "Dangerous rm -rf command blocked by webhook"
}), 200
return jsonify({"continue": True})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
Configure Claude Code to use this local validator:
{
"type": "http",
"url": "http://localhost:5000/hook",
"matcher": "Bash"
}
Testing Your Configuration
Validate your HTTP hook implementation using curl to simulate Claude Code's POST request:
curl -X POST -H "Content-Type: application/json" \
-d '{"tool_name":"Bash","tool_input":{"command":"ls -la"}}' \
http://localhost:5000/hook
Key Source Files
The luongnv89/claude-howto repository provides comprehensive reference material for configuring HTTP webhooks:
06-hooks/README.md: Primary documentation for hook architecture, event lists, and the HTTP hook specification (lines 88-106 cover sandboxing, lines 95-101 show the minimal JSON schema)resources/DESIGN-SYSTEM.md: Design principles explaining why hooks are first-class extension points06-hooks/directory: Example command hook scripts that demonstrate payload formats adaptable for HTTP hook testing
Summary
- HTTP hooks are external webhooks that POST JSON payloads to remote URLs when Claude Code tool events fire, introduced in version 2.1.63.
- Configuration requires
type,url, andmatcherfields, with optionaltimeoutandallowedEnvVarsfor security. - Security constraints mandate explicit
allowedEnvVarsdeclarations for environment interpolation and sandboxed network access to prevent data exfiltration. - Responses must return HTTP 2xx status codes with JSON bodies containing optional
continue,systemMessage, orblockdirectives. - Architecture follows a five-step dispatch process from event generation through response merging into the session context.
Frequently Asked Questions
What JSON fields are required to configure an HTTP webhook in Claude Code?
The minimum configuration requires three fields: "type": "http", "url": "https://your-endpoint.com", and a "matcher" pattern to filter which tool events trigger the hook. Optional fields include "timeout" (default 60 seconds) and "allowedEnvVars" for secure environment variable interpolation. As shown in 06-hooks/README.md (lines 95-101), this schema matches command hooks but substitutes the local script path with a remote URL.
How do I pass environment variables securely to an HTTP hook?
You must explicitly list any environment variables in the allowedEnvVars array within your hook configuration. For example, if your URL contains ${API_TOKEN}, you must include "allowedEnvVars": ["API_TOKEN"] in the JSON. Claude Code strips unspecified environment variables from URLs to prevent accidental secret leakage, as documented in the security section of 06-hooks/README.md.
What happens if my HTTP webhook returns a non-2xx status code?
Claude Code treats non-2xx HTTP responses as non-blocking errors. The tool execution continues unless the hook is specifically configured to be blocking, but the hook's response content is discarded. To influence Claude Code's behavior (such as aborting a tool execution), your endpoint must return an HTTP 200, 201, or 204 status with a JSON body containing "continue": false or appropriate control directives.
Can HTTP hooks reach arbitrary external hosts when sandboxing is enabled?
No. When sandboxing is enabled, HTTP hooks are routed through the sandbox network context and cannot reach arbitrary external hosts unless you explicitly enable outbound networking. According to 06-hooks/README.md (lines 88-106), this restriction protects against data exfiltration while still allowing legitimate webhook integrations to proceed with proper user authorization and network configuration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →