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

# Webhooks

> Send Validio notification messages as webhook payloads to an HTTP endpoint.

Webhook notifications send JSON payloads to any HTTP endpoint when Validio detects data quality incidents, schema changes, or source errors. Use webhooks to integrate Validio alerts with custom tools, internal dashboards, or automation workflows that aren't covered by the built-in notification channels.

In Validio, you configure webhooks in two steps: create a Webhook **integration** that holds the endpoint URL and authentication header, then create one or more **channels** that route alerts through that integration.

## Create a webhook integration

1. In Validio, navigate to **Workspace > Integrations** and click **+ New integration**.
2. From the **Integration type** list, select **Webhook**.
3. Enter a **Name** for the integration.
4. Enter the **Webhook URL** of the HTTP endpoint that should receive payloads.
5. (Optional) Enter an **Authorization header** value to include in requests to the endpoint.
6. (Optional) Click **Test integration** to send a test payload and verify that the endpoint responds successfully.
7. Click **Create integration**.

## Create a webhook channel

1. In Validio, navigate to **Notifications > Channels** and click **+ New channel**.
2. Under **Integration**, select the Webhook integration you created.
3. Enter a **Name** for the channel.
4. Select the **Namespace** where the channel will be created.
5. Click **Create**.

### Webhook configuration parameters

| Field / Option | Description |
| :- | :- |
| Webhook URL (integration) | Webhook URL to the specified HTTP endpoint. |
| Authorization header (integration) | (Optional) Signature to include in the authorization header sent to the HTTP endpoint. |
| Integration (channel) | Select an existing Webhook integration. If none exists, create one first at **Workspace > Integrations**. |
| Name (channel) | Identifier for the channel, used when referencing it from notification rules. |

After creating the channel, add [notification rules](https://docs.validio.io/v10.0/docs/notifications/notification-rules.md) on the channel's details page to control which incidents trigger webhook payloads.

### Request timeout and retry behavior

There is no timeout for Validio webhook requests. Webhook endpoints should respond with an HTTP 2xx within 30 seconds; otherwise the request is treated as a failed attempt. Failed message requests are retried every 30 minutes, up to 20 times.

## Webhook payload

Webhook payload is data embedded in a HTTP POST as JSON format. When your Notification rule is triggered, the webhook payload is sent to the specified HTTP endpoint. The payload structure varies depending on the notification type.

> [!NOTE]
>
> **Notifications on Backfilled Validators**
>
> Validio does not send notifications for incidents when backfilling validators.

### Validator incidents

Validator incidents occur when your data breaches a configured [Threshold](https://docs.validio.io/v10.0/docs/thresholds.md). The payload structure varies depending on Segmentation and Threshold type.

```json title="JSON (segmented validator, dynamic threshold)" theme={null}
{
  "type": "ValidatorIncident",
  "title": "1 incident triggered on: demo_source (DynamicThreshold threshold)",
  "validatorUrl": "https://your-validio-instance/observe/sources/SRC_123/validators/VAL_13",
  "source": {
    "id": "SRC_123",
    "name": "demo_source",
    "tags": [
      {
        "environment": "production"
      },
      {
        "domain": "finance"
      },
      {
        "dataOwner": "data-platform-team"
      },
      {
        "criticality": "tier-1"
      },
      {
        "containsPii": "true"
      },
      {
        "deprecated": null
      }
    ]
  },
  "validator": {
    "id": "MTR_13",
    "name": "numeric_validator",
    "tags": [
      {
        "checkType": "freshness"
      },
      {
        "sla": "15m"
      },
      {
        "regulation": "SOX"
      },
      {
        "onCall": "analytics-oncall"
      },
      {
        "reviewPending": null
      }
    ]
  },
  "segmentation": {
    "id": "SGM_123",
    "name": "Unsegmented"
  },
  "incidents": [
    {
      "endTime": "2024-01-01 0:00:01 UTC",
      "message": "placeholder",
      "incident_id": "TAT_123",
      "incident_group_id": "IGP_123",
      "segment": {
        "segmentFields": [
          {
            "field": "Age",
            "value": "123"
          }
        ],
        "segmentId": "PRT_123"
      },
      "startTime": "2024-01-01 0:00:01 UTC",
      "threshold": {
        "backfillMode": false,
        "decisionBoundsType": "UPPER_AND_LOWER",
        "lowerBound": 0,
        "sensitivity": 3,
        "severity": "LOW",
        "thresholdType": "DynamicThreshold",
        "upperBound": 1,
        "value": 0
      },
      "url": "https://your-validio-instance/issues/incidents/IGP_123",
      "imageUrl": "https://your-validio-instance/incident-graph/TAT_123",
      "priority": "CRITICAL",
      "owner": {
        "email": "owner@your-company.com"
      }
    }
  ]
}
```

#### Dynamic threshold

The payload structure for dynamic thresholds include the `value`, `boundary`, and `decisionBoundsType`:  `LOWER`, `UPPER`, or `UPPER_AND_LOWER`.

```json title="JSON (Dynamic threshold, upper and lower bounds)" theme={null}
"threshold": {
    "thresholdType": "DynamicThreshold",
    "value": 90,
    "decisionBoundsType": "UPPER_AND_LOWER",
    "lowerBound": 80.47892,
    "upperBound": 84.3383
}
```

```json title="JSON (Dynamic threshold, lower bound)" theme={null}
"threshold": {
    "thresholdType": "DynamicThreshold",
    "value": 81,
    "decisionBoundsType": "LOWER",
    "lowerBound": 81.62181
}
```

#### Fixed threshold

The payload structure for fixed thresholds include the `comparison value`, `value`, and `comparison operator`: `LESS`, `LESS_EQUAL`, `EQUAL`, `NOT_EQUAL`, `GREATER`, or `GREATER_EQUAL`.

```json title="JSON (Fixed threshold, LESS operator)" theme={null}
"threshold": {
    "thresholdType": "FixedThreshold",
    "operator": "LESS",
    "comparisonValue": 8,
    "value": 6
}
```

```json title="JSON (Fixed threshold, LESS_EQUAL operator)" theme={null}
"threshold": {
    "thresholdType": "FixedThreshold",
    "operator": "LESS_EQUAL",
    "comparisonValue": 30,
    "value": 24
}
```

#### Difference threshold

The payload structure for difference thresholds include the `difference_type` which contains either `ABSOLUTE` or `PERCENTAGE`.

```json title="JSON (Difference threshold, PERCENTAGE type)" theme={null}
"threshold": {
  "thresholdType": "DifferenceThreshold",
  "lowerBound": 42.0,
  "upperBound": 42.1,
  "differenceType": "PERCENTAGE",
  "operator": "INCREASING",
  "value": 42.2,
  "numberOfWindows": 42
}
```

### Schema changes

Validio can send notifications about changes in your schema. `changeTypes` can include one of the following: `Nullability`, `MissingField`, `JtdType`, or `UnderlyingType`.

```json title="JSON (Schema change)" theme={null}
{
  "type": "SchemaChangeSourceError",
  "title": "1 schema change found on: demo_source (DemoSource).",
  "sourceUrl": "https://your-validio-instance/observe/sources/SRC_123",
  "sourceId": "SRC_123",
  "source": {
    "id": "SRC_123",
    "name": "demo_source"
  },
  "incidents": [
    {
      "changes": {
        "Age": {
          "changeTypes": ["Nullability", "JtdType", "UnderlyingType", "Index"],
          "new": {
            "fieldIndex": 5,
            "name": "Age",
            "nullable": true,
            "type": "float64",
            "underlyingType": "int"
          },
          "old": {
            "fieldIndex": 2,
            "name": "Age",
            "nullable": false,
            "type": "float64",
            "underlyingType": "int"
          }
        },
        "Credit_score": {
          "changeTypes": ["JtdType"],
          "new": {
            "name": "Credit_score",
            "nullable": false,
            "type": "string",
            "underlyingType": "float64"
          },
          "old": {
            "name": "Credit_score",
            "nullable": false,
            "type": "float64",
            "underlyingType": "float64"
          }
        },
        "age2": {
          "changeTypes": ["MissingField"],
          "new": {
            "name": "",
            "nullable": false,
            "type": "",
            "underlyingType": ""
          },
          "old": {
            "name": "age",
            "nullable": true,
            "type": "float64",
            "underlyingType": "FLOAT"
          }
        },
        "age3": {
          "changeTypes": ["JtdType"],
          "new": {
            "name": "age3",
            "nullable": false,
            "type": "float64",
            "underlyingType": "string"
          }
        },
        "buy_cycle": {
          "changeTypes": ["MissingField"],
          "new": {
            "name": "",
            "nullable": false,
            "type": "",
            "underlyingType": ""
          },
          "old": {
            "name": "buy_cycle",
            "nullable": true,
            "type": "float64",
            "underlyingType": "INTEGER"
          }
        },
        "country": {
          "changeTypes": ["AddedField"],
          "new": {
            "name": "country",
            "nullable": false,
            "type": "string",
            "underlyingType": "string"
          },
          "old": {
            "name": "",
            "nullable": false,
            "type": "",
            "underlyingType": ""
          }
        },
        "exam_28d": {
          "changeTypes": ["MissingField"],
          "new": {
            "name": "",
            "nullable": false,
            "type": "",
            "underlyingType": ""
          },
          "old": {
            "name": "exam_28d",
            "nullable": true,
            "type": "float64",
            "underlyingType": "INTEGER"
          }
        },
        "exam_7d": {
          "changeTypes": ["MissingField"],
          "new": {
            "name": "",
            "nullable": false,
            "type": "",
            "underlyingType": ""
          },
          "old": {
            "name": "exam_7d",
            "nullable": true,
            "type": "float64",
            "underlyingType": "INTEGER"
          }
        },
        "gender": {
          "changeTypes": ["MissingField"],
          "new": {
            "name": "",
            "nullable": false,
            "type": "",
            "underlyingType": ""
          },
          "old": {
            "name": "gender",
            "nullable": true,
            "type": "float64",
            "underlyingType": "INTEGER"
          }
        },
        "new_nps": {
          "changeTypes": ["MissingField"],
          "new": {
            "name": "",
            "nullable": false,
            "type": "",
            "underlyingType": ""
          },
          "old": {
            "name": "new_nps",
            "nullable": true,
            "type": "float64",
            "underlyingType": "FLOAT"
          }
        }
      }
    }
  ]
}
```

### Segment limits

```json title="JSON (Segment limit)" theme={null}
{
  "type": "SegmentLimitExceededSourceError",
  "title": "1 segment limit exceeded on: demo_source (DemoSource).",
  "sourceUrl": "https://your-validio-instance/observe/sources/SRC_123",
  "sourceId": "SRC_123",
  "source": {
    "id": "SRC_123",
    "name": "demo_source"
  },
  "incidents": [
    {
      "limit": 1000,
      "segmentation": {
        "id": "SGM_123",
        "name": "Unsegmented"
      },
      "segmentationUrl": "https://your-validio-instance/observe/sources/SRC_123/segmentations/SGM_123"
    }
  ]
}
```

### Source errors

```json title="JSON (Source error)" theme={null}
{
  "type": "GenericSourceError",
  "title": "1 source error found on: demo_source (DemoSource).",
  "sourceUrl": "https://your-validio-instance/observe/sources/SRC_123",
  "sourceId": "SRC_123",
  "source": {
    "id": "SRC_123",
    "name": "demo_source"
  },
  "incidents": [
    {
      "message": "An unknown error has occurred in the source."
    }
  ]
}
```
