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

# Webhooks API: Real-Time Notifications and Signatures

> Register webhook endpoints to receive real-time notifications when sessions complete, critical patterns are detected, or agent health scores change.

Webhooks let Agent Therapy push event notifications to your infrastructure the moment something significant happens — no polling required. When a subscribed event fires, Agent Therapy sends an HTTP POST request to the URL you register, with a JSON body describing the event. Use webhooks to trigger downstream workflows: escalating a critical finding to your on-call channel, automatically applying a pre-configured intervention, or updating your internal observability dashboard.

> [!TIP]
>
> Return a `2xx` response to Agent Therapy as quickly as possible — ideally within 5 seconds — and process the event asynchronously in a background job or queue. If your endpoint does not respond with a `2xx` status within the timeout window, Agent Therapy will retry the delivery up to **3 times** with exponential backoff (10 s, 30 s, 90 s).

## Supported Events

| Event | Description |
| - | - |
| `session.completed` | A diagnostic session finished processing and a full report is available |
| `session.failed` | A diagnostic session failed to complete due to an analysis error |
| `finding.critical` | A session or diagnostic produced at least one finding with `severity: critical` |
| `health_score.threshold_breached` | An agent's rolling health score dropped below your configured alert threshold |
| `intervention.applied` | An intervention was successfully applied to an agent |

## Registering a Webhook

### POST /webhooks

Register a new webhook endpoint and subscribe it to one or more events.

#### Request Body

**url** `string` *required*

The HTTPS URL that Agent Therapy should POST event payloads to. Must be publicly reachable and respond with a `2xx` status. HTTP (non-TLS) URLs are not accepted.

**events** `array` *required*

An array of event name strings to subscribe to. You must subscribe to at least one event. Use `["*"]` to subscribe to all current and future events. Valid values: `session.completed`, `session.failed`, `finding.critical`, `health_score.threshold_breached`, `intervention.applied`.

**secret** `string`

An optional secret string used to sign webhook payloads with HMAC-SHA256. Strongly recommended for production endpoints. If provided, every request will include an `X-AgentTherapy-Signature` header you can use to verify authenticity. See [Verifying Webhook Signatures](#verifying-webhook-signatures) for details.

#### Response Fields

**id** `string`

The unique identifier for this webhook registration. Prefixed with `wh_`.

**url** `string`

The destination URL that was registered.

**events** `array`

The list of events this webhook is subscribed to.

**status** `string`

The webhook's current status: `active` or `inactive`.

**created\_at** `string`

ISO 8601 timestamp indicating when the webhook was registered.

#### Example

```bash theme={null}
curl -X POST https://api.agenttherapy.ai/v1/webhooks \
  -H "Authorization: Bearer at_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.yourdomain.com/agent-therapy",
    "events": ["session.completed", "finding.critical"],
    "secret": "whsec_your_signing_secret_here"
  }'
```

```json theme={null}
{
  "data": {
    "id": "wh_11t3d4uc2w5x8a6b",
    "url": "https://hooks.yourdomain.com/agent-therapy",
    "events": ["session.completed", "finding.critical"],
    "status": "active",
    "created_at": "2024-11-14T14:00:00Z"
  }
}
```

## Webhook Payload Format

When an event fires, Agent Therapy POSTs a JSON payload to your registered URL. Every payload follows the same envelope structure:

```json theme={null}
{
  "event": "session.completed",
  "timestamp": "2024-11-14T10:00:41Z",
  "data": {
    "id": "sess_04m6w7nv5p8q1t9u",
    "agent_id": "agt_01j9z3kx2m4n8p7q",
    "status": "completed",
    "health_score": 76,
    "findings": [
      {
        "id": "fnd_05n7x8ow6q9r2u0v",
        "pattern": "sycophancy",
        "severity": "medium",
        "confidence": 0.82
      }
    ],
    "completed_at": "2024-11-14T10:00:41Z"
  }
}
```

| Field | Type | Description |
| - | - | - |
| `event` | string | The name of the event that fired |
| `timestamp` | string | ISO 8601 UTC timestamp of when the event occurred |
| `data` | object | The resource snapshot relevant to the event. For session events, this is the session object. For `intervention.applied`, this is the intervention object. |

## Verifying Webhook Signatures

If you provided a `secret` when registering your webhook, Agent Therapy signs each payload with HMAC-SHA256 and includes the signature in the `X-AgentTherapy-Signature` header. Always verify this signature before processing the event to ensure the payload came from Agent Therapy and was not tampered with.

The signature is computed as:

```
HMAC-SHA256(secret, raw_request_body)
```

The header value is prefixed with `sha256=`:

```
X-AgentTherapy-Signature: sha256=a3f1b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2
```

Here is a Python example showing how to verify the signature in a Flask webhook handler:

```python theme={null}
import hashlib
import hmac
from flask import Flask, request, abort

app = Flask(__name__)

WEBHOOK_SECRET = "whsec_your_signing_secret_here"


def verify_signature(payload_body: bytes, signature_header: str) -> bool:
    """Return True if the payload signature matches the expected HMAC-SHA256."""
    if not signature_header or not signature_header.startswith("sha256="):
        return False

    received_sig = signature_header[len("sha256="):]
    expected_sig = hmac.new(
        key=WEBHOOK_SECRET.encode("utf-8"),
        msg=payload_body,
        digestmod=hashlib.sha256,
    ).hexdigest()

    # Use compare_digest to prevent timing attacks
    return hmac.compare_digest(received_sig, expected_sig)


@app.route("/agent-therapy", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-AgentTherapy-Signature", "")
    raw_body = request.get_data()

    if not verify_signature(raw_body, signature):
        abort(403, "Invalid webhook signature")

    event = request.get_json()

    # Acknowledge receipt immediately, then process asynchronously
    process_event_async(event)
    return "", 200


def process_event_async(event: dict):
    # Enqueue the event to your task queue (Celery, RQ, etc.)
    pass
```

> [!WARNING]
>
> Always use `hmac.compare_digest` (or an equivalent constant-time comparison) when validating signatures. A standard string comparison (`==`) is vulnerable to timing attacks that can allow an attacker to forge a valid signature.

## Managing Webhooks

### GET /webhooks

List all webhook registrations for your account.

```bash theme={null}
curl https://api.agenttherapy.ai/v1/webhooks \
  -H "Authorization: Bearer at_your_key_here"
```

```json theme={null}
{
  "data": [
    {
      "id": "wh_11t3d4uc2w5x8a6b",
      "url": "https://hooks.yourdomain.com/agent-therapy",
      "events": ["session.completed", "finding.critical"],
      "status": "active",
      "created_at": "2024-11-14T14:00:00Z"
    }
  ],
  "next_cursor": null,
  "has_more": false
}
```

### DELETE /webhooks/{id}

Deactivate and remove a webhook registration. Agent Therapy will immediately stop sending events to the registered URL.

```bash theme={null}
curl -X DELETE https://api.agenttherapy.ai/v1/webhooks/wh_11t3d4uc2w5x8a6b \
  -H "Authorization: Bearer at_your_key_here"
```

A successful delete returns an HTTP `204 No Content` response with no body.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.