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

# Webhooks

> Receive HTTP notifications when workflow events occur

<Note>
  Your webhook endpoint must be publicly accessible.
</Note>

## Setup

<CodeGroup>
  ```typescript title="Node SDK" theme={null}
  import { KadoaClient } from "@kadoa/node-sdk";

  const client = new KadoaClient({ apiKey: "YOUR_API_KEY" });

  await client.notification.setupForWorkflow({
    workflowId: "YOUR_WORKFLOW_ID",
    events: ["workflow_data_change"],
    channels: {
      WEBHOOK: {
        name: "my-webhook",
        webhookUrl: "https://api.example.com/webhooks/kadoa",
        httpMethod: "POST",
      },
    },
  });
  ```

  ```python title="Python SDK" theme={null}
  from kadoa_sdk import KadoaClient, KadoaClientConfig
  from kadoa_sdk.notifications import SetupWorkflowNotificationSettingsRequest

  client = KadoaClient(KadoaClientConfig(api_key="YOUR_API_KEY"))

  client.notification.setup_for_workflow(
      SetupWorkflowNotificationSettingsRequest(
          workflow_id="YOUR_WORKFLOW_ID",
          events=["workflow_data_change"],
          channels={
              "WEBHOOK": {
                  "name": "my-webhook",
                  "webhookUrl": "https://api.example.com/webhooks/kadoa",
                  "httpMethod": "POST",
              }
          },
      )
  )
  ```
</CodeGroup>

For API configuration, see the [API reference](/api-reference/notifications).

### Dashboard Setup

1. Go to **Notifications** in the sidebar
2. Click **Add Channel** → **Webhook**
3. Enter your endpoint URL
4. Save changes

<img src="https://mintcdn.com/kadoa/oarWYx8cTCu-JBDx/images/notifications/webhook/webhook-ui.png?fit=max&auto=format&n=oarWYx8cTCu-JBDx&q=85&s=6f7332a5db6729f64de694edb2775c8e" alt="Webhook setup" width="1006" height="952" data-path="images/notifications/webhook/webhook-ui.png" />

## Authentication

Add custom headers for webhook authentication:

```json theme={null}
// POST /v5/notifications/channels
{
  "channelType": "WEBHOOK",
  "name": "Authenticated Webhook",
  "config": {
    "webhookUrl": "https://api.example.com/webhooks/kadoa",
    "httpMethod": "POST",
    "auth": {
      "type": "HEADER",
      "headers": {
        "Authorization": "Bearer your-secret-token",
        "X-Custom-Header": "custom-value"
      }
    }
  }
}
```

## Request Format

Every webhook request includes:

| Header          | Description                               |
| --------------- | ----------------------------------------- |
| `Content-Type`  | `application/json`                        |
| `X-Kadoa-Event` | Event type (e.g., `workflow_data_change`) |

## Payload Reference

All payloads follow this structure:

```json theme={null}
{
  "eventType": "event_name",
  "timestamp": "2025-01-15T10:30:00Z",
  "data": { /* event-specific data */ }
}
```

<CodeGroup>
  ```json title="workflow_data_change" theme={null}
  {
    "eventType": "workflow_data_change",
    "timestamp": "2025-01-15T10:30:00Z",
    "data": {
      "id": "change_123",
      "workflowId": "wf_123",
      "data": [
        { "id": "record-1", "name": "Product A", "price": 29.99 }
      ],
      "differences": [
        {
          "type": "changed",
          "fields": [
            { "key": "price", "value": 29.99, "previousValue": 24.99 }
          ]
        },
        {
          "type": "added",
          "fields": [
            { "key": "id", "value": "record-2" },
            { "key": "name", "value": "New Product" }
          ]
        }
      ],
      "url": "https://monitored-page.com",
      "createdAt": "2025-01-15T10:30:00Z",
      "metadata": {
        "workflowName": "Product Monitor",
        "tags": ["pricing"]
      }
    }
  }
  ```

  ```json title="workflow_finished" theme={null}
  {
    "eventType": "workflow_finished",
    "timestamp": "2025-01-15T10:30:00Z",
    "data": {
      "id": "wf_123",
      "jobId": "job_456",
      "source": "scheduler"
    }
  }
  ```

  ```json title="workflow_failed" theme={null}
  {
    "eventType": "workflow_failed",
    "timestamp": "2025-01-15T10:30:00Z",
    "data": {
      "workflowId": "wf_123",
      "workflowName": "Product Monitor",
      "source": "Product Monitor",
      "sourceUrl": "https://monitored-page.com",
      "url": "https://monitored-page.com",
      "reason": "Access blocked by bot protection",
      "action": "No action needed. We'll email you when the workflow recovers."
    }
  }
  ```

  ```json title="workflow_recovered" theme={null}
  {
    "eventType": "workflow_recovered",
    "timestamp": "2025-01-15T10:45:00Z",
    "data": {
      "workflowId": "wf_123",
      "workflowName": "Product Monitor",
      "source": "Product Monitor",
      "sourceUrl": "https://monitored-page.com",
      "url": "https://monitored-page.com"
    }
  }
  ```

  ```json title="workflow_validation_anomaly_change" theme={null}
  {
    "eventType": "workflow_validation_anomaly_change",
    "timestamp": "2025-01-15T10:30:00Z",
    "data": {
      "validationId": "val_123",
      "workflowId": "wf_123",
      "jobId": "job_456",
      "anomaliesCountTotal": 15,
      "anomaliesChangeTotal": 10,
      "anomaliesByRule": [
        { "ruleName": "missing_values", "count": 8, "change": 5 }
      ],
      "previousJobId": "job_455",
      "workflowName": "Product Monitor",
      "createdAt": "2025-01-15T10:30:00Z"
    }
  }
  ```
</CodeGroup>

`workflow_failed` fields: required `workflowId`, `source`, `reason`, `action`; optional `workflowName`, `sourceUrl`, `url`.

`workflow_recovered` fields: required `workflowId`, `workflowName`, `source`; optional `sourceUrl`, `url`.

| Event                                | Description                                                                                                                     |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `workflow_data_change`               | Monitored data changes. Difference types: `changed`, `added`, `removed`                                                         |
| `workflow_finished`                  | Workflow completes successfully                                                                                                 |
| `workflow_failed`                    | Workflow fails. Includes `reason` and a human-readable `action`.                                                                |
| `workflow_recovered`                 | Workflow recovers after failure. Sent via `workflow_failed` subscription; suppressed if `workflow_finished` is also configured. |
| `workflow_validation_anomaly_change` | Validation anomalies change                                                                                                     |

## Error Handling

Kadoa retries failed webhook deliveries with exponential backoff:

| Attempt   | Delay     |
| --------- | --------- |
| 1st retry | 1 second  |
| 2nd retry | 2 seconds |
| 3rd retry | 4 seconds |

Your endpoint should return a `2xx` status code to acknowledge receipt.
