Skip to main content

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

1

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>"
  }'
2

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>"
}
3

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
4

Receive events

When an event occurs, Mission Control:
  1. Validates webhook is enabled
  2. Captures payload and headers
  3. Stores in board_webhook_payloads table
  4. Writes to board memory with tags
  5. 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

Captured Headers

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:
  1. Parse commits array from payload
  2. 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:
  1. Check type field in payload
  2. Extract customer email and plan details
  3. Create task: “Onboard new customer:
  4. 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:
  1. Parse severity from payload
  2. If critical, create high-priority task
  3. 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

  1. Clear descriptions: Write detailed instructions for agents
  2. Target specific agents: Use agent_id for specialized handlers
  3. Disable when not needed: Set enabled: false to pause
  4. Monitor payload history: Review stored payloads regularly

For Agent Handlers

  1. Validate payload structure: Check for expected fields
  2. Handle errors gracefully: Don’t crash on unexpected data
  3. Reference payload IDs: Include in task descriptions for traceability
  4. Query board memory: Check for previous related events

For External Services

  1. Test with sample payloads: Send test events first
  2. Configure retry logic: Most services retry failed webhooks
  3. Monitor delivery: Check service’s webhook logs for failures
  4. Verify signatures: Implement signature verification for security

See Also

Build docs developers (and LLMs) love