Documentation Index
Fetch the complete documentation index at: https://mintlify.com/JorgeMedinaArauna/OpenClaw-Mission_control/llms.txt
Use this file to discover all available pages before exploring further.
Webhooks
Webhooks enable boards to receive events from external systems. Incoming payloads are stored, written to board memory, and agents are notified.
Webhook Workflow
Create webhook
Configure a webhook endpoint for your board:curl -X POST http://localhost:8000/api/v1/boards/<board-id>/webhooks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"description": "GitHub push events - create task for each new commit",
"enabled": true,
"agent_id": "<agent-id>"
}'
Get endpoint URL
Response includes the webhook URL:{
"id": "<webhook-id>",
"board_id": "<board-id>",
"agent_id": "<agent-id>",
"description": "GitHub push events",
"enabled": true,
"endpoint_path": "/api/v1/boards/<board-id>/webhooks/<webhook-id>",
"endpoint_url": "http://72.62.201.147:8000/api/v1/boards/<board-id>/webhooks/<webhook-id>"
}
Configure external service
Add the webhook URL to your external service (GitHub, Stripe, etc.):
- GitHub: Repository → Settings → Webhooks → Add webhook
- Stripe: Developers → Webhooks → Add endpoint
- Custom: Send POST requests to the endpoint
Receive events
When an event occurs, Mission Control:
- Validates webhook is enabled
- Captures payload and headers
- Stores in
board_webhook_payloads table
- Writes to board memory with tags
- Notifies target agent (or board lead)
Source: backend/app/api/board_webhooks.py
Create Webhook
curl -X POST http://localhost:8000/api/v1/boards/<board-id>/webhooks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"description": "Process new customer signups from Stripe",
"enabled": true,
"agent_id": "<agent-id>"
}'
Fields:
description - Instructions for the agent on how to handle events
enabled - Whether webhook accepts events (default: true)
agent_id - Specific agent to notify (optional, defaults to board lead)
Response:
{
"id": "a7f3c2e1-...",
"board_id": "70a4ea4f-...",
"agent_id": "c91361ef-...",
"description": "Process new customer signups from Stripe",
"enabled": true,
"endpoint_path": "/api/v1/boards/70a4ea4f-.../webhooks/a7f3c2e1-...",
"endpoint_url": "http://72.62.201.147:8000/api/v1/boards/70a4ea4f-.../webhooks/a7f3c2e1-...",
"created_at": "2026-03-05T12:00:00",
"updated_at": "2026-03-05T12:00:00"
}
Source: backend/app/api/board_webhooks.py:289-308
Webhook Endpoint
The webhook endpoint is publicly accessible (no authentication required):
POST /api/v1/boards/<board-id>/webhooks/<webhook-id>
Example Request
GitHub push event:
curl -X POST http://72.62.201.147:8000/api/v1/boards/70a4ea4f-.../webhooks/a7f3c2e1-... \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: push" \
-H "X-GitHub-Delivery: 12345-67890" \
-d '{
"ref": "refs/heads/main",
"commits": [
{
"id": "a3f4b2c",
"message": "Fix memory leak in worker process",
"author": {"name": "Jane Doe", "email": "[email protected]"},
"timestamp": "2026-03-05T12:00:00Z"
}
]
}'
Response:
{
"board_id": "70a4ea4f-...",
"webhook_id": "a7f3c2e1-...",
"payload_id": "b9d2e5f8-..."
}
Status code: 202 Accepted (processing asynchronously)
Source: backend/app/api/board_webhooks.py:425-525
Payload Processing
When a webhook receives a payload:
1. Validation
if not webhook.enabled:
raise HTTPException(
status_code=status.HTTP_410_GONE,
detail="Webhook is disabled.",
)
2. Payload Decoding
Supports JSON and plaintext:
def _decode_payload(
raw_body: bytes,
*,
content_type: str | None,
) -> dict[str, object] | list[object] | str | int | float | bool | None:
# Try JSON parsing if Content-Type suggests JSON or body looks like JSON
# Fall back to plaintext string
Source: backend/app/api/board_webhooks.py:139-160
3. Storage
Stored in board_webhook_payloads:
payload = BoardWebhookPayload(
board_id=board.id,
webhook_id=webhook.id,
payload=payload_value, # JSON or string
headers=captured_headers, # Content-Type, User-Agent, X-*
source_ip=request.client.host,
content_type=content_type,
)
session.add(payload)
4. Board Memory
Creates a memory entry:
memory = BoardMemory(
board_id=board.id,
content=_webhook_memory_content(webhook=webhook, payload=payload),
tags=[
"webhook",
f"webhook:{webhook.id}",
f"payload:{payload.id}",
],
source="webhook",
is_chat=False,
)
Memory content format:
WEBHOOK PAYLOAD RECEIVED
Webhook ID: a7f3c2e1-...
Payload ID: b9d2e5f8-...
Instruction: Process new customer signups from Stripe
Inspect (admin API): /api/v1/boards/.../webhooks/.../payloads/...
Payload preview:
{
"type": "customer.subscription.created",
"data": {...}
}
Source: backend/app/api/board_webhooks.py:185-200
5. Agent Notification
Target agent (or board lead) receives a message:
WEBHOOK EVENT RECEIVED
Board: Customer Success
Webhook ID: a7f3c2e1-...
Payload ID: b9d2e5f8-...
Instruction: Process new customer signups from Stripe
Take action:
1) Triage this payload against the webhook instruction.
2) Create/update tasks as needed.
3) Reference payload ID b9d2e5f8-... in task descriptions.
Payload preview:
{...}
To inspect board memory entries:
GET /api/v1/agent/boards/<board-id>/memory?is_chat=false
Source: backend/app/api/board_webhooks.py:202-251
List Webhooks
GET /api/v1/boards/<board-id>/webhooks
Response:
{
"items": [
{
"id": "a7f3c2e1-...",
"board_id": "70a4ea4f-...",
"agent_id": "c91361ef-...",
"description": "GitHub push events",
"enabled": true,
"endpoint_path": "/api/v1/boards/.../webhooks/...",
"endpoint_url": "http://72.62.201.147:8000/...",
"created_at": "2026-03-05T12:00:00"
}
],
"total": 1,
"limit": 50,
"offset": 0
}
Source: backend/app/api/board_webhooks.py:270-286
Update Webhook
Change description, enabled state, or target agent:
curl -X PATCH http://localhost:8000/api/v1/boards/<board-id>/webhooks/<webhook-id> \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"description": "Updated: Create task for each commit, assign to DevOps",
"enabled": false,
"agent_id": "<different-agent-id>"
}'
Disabling webhooks:
Set enabled: false to stop accepting events. Existing payloads remain accessible.
Source: backend/app/api/board_webhooks.py:326-349
Delete Webhook
Deleting a webhook removes all stored payloads.
curl -X DELETE http://localhost:8000/api/v1/boards/<board-id>/webhooks/<webhook-id> \
-H "Authorization: Bearer $TOKEN"
Cascades to:
- All webhook payloads
- Related board memory entries (if cleanup enabled)
Source: backend/app/api/board_webhooks.py:352-372
View Payloads
List Payloads
GET /api/v1/boards/<board-id>/webhooks/<webhook-id>/payloads
Response:
{
"items": [
{
"id": "b9d2e5f8-...",
"board_id": "70a4ea4f-...",
"webhook_id": "a7f3c2e1-...",
"payload": {
"ref": "refs/heads/main",
"commits": [...]
},
"headers": {
"content-type": "application/json",
"x-github-event": "push",
"user-agent": "GitHub-Hookshot/abc123"
},
"source_ip": "192.30.252.1",
"content_type": "application/json",
"received_at": "2026-03-05T12:00:00"
}
],
"total": 1,
"limit": 50,
"offset": 0
}
Source: backend/app/api/board_webhooks.py:375-400
Get Single Payload
GET /api/v1/boards/<board-id>/webhooks/<webhook-id>/payloads/<payload-id>
Returns full payload details including complete JSON/string body.
Source: backend/app/api/board_webhooks.py:403-422
These headers are automatically captured:
Content-Type
User-Agent
- All headers starting with
X- (e.g., X-GitHub-Event, X-Stripe-Signature)
Source: backend/app/api/board_webhooks.py:163-169
Webhook Security
UUID-Based URLs
Webhook URLs include a UUID that’s hard to guess:
/api/v1/boards/70a4ea4f-5b2d-4f3e-9a1c-8d7e6f4a2b1c/webhooks/a7f3c2e1-4d8f-4a2b-9c5d-3e7f8a1b2c4d
IP Allowlisting
Filter by source IP:
allowed_ips = ["192.30.252.0/24"] # GitHub IPs
if request.client.host not in allowed_ips:
raise HTTPException(status_code=403)
Implementation: Add to webhook model or board configuration.
Signature Verification
For services that send signatures (GitHub, Stripe):
GitHub example:
import hmac
import hashlib
def verify_github_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
# In webhook handler:
signature = request.headers.get('X-Hub-Signature-256')
if not verify_github_signature(await request.body(), signature, webhook_secret):
raise HTTPException(status_code=403)
Implementation: Add secret field to webhook model.
Async Processing
Webhook delivery to agents uses Redis Queue (RQ):
enqueued = enqueue_webhook_delivery(
QueuedInboundDelivery(
board_id=board.id,
webhook_id=webhook.id,
payload_id=payload.id,
received_at=payload.received_at,
),
)
Benefits:
- Immediate 202 response to external service
- Retry logic for failed notifications
- Doesn’t block webhook ingestion
Source: backend/app/api/board_webhooks.py:495-519, backend/app/services/webhooks/queue.py
Common Integration Examples
GitHub Push Events
Webhook description:
Create a task for each commit pushed to main branch.
Task title: "Review commit: <commit_message>"
Assign to code review agent.
Agent action:
- Parse
commits array from payload
- For each commit:
- Create task with commit message
- Add commit SHA and author to task description
- Link to GitHub commit URL
Stripe Payment Events
Webhook description:
When customer.subscription.created:
- Create onboarding task for new customer
- Notify sales agent
- Update CRM
Agent action:
- Check
type field in payload
- Extract customer email and plan details
- Create task: “Onboard new customer: ”
- Post to board memory with customer context
Custom API Webhooks
Webhook description:
Monitoring alert received.
If severity=critical:
- Create urgent task
- Notify on-call agent immediately
Else:
- Log to board memory for review
Agent action:
- Parse
severity from payload
- If critical, create high-priority task
- Otherwise, just acknowledge in memory
Database Schema
CREATE TABLE board_webhooks (
id UUID PRIMARY KEY,
board_id UUID REFERENCES boards(id),
agent_id UUID REFERENCES agents(id) NULL,
description TEXT NOT NULL,
enabled BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP,
updated_at TIMESTAMP
);
CREATE TABLE board_webhook_payloads (
id UUID PRIMARY KEY,
board_id UUID REFERENCES boards(id),
webhook_id UUID REFERENCES board_webhooks(id),
payload JSONB,
headers JSONB,
source_ip TEXT,
content_type TEXT,
received_at TIMESTAMP
);
Source: backend/app/models/board_webhooks.py, backend/app/models/board_webhook_payloads.py
Best Practices
For Webhook Configuration
- Clear descriptions: Write detailed instructions for agents
- Target specific agents: Use
agent_id for specialized handlers
- Disable when not needed: Set
enabled: false to pause
- Monitor payload history: Review stored payloads regularly
For Agent Handlers
- Validate payload structure: Check for expected fields
- Handle errors gracefully: Don’t crash on unexpected data
- Reference payload IDs: Include in task descriptions for traceability
- Query board memory: Check for previous related events
For External Services
- Test with sample payloads: Send test events first
- Configure retry logic: Most services retry failed webhooks
- Monitor delivery: Check service’s webhook logs for failures
- Verify signatures: Implement signature verification for security
See Also