- Overview
- API Resources
Asynchronous table-level data-quality checks (freshness, missing-data, foreign-key) and constraint toggles, configured per table through the objectValidations field.
Object-level validations are asynchronous, table-level data-quality checks that evaluate a whole table rather than individual rows. Unlike the column-level validations applied inline during ingestion, they run after rollout — on a schedule or on demand — independently of any single ingest request.
You configure them per table in an objectValidations array, set when you save a schema or add a custom object and updated later with Patch a solution's schema.
Entry fields
Each entry in the objectValidations array is an object:
| Field | Required | Description |
|---|---|---|
type | Yes | One of freshness, missing_data_validation, foreign_key, async_foreign_key, unique_key. |
enabled | Yes | Whether the rule or check is active. |
severity | Depends on type | error or warn. Required for freshness, missing_data_validation, and async_foreign_key; optional for foreign_key (defaults to warn); not allowed on unique_key. |
params | Depends on type | Rule parameters. Required for freshness and missing_data_validation; optional for foreign_key and async_foreign_key (only constraintName, see Routing constraints); not allowed on unique_key. Keys depend on type (see below). |
alerts | Optional | Names of the alert channels to notify when the rule fails. Available on freshness, missing_data_validation, and async_foreign_key. See Data quality alerts. |
Data-quality rules
-
freshness— flags a table whose most-recent record is older than a threshold.params:Param Description columnTimestamp or date column to measure recency on. thresholdNumeric age limit. unitOne of minutes,hours,days,months,years. -
missing_data_validation— flags a time window that received fewer rows than expected.params:Param Description columnTimestamp or date column that defines the window. intervalNumeric length of the window. unitOne of minutes,hours,days,months,years.minRowCountMinimum number of rows expected in the window.
Foreign-key checks
The foreign-key check verifies that every value in a foreign-key column has a matching row in the referenced table. Two entries configure it, and you can use both on the same table:
foreign_key— runs the check inline as rows are ingested, scoped to the rows in each load. How a foreign-key violation is handled during ingestion — flagged on the row or routed to<table_name>_failed_rows— is described under Validation behavior.severityis optional and defaults towarn.async_foreign_key— an object-level check that re-evaluates the whole table after rollout, on a schedule or on demand, independently of any ingest. Like every object-level validation it does not move any row — it flags each orphan row in place;severityis required.
Because async_foreign_key re-checks every row on each run, a row flagged only because its parent had not yet been loaded is cleared automatically once the parent arrives — so a table no longer has to be ingested parent-before-child.
Both entries flag a violating row through the same two audit columns on the table:
| Column | Description |
|---|---|
peakAuditErrors | JSON array of the foreign-key violations on the row, each { "errorCode", "errorDetails", "severity", "constraintName" }. |
peakAuditLastValidationTime | Timestamp of the run that last flagged the row. |
Your downstream pipelines read peakAuditErrors to skip or specially handle flagged rows. When a later run finds that the parent row now exists, both columns are cleared for that row.
See Audit columns added at rollout for the columns and their per-warehouse casing, and the DI_{E|W}_23F01 error code reported for each violation.
Routing constraints with params.constraintName
Both foreign_key and async_foreign_key accept an optional params.constraintName — an array of foreign-key constraint names. When present, the entry applies only to the listed constraints; when omitted, it applies to all foreign keys on the table.
This lets you route some constraints to the per-load foreign_key check and others to the whole-table async_foreign_key check on the same table — for example, enforce a stable reference (a currency or region table) during ingestion, while re-checking a constraint whose parent rows arrive in a separate feed asynchronously.
Unique-key and primary-key checks
A unique_key entry enables or disables the asynchronous unique-key collision check for the table — it carries only type and enabled (no params, no severity). For example, { "type": "unique_key", "enabled": false } turns the check off. The primary-key check is always on and cannot be disabled.
The foreign_key / async_foreign_key / unique_key entries are distinct from the structural foreignKeys / uniqueKeys per-table fields. Those define the constraints (which columns form a key, which table is referenced); the objectValidations entries only control whether — and how — the corresponding check runs.
Alerts
Add an alerts array to a freshness, missing_data_validation, or async_foreign_key entry to notify a Slack or email channel when it fails. The names must match channels registered for your tenant, and the reserved name __ALL__ expands to all of them. Alerts are sent only when a check finishes in a failed or error state.
Channels are registered once per tenant through /api/v2/alert-configs, which is covered in Data quality alerts. A name that matches no registered channel is rejected with 400 Bad Request when you save the validation.
Defaults
- The
objectValidationsarray is optional. Omit it and the table has no data-quality rules; its foreign-key, unique-key, and primary-key checks still run with their default behavior. - A check you don't list runs on by default — the
foreign_key,async_foreign_key, andunique_keychecks are active for a table that declares the corresponding keys, unless you add an entry with"enabled": false. The primary-key check is always on and cannot be disabled. foreign_keyseverity defaults towarnwhen omitted;async_foreign_keyrequires an explicitseverity, andfreshness/missing_data_validationrequire bothseverityandparams.- Within an entry there are no other implicit defaults:
typeandenabledare always required. Omitting a required field returns400 Bad Request.
Example
"objectValidations": [
{ "type": "freshness",
"params": { "column": "order_date", "threshold": 24, "unit": "hours" },
"enabled": true, "severity": "error" },
{ "type": "missing_data_validation",
"params": { "column": "order_date", "interval": 1, "unit": "days", "minRowCount": 100 },
"enabled": true, "severity": "warn" },
{ "type": "foreign_key", "enabled": true, "severity": "warn",
"params": { "constraintName": ["fk_orders_customer"] } },
{ "type": "async_foreign_key", "enabled": true, "severity": "warn",
"alerts": ["data-oncall"],
"params": { "constraintName": ["fk_orders_region"] } },
{ "type": "unique_key", "enabled": false }
]
"objectValidations": [
{ "type": "freshness",
"params": { "column": "order_date", "threshold": 24, "unit": "hours" },
"enabled": true, "severity": "error" },
{ "type": "missing_data_validation",
"params": { "column": "order_date", "interval": 1, "unit": "days", "minRowCount": 100 },
"enabled": true, "severity": "warn" },
{ "type": "foreign_key", "enabled": true, "severity": "warn",
"params": { "constraintName": ["fk_orders_customer"] } },
{ "type": "async_foreign_key", "enabled": true, "severity": "warn",
"alerts": ["data-oncall"],
"params": { "constraintName": ["fk_orders_region"] } },
{ "type": "unique_key", "enabled": false }
]
Results
Object-level validations run asynchronously, and their outcomes surface in the Data Quality Dashboard.
Failures are reported under the OBJECT_VALIDATION error codes — DI_{E|W}_24F01 (freshness), DI_{E|W}_24M01 (missing data), and DI_{E|W}_23F01 (foreign key), where E is an error and W a non-fatal warning, set by the entry's severity.
Foreign-key violations are flagged on the row through peakAuditErrors / peakAuditLastValidationTime (see Foreign-key checks); a later async_foreign_key run clears the flag once the parent row exists.
When a rule names alert channels, the run report also lists the channels notified for that result in alerts_sent. A channel that could not be reached is left out, and the run still completes.