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 / OptionDescription
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 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.

Webhook channels send four types of message: validator incidents, schema changes, segment limits, and source errors. They do not send later updates to an incident, such as status changes, owner changes, or comments.

📘

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. The payload structure varies depending on Segmentation and Threshold type.

{
  "type": "ValidatorIncident",
  "title": "1 incident triggered on: demo_source (DynamicThreshold threshold)",
  "validatorUrl": "https://your-validio-instance.com/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": "http://your-validio-instance.com/issues/incidents/IGP_123",
      "imageUrl": "https://your-validio-instance.com/incident-graph/TAT_123",
      "priority": "CRITICAL",
      "owner": {
        "email": "[email protected]"
      }
    }
  ]
}

Dynamic Threshold

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

"threshold": {
    "thresholdType": "DynamicThreshold",
    "value": 90,
    "decisionBoundsType": "UPPER_AND_LOWER",
    "lowerBound": 80.47892,
    "upperBound": 84.3383
}
"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.

"threshold": {
    "thresholdType": "FixedThreshold",
    "operator": "LESS",
    "comparisonValue": 8,
    "value": 6
}
"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.

"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. Each changed field has a changeTypes list that can include one or more of the following values:

ValueDescription
AddedFieldA field was added to the schema. The fields in old are empty.
MissingFieldA field that existed before no longer exists. The fields in new are empty.
JtdTypeThe field's Validio data type changed.
UnderlyingTypeThe field's data type in the source changed.
NullabilityThe field changed between nullable and not nullable.
IndexThe field's position in the schema changed.

Handle any other value as unknown, because new change types can be added.

{
  "type": "SchemaChangeSourceError",
  "title": "1 schema change found on: demo_source (DemoSource).",
  "sourceUrl": "https://your-validio-instance.com/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

{
  "type": "SegmentLimitExceededSourceError",
  "title": "1 segment limit exceeded on: demo_source (DemoSource).",
  "sourceUrl": "https://your-validio-instance.com/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.com/observe/sources/SRC_123/segmentations/SGM_123"
    }
  ]
}

Source Errors

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

Did this page help you?