Webhooks
Webhooks allow you to receive real-time notifications when events occur in ClawBook. Instead of polling the API, configure a webhook URL and ClawBook will send HTTP POST requests to your server.
Setting Up Webhooks
Via Dashboard
- Go to Settings → API → Webhooks
- Click Add Webhook
- Enter your endpoint URL
- Select events to subscribe to
- Click Create
Via API
curl -X POST "https://your-domain.com/api/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhook",
"events": ["message.received", "message.sent", "integration.disconnected"],
"secret": "your-webhook-secret"
}'
Webhook Events
Message Events
| Event | Description |
|---|---|
message.received | New inbound message received |
message.sent | Outbound message sent |
message.delivered | Message delivery confirmed |
message.failed | Message delivery failed |
Integration Events
| Event | Description |
|---|---|
integration.connected | Platform connected |
integration.disconnected | Platform disconnected |
integration.error | Integration error occurred |
AI Events
| Event | Description |
|---|---|
ai.request | AI request sent |
ai.response | AI response received |
ai.error | AI provider error |
ai.rate_limited | Rate limit hit |
System Events
| Event | Description |
|---|---|
system.health | Health status change |
backup.completed | Backup finished |
backup.failed | Backup failed |
Webhook Payload
All webhooks follow this structure:
{
"id": "evt_abc123",
"type": "message.received",
"created_at": "2026-01-30T14:30:00Z",
"data": {
// Event-specific data
}
}
Example: message.received
{
"id": "evt_abc123",
"type": "message.received",
"created_at": "2026-01-30T14:30:00Z",
"data": {
"message_id": "msg_xyz789",
"conversation_id": "conv_abc456",
"platform": "telegram",
"sender": {
"id": "123456789",
"name": "John Doe",
"username": "@johndoe"
},
"content": "Hello, how are you?",
"timestamp": "2026-01-30T14:29:58Z"
}
}
Example: message.sent
{
"id": "evt_def456",
"type": "message.sent",
"created_at": "2026-01-30T14:30:02Z",
"data": {
"message_id": "msg_response123",
"conversation_id": "conv_abc456",
"platform": "telegram",
"recipient": {
"id": "123456789",
"name": "John Doe"
},
"content": "I'm doing well, thank you for asking!",
"ai_model": "claude-3-5-sonnet",
"tokens": {
"input": 45,
"output": 15
},
"latency_ms": 1250
}
}
Example: integration.disconnected
{
"id": "evt_ghi789",
"type": "integration.disconnected",
"created_at": "2026-01-30T14:35:00Z",
"data": {
"platform": "whatsapp",
"reason": "Phone went offline",
"last_connected_at": "2026-01-30T12:00:00Z",
"auto_reconnect": true
}
}
Webhook Security
Verifying Signatures
All webhooks include a signature header for verification:
X-ClawBook-Signature: sha256=abc123...
Verify in your code:
Node.js:
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return `sha256=${expected}` === signature;
}
// In your handler
app.post('/webhook', (req, res) => {
const signature = req.headers['x-clawbook-signature'];
const payload = JSON.stringify(req.body);
if (!verifySignature(payload, signature, 'your-webhook-secret')) {
return res.status(401).send('Invalid signature');
}
// Process webhook
console.log('Event:', req.body.type);
res.status(200).send('OK');
});
Python:
import hmac
import hashlib
def verify_signature(payload, signature, secret):
expected = hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
return f"sha256={expected}" == signature
# In your handler
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-ClawBook-Signature')
payload = request.get_data(as_text=True)
if not verify_signature(payload, signature, 'your-webhook-secret'):
return 'Invalid signature', 401
event = request.json
print(f"Event: {event['type']}")
return 'OK', 200
PHP:
function verifySignature($payload, $signature, $secret) {
$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);
return hash_equals($expected, $signature);
}
// In your handler
$signature = $_SERVER['HTTP_X_CLAWBOOK_SIGNATURE'];
$payload = file_get_contents('php://input');
if (!verifySignature($payload, $signature, 'your-webhook-secret')) {
http_response_code(401);
exit('Invalid signature');
}
$event = json_decode($payload, true);
error_log("Event: " . $event['type']);
http_response_code(200);
IP Allowlisting
ClawBook webhooks come from these IP ranges:
203.0.113.0/24
198.51.100.0/24
Configure your firewall to only accept webhook requests from these IPs.
Webhook Delivery
Retry Policy
Failed webhooks are retried with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry | 12 hours |
After 5 failures, the webhook is marked as failed and you'll receive an email notification.
Expected Response
Your endpoint should:
- Return
200 OKwithin 30 seconds - Return
2xxstatus codes for success - Return
4xxfor permanent failures (won't retry) - Return
5xxfor temporary failures (will retry)
Timeout
Webhooks timeout after 30 seconds. For long-running tasks:
- Return
200 OKimmediately - Process asynchronously
- Use the API to acknowledge later if needed
Managing Webhooks
List Webhooks
curl "https://your-domain.com/api/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY"
Get Webhook Details
curl "https://your-domain.com/api/v1/webhooks/wh_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"
Response includes recent delivery attempts:
{
"id": "wh_abc123",
"url": "https://your-server.com/webhook",
"events": ["message.received", "message.sent"],
"status": "active",
"recent_deliveries": [
{
"id": "del_xyz789",
"event_id": "evt_abc123",
"status": "success",
"response_code": 200,
"response_time_ms": 150,
"timestamp": "2026-01-30T14:30:00Z"
}
]
}
Update Webhook
curl -X PATCH "https://your-domain.com/api/v1/webhooks/wh_abc123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": ["message.received"],
"enabled": true
}'
Delete Webhook
curl -X DELETE "https://your-domain.com/api/v1/webhooks/wh_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"
Test Webhook
Send a test event to your endpoint:
curl -X POST "https://your-domain.com/api/v1/webhooks/wh_abc123/test" \
-H "Authorization: Bearer YOUR_API_KEY"
Webhook Logs
View delivery logs in dashboard:
Settings → API → Webhooks → Select webhook → Delivery Logs
Or via API:
curl "https://your-domain.com/api/v1/webhooks/wh_abc123/deliveries" \
-H "Authorization: Bearer YOUR_API_KEY"
Best Practices
- Always verify signatures - Prevent spoofed requests
- Respond quickly - Return 200 before processing
- Handle duplicates - Use event IDs for idempotency
- Monitor delivery - Check for failed deliveries
- Use HTTPS - Secure your endpoint
- Implement retry logic - In case you miss events
Example: Full Webhook Handler
Node.js/Express:
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.CLAWBOOK_WEBHOOK_SECRET;
const processedEvents = new Set();
function verifySignature(payload, signature) {
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');
return `sha256=${expected}` === signature;
}
app.post('/webhook/clawbook', (req, res) => {
// Verify signature
const signature = req.headers['x-clawbook-signature'];
if (!verifySignature(JSON.stringify(req.body), signature)) {
return res.status(401).send('Invalid signature');
}
const event = req.body;
// Idempotency check
if (processedEvents.has(event.id)) {
return res.status(200).send('Already processed');
}
processedEvents.add(event.id);
// Return immediately
res.status(200).send('OK');
// Process asynchronously
processEvent(event).catch(console.error);
});
async function processEvent(event) {
switch (event.type) {
case 'message.received':
console.log('New message from:', event.data.sender.name);
// Your logic here
break;
case 'integration.disconnected':
console.log('Platform disconnected:', event.data.platform);
// Send alert
break;
default:
console.log('Unhandled event:', event.type);
}
}
app.listen(3000);
Next Steps
- Authentication - Secure your API access
- Endpoints - Full API reference
- Troubleshooting - Fix issues