Documentation Index
Fetch the complete documentation index at: https://mintlify.com/nearai/ironclaw/llms.txt
Use this file to discover all available pages before exploring further.
The HTTP webhook channel provides a simple REST API for sending messages to IronClaw and receiving responses.
Features
- JSON API - Simple POST requests with JSON payloads
- Webhook secret - HMAC-based authentication
- Synchronous responses - Optional wait for agent reply
- Thread support - Conversation continuity via
thread_id
- Rate limiting - 60 requests/minute
- Fixed user ID - Single user per channel instance
Configuration
Set via environment variables or .env file:
# HTTP server host and port
HTTP_HOST=0.0.0.0
HTTP_PORT=8080
# Required: Webhook secret for authentication
HTTP_WEBHOOK_SECRET=your-webhook-secret
Configuration Options
| Variable | Type | Default | Description |
|---|
HTTP_HOST | string | "0.0.0.0" | Bind address |
HTTP_PORT | integer | 8080 | HTTP port |
HTTP_WEBHOOK_SECRET | string | required | Secret for request authentication |
Endpoints
Health Check
Response:
{
"status": "healthy",
"channel": "http"
}
Send Message (Async)
POST /webhook
Content-Type: application/json
{
"content": "Hello, agent!",
"secret": "your-webhook-secret"
}
Response (202 Accepted):
{
"message_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "accepted"
}
The agent processes the message asynchronously. Listen for responses via SSE or WebSocket (Web Gateway channel).
Send Message (Sync)
POST /webhook
Content-Type: application/json
{
"content": "What is 2+2?",
"secret": "your-webhook-secret",
"wait_for_response": true
}
Response (200 OK):
{
"message_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "accepted",
"response": "2 + 2 equals 4."
}
The request blocks (up to 60 seconds) until the agent responds.
Thread Support
POST /webhook
Content-Type: application/json
{
"content": "Continue the conversation",
"thread_id": "thread-123",
"secret": "your-webhook-secret"
}
Messages with the same thread_id are tracked as a single conversation. The agent loads conversation history when a matching thread is found.
Request Schema
interface WebhookRequest {
// Message content (required)
content: string;
// Webhook secret (required)
secret: string;
// Optional thread ID for conversation tracking
thread_id?: string;
// Wait for synchronous response (default: false)
wait_for_response?: boolean;
// User ID (ignored, fixed by server config)
user_id?: string;
}
Response Schema
interface WebhookResponse {
// Assigned message ID
message_id: string;
// Status: "accepted" or "error"
status: string;
// Response content (only if wait_for_response was true)
response?: string;
}
Error Responses
401 Unauthorized - Invalid Secret
{
"message_id": "00000000-0000-0000-0000-000000000000",
"status": "error",
"response": "Invalid webhook secret"
}
401 Unauthorized - Missing Secret
{
"message_id": "00000000-0000-0000-0000-000000000000",
"status": "error",
"response": "Webhook secret required"
}
413 Payload Too Large
{
"message_id": "00000000-0000-0000-0000-000000000000",
"status": "error",
"response": "Content too large"
}
Limits:
- Max body size: 64 KB
- Max content length: 32 KB
429 Too Many Requests
{
"message_id": "00000000-0000-0000-0000-000000000000",
"status": "error",
"response": "Rate limit exceeded"
}
Rate limits:
- 60 requests per minute
- 100 pending wait-for-response requests
503 Service Unavailable
{
"message_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "error",
"response": "Channel not started"
}
The channel hasn’t been initialized yet. Wait for IronClaw to start.
Security
Webhook Secret
The webhook secret is required and validated using constant-time comparison to prevent timing attacks:
use subtle::ConstantTimeEq;
if !provided.as_bytes().ct_eq(expected.as_bytes()).into() {
return Err("Invalid secret");
}
Fixed User ID
Each HTTP channel instance has a fixed user_id from config. The user_id field in requests is ignored:
let msg = IncomingMessage::new("http", &self.config.user_id, &req.content);
This prevents impersonation attacks.
Rate Limiting
The channel enforces a sliding window rate limit:
- 60 requests/minute - Resets every 60 seconds
- 100 pending sync requests - Prevents resource exhaustion
Exceeding these returns HTTP 429.
Integration Examples
cURL
curl -X POST http://localhost:8080/webhook \
-H "Content-Type: application/json" \
-d '{
"content": "Hello from cURL",
"secret": "your-webhook-secret"
}'
Python
import requests
response = requests.post(
"http://localhost:8080/webhook",
json={
"content": "Hello from Python",
"secret": "your-webhook-secret",
"wait_for_response": True
}
)
print(response.json()["response"])
JavaScript (Node.js)
const fetch = require('node-fetch');
const response = await fetch('http://localhost:8080/webhook', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
content: 'Hello from Node.js',
secret: 'your-webhook-secret',
wait_for_response: true
})
});
const data = await response.json();
console.log(data.response);
Bash Script
#!/bin/bash
SECRET="your-webhook-secret"
URL="http://localhost:8080/webhook"
send_message() {
local content="$1"
curl -s -X POST "$URL" \
-H "Content-Type: application/json" \
-d "{
\"content\": \"$content\",
\"secret\": \"$SECRET\",
\"wait_for_response\": true
}" | jq -r '.response'
}
# Usage
send_message "What is the weather in Tokyo?"
Use Cases
CI/CD Integration
Notify the agent when builds fail:
# .github/workflows/ci.yml
steps:
- name: Notify IronClaw on failure
if: failure()
run: |
curl -X POST http://ironclaw.internal:8080/webhook \
-H "Content-Type: application/json" \
-d '{
"content": "Build failed: ${{ github.repository }}#${{ github.run_number }}",
"secret": "${{ secrets.IRONCLAW_SECRET }}"
}'
Monitoring Alerts
Forward alerts from monitoring systems:
# Prometheus Alertmanager webhook receiver
from flask import Flask, request
import requests
app = Flask(__name__)
@app.route('/alertmanager', methods=['POST'])
def alertmanager():
alerts = request.json['alerts']
for alert in alerts:
requests.post('http://localhost:8080/webhook', json={
'content': f"Alert: {alert['labels']['alertname']} - {alert['annotations']['summary']}",
'secret': 'your-webhook-secret'
})
return '', 200
Slack Slash Commands
Bridge Slack slash commands to IronClaw:
# Slack slash command webhook
from flask import Flask, request
import requests
app = Flask(__name__)
@app.route('/slack/ironclaw', methods=['POST'])
def slack_command():
text = request.form['text']
response = requests.post('http://localhost:8080/webhook', json={
'content': text,
'secret': 'your-webhook-secret',
'wait_for_response': True
})
return response.json()['response']
Chatbot Gateway
Proxy multiple chat platforms through the HTTP channel:
# Multi-platform chatbot
import requests
def send_to_ironclaw(message, platform, user_id):
response = requests.post('http://localhost:8080/webhook', json={
'content': f"[{platform}:{user_id}] {message}",
'secret': 'your-webhook-secret',
'wait_for_response': True,
'thread_id': f"{platform}-{user_id}"
})
return response.json()['response']
# Usage
reply = send_to_ironclaw("Hello", "discord", "user123")
print(reply)
Source Code
- Implementation:
~/workspace/source/src/channels/http.rs
- Tests:
~/workspace/source/src/channels/http.rs:359-445
Troubleshooting
401 Unauthorized
- Verify
HTTP_WEBHOOK_SECRET matches the secret in requests
- Check for typos in the secret value
- Ensure the secret is set before starting IronClaw
503 Service Unavailable
- Wait for IronClaw to fully start
- Check logs for “HTTP channel ready”
- Verify
HTTP_PORT is correct
429 Too Many Requests
- Reduce request frequency to less than 60/minute
- Implement exponential backoff in client
- Close stale wait-for-response requests
Timeout on wait_for_response
- Requests timeout after 60 seconds
- Complex queries may exceed this; use async mode instead
- Check agent logs for errors during processing
Empty response field
response field is only present when wait_for_response: true
- For async requests, use Web Gateway SSE or WebSocket to receive responses