> ## Documentation Index
> Fetch the complete documentation index at: https://docs.emergence.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks (Planned)

> Event-driven webhook delivery with HMAC signing, retry logic, and SSRF protection for CRAFT.

# Webhooks

Webhooks enable event-driven communication between CRAFT and external systems. When a platform event occurs (such as a schedule trigger, agent completion, or data connection status change), the webhook system delivers a signed HTTP POST request to a configured endpoint.

<Warning>
  **Coming Soon**, The webhook system described on this page is planned but not yet implemented. This page documents the target architecture and capabilities for an upcoming release. Do not build integrations against these APIs until this warning is removed.
</Warning>

## Architecture

The webhook system follows a publish-subscribe pattern built on **Redis Streams**, consistent with the platform's infrastructure-agnostic design:

```mermaid theme={null}
%%{init: {'theme': 'base', 'themeVariables': {'lineColor': '#555555', 'fontFamily': 'sans-serif', 'edgeLabelBackground': '#ffffff'}}}%%
flowchart TD
    E["Platform Event"]
    RS["Redis Streams<br/>(event bus)"]
    WD["Webhook Dispatcher<br/>HMAC sign → Deliver → Record → Retry"]
    EX["External System"]

    E --> RS --> WD --> EX

    classDef event fill:#56B4E9,stroke:#555555,color:#000
    classDef infra fill:#0072B2,stroke:#555555,color:#fff
    classDef proc fill:#E69F00,stroke:#555555,color:#000
    classDef ext fill:#CC79A7,stroke:#555555,color:#000
    class E event
    class RS infra
    class WD proc
    class EX ext
```

<Info>
  Redis Streams is used instead of cloud-specific message brokers (SQS, Pub/Sub) to avoid cloud-specific dependencies. Redis is already part of the infrastructure stack, so no additional dependencies are required.
</Info>

## Security

### HMAC Payload Signing

Every webhook delivery includes an HMAC-SHA256 signature in the request headers, allowing receivers to verify that the payload was sent by the platform and has not been tampered with:

```http theme={null}
POST /webhook-endpoint HTTP/1.1
Content-Type: application/json
X-Webhook-Signature: sha256=a1b2c3d4e5f6...
X-Webhook-Timestamp: 1743696000
X-Webhook-Event: schedule.triggered

{...payload...}
```

Receivers should:

1. Extract the timestamp and signature from headers
2. Reconstruct the signed payload: `{timestamp}.{body}`
3. Compute HMAC-SHA256 using the shared secret
4. Compare the computed signature with the received one (constant-time comparison)
5. Reject payloads older than a configurable tolerance window (e.g., 5 minutes) to prevent replay attacks

### SSRF Protection

The webhook dispatcher includes protection against Server-Side Request Forgery (SSRF):

* Private/internal IP ranges are blocked by default (10.x.x.x, 172.16-31.x.x, 192.168.x.x, 127.x.x.x)
* DNS resolution is validated before delivery
* Redirect following is disabled or limited to prevent redirect-based SSRF

## Retry Logic

Failed webhook deliveries are retried with exponential backoff:

| Attempt   | Delay      | Cumulative   |
| --------- | ---------- | ------------ |
| 1st retry | 1 minute   | 1 minute     |
| 2nd retry | 5 minutes  | 6 minutes    |
| 3rd retry | 30 minutes | 36 minutes   |
| 4th retry | 2 hours    | \~2.5 hours  |
| 5th retry | 12 hours   | \~14.5 hours |

A delivery is considered successful when the receiver responds with a 2xx status code. After all retries are exhausted, the delivery is marked as failed and recorded in the delivery log.

## Event Types

The platform plans to support webhook notifications for the following event categories:

| Category             | Events                                                            | Description                                                 |
| -------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------- |
| **Schedules**        | `schedule.triggered`, `schedule.failed`                           | Schedule execution events                                   |
| **Agents**           | `agent.registered`, `agent.health_changed`                        | Agent lifecycle events                                      |
| **Assets**           | `asset.created`, `asset.updated`, `asset.deleted`                 | Asset lifecycle events (files, artifacts, data connections) |
| **Governance**       | `organization.created`, `organization.deleted`, `project.created` | Tenant-boundary events                                      |
| **Data Connections** | `connection.status_changed`, `connection.verified`                | Connection state changes                                    |
| **Deployments**      | `deployment.started`, `deployment.completed`, `deployment.failed` | Deployment lifecycle                                        |

## Webhook Payload Structure

Webhook payloads follow a consistent envelope format:

```json theme={null}
{
  "id": "evt-a1b2c3d4",
  "type": "schedule.triggered",
  "timestamp": "2026-04-03T06:00:00Z",
  "organization_id": "acme-corp",
  "project_id": "analytics-prod",
  "data": {
    "schedule_id": "sch-x1y2z3",
    "schedule_name": "Daily Analytics Refresh",
    "run_id": "run-m1n2o3"
  }
}
```

| Field             | Description                         |
| ----------------- | ----------------------------------- |
| `id`              | Unique event ID for idempotency     |
| `type`            | Event type identifier               |
| `timestamp`       | ISO 8601 UTC timestamp of the event |
| `organization_id` | Organization that owns the resource |
| `project_id`      | Project scope (if applicable)       |
| `data`            | Event-specific payload              |

<Tip>
  Use the event `id` field for idempotency. If you receive the same event ID multiple times (due to retries), process it only once.
</Tip>

## Multi-Tenancy

Webhooks are scoped to organizations and optionally to projects, following the same isolation model as all platform resources:

* Webhook configurations are owned by an organization and optionally scoped to a project
* Events are only delivered for resources within the webhook's scope
* Webhook secrets (for HMAC signing) are stored via the Governance Secrets API

## Next Steps

<CardGroup cols={2}>
  <Card title="Schedules" icon="clock" href="/platform/schedules">
    Configure time-based triggers that generate webhook events.
  </Card>

  <Card title="Agent Registry" icon="robot" href="/platform/agents">
    Monitor agent lifecycle events via webhooks.
  </Card>

  <Card title="Data Connections" icon="database" href="/platform/data-connections">
    Receive notifications when connection status changes.
  </Card>

  <Card title="Authentication" icon="lock" href="/platform/authentication">
    Understand how webhook endpoints authenticate with the platform.
  </Card>
</CardGroup>
