Scan API
This page provides payload examples for running, scheduling, and checking the status of scan operations. Replace the placeholder values with data specific to your setup.
All endpoints use the base URL of your Qualytics deployment (e.g., https://your-instance.qualytics.io/api).
Interactive API reference
For the full, interactive API reference (request schemas, response examples, and an in-browser request runner), visit the API docs.
Running a Scan operation
To run a scan operation, use the API payload example below and replace the placeholder values with your specific values.
Endpoint (Post)
Endpoint: POST /api/operations/run
- container_names:
[]means that it will scan all containers. - max_records_analyzed_per_partition:
nullmeans that it will scan all records of all containers. - Remediation:
appendreplicates source containers using an append-first strategy. - auto_resolve_passed_anomalies:
true(default for Full scans) automatically resolves previously open anomalies when the same checks no longer detect the issue. Forced tofalseserver-side whenincrementalistrue.
- container_names:
["table_name_1", "table_name_2"]means that it will scan only the tables table_name_1 and table_name_2. - max_records_analyzed_per_partition:
1000000means that it will scan a maximum of 1 million records per partition. - Remediation:
overwritereplicates source containers using an overwrite strategy.
About enrichment_source_record_limit
Caps how many source records are kept per anomaly: the rows written to the _source_records enrichment output and returned by the anomaly source-record endpoints. It defaults to 10 and accepts values from 1 to 1,000,000,000. Set it on the datastore to change the default for every scan, or on a scan run or schedule to override it for that run. A change applies to scans that start after it; earlier anomalies keep the sample they were written with. The limit does not affect anomalous_records_count on the anomaly, which holds the full count whenever the platform can compute it (it is null for shape anomalies whose affected rows cannot be counted). Raising it on wide tables increases enrichment storage and scan time.
Scheduling a Scan operation of all containers
To schedule a scan operation, use the API payload example below and replace the placeholder values with your specific values.
Endpoint (Post)
Endpoint: POST /api/operations/schedule
This payload is to run a scheduled scan operation every day at 00:00
{
"type":"scan",
"name":"My scheduled Scan operation",
"datastore_id":"datastore-id",
"container_names":[],
"remediation": "overwrite",
"incremental": false,
"auto_resolve_passed_anomalies": true,
"max_records_analyzed_per_partition":null,
"enrichment_source_record_limit":10,
"crontab":"0 0 * * *"
}
Retrieving Scan operation information
Endpoint (Get)
Endpoint: GET /api/operations/{id}
The status object includes auto_resolved_anomaly_count, the number of previously open anomalies this scan automatically resolved (always 0 for Incremental scans and for Full scans that ran with auto_resolve_passed_anomalies set to false).
{
"items": [
{
"id": 12345,
"created": "YYYY-MM-DDTHH:MM:SS.ssssssZ",
"type": "scan",
"start_time": "YYYY-MM-DDTHH:MM:SS.ssssssZ",
"end_time": "YYYY-MM-DDTHH:MM:SS.ssssssZ",
"result": "success",
"message": null,
"triggered_by": "user@example.com",
"datastore": {
"id": 101,
"name": "Datastore-Sample",
"store_type": "jdbc",
"type": "db_type",
"enrichment_only": false,
"enrichment_prefix": "data_prefix",
"favorite": false
},
"schedule": null,
"incremental": false,
"auto_resolve_passed_anomalies": true,
"remediation": "none",
"max_records_analyzed_per_partition": -1,
"greater_than_time": null,
"greater_than_batch": null,
"high_count_rollup_threshold": 10,
"enrichment_source_record_limit": 10,
"status": {
"total_containers": 2,
"containers_analyzed": 2,
"partitions_scanned": 2,
"records_processed": 28,
"anomalies_identified": 2,
"auto_resolved_anomaly_count": 1
},
"containers": [
{
"id": 234,
"name": "Container1",
"container_type": "table",
"table_type": "table"
},
{
"id": 235,
"name": "Container2",
"container_type": "table",
"table_type": "table"
}
],
"container_scans": [
{
"id": 456,
"created": "YYYY-MM-DDTHH:MM:SS.ssssssZ",
"container": {
"id": 235,
"name": "Container2",
"container_type": "table",
"table_type": "table"
},
"start_time": "YYYY-MM-DDTHH:MM:SS.ssssssZ",
"end_time": "YYYY-MM-DDTHH:MM:SS.ssssssZ",
"records_processed": 8,
"anomaly_count": 1,
"auto_resolved_anomaly_count": 1,
"result": "success",
"message": null
},
{
"id": 457,
"created": "YYYY-MM-DDTHH:MM:SS.ssssssZ",
"container": {
"id": 234,
"name": "Container1",
"container_type": "table",
"table_type": "table"
},
"start_time": "YYYY-MM-DDTHH:MM:SS.ssssssZ",
"end_time": "YYYY-MM-DDTHH:MM:SS.ssssssZ",
"records_processed": 20,
"anomaly_count": 1,
"auto_resolved_anomaly_count": 0,
"result": "success",
"message": null
}
],
"tags": []
}
],
"total": 1,
"page": 1,
"size": 50,
"pages": 1
}
Container Scans
A scan operation runs one container scan per container, and each container scan runs one partition scan per partition. Container scans are the unit that links a scan to its anomalies, its check results, and its source records. Every timestamp is UTC, ISO 8601 with a trailing Z.
List container scans
Endpoint: GET /api/container-scans
Permission: Member role. Results are scoped to the datastores the caller can see.
Query parameters (all optional):
| Parameter | Type | Description |
|---|---|---|
datastore, container, operation |
int[] |
Scope to specific datastores, containers, or scan operations. |
name, search |
string |
Match on the container name (search also matches the ID). |
result |
string[] |
Filter by result (success, failure, aborted, queued, running). |
latest_only |
bool |
Return only the latest container scan of each container. |
created_date, offset |
date, int |
Return container scans created on one day; offset is your timezone offset from UTC in minutes. |
sort_created, sort_active_anomalies |
"asc" \| "desc" |
Sort options. |
page, size |
int |
Pagination. |
Get a container scan
Endpoint: GET /api/container-scans/{id}
Permission: Member role plus the Reporter team permission on the datastore.
Example response (abbreviated)
{
"id": 456,
"created": "2026-06-01T02:00:00.117Z",
"operation_id": 12345,
"datastore": { "id": 101, "name": "Sales" },
"container": { "id": 235, "name": "orders", "container_type": "table" },
"start_time": "2026-06-01T02:00:00.117Z",
"end_time": "2026-06-01T02:03:41.902Z",
"records_processed": 121500,
"anomaly_count": 37,
"result": "success",
"message": null,
"partition_scans": [
{
"id": 9017,
"partition": { "id": 300, "name": "orders" },
"records_processed": 121500,
"anomaly_count": 37,
"open_anomaly_count": 37,
"archived_anomaly_count": 0,
"result": "success",
"message": null
}
]
}
start_time is the value to pass as version_at to GET /api/quality-checks/{id}/version to see the check definitions this scan evaluated.
List anomalies of a container scan
Endpoint: GET /api/container-scans/{id}/anomalies
Permission: Member role.
Returns the anomalies the container scan produced, paginated, in the same shape as GET /api/anomalies. The list endpoint offers the same scoping with more filters through GET /api/anomalies?container_scan={id}; see the Anomalies API.
Get source records of a container scan
Returns the source records of every anomaly the container scan produced that has source records, deduplicated when several anomalies share a record. Two formats are available.
Endpoint (JSON): GET /api/container-scans/{id}/source-records
Endpoint (CSV): GET /api/container-scans/{id}/source-records/download
Permission: Member role plus the Viewer team permission on the datastore; include_masked=true needs the Editor team permission.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
limit |
int (≥1) |
Maximum number of rows returned. Defaults to 10 on the JSON endpoint; omit on the CSV endpoint to download every recorded row. |
include_masked |
bool (default false) |
When true, returns raw values for masked fields. Requires the Editor team permission, and the platform writes an audit-log entry naming the masked fields you accessed. |
Example request
The rows are the same ones served per anomaly by GET /api/anomalies/{id}/source-record, so the number kept per anomaly is capped by enrichment_source_record_limit (see Running a Scan operation).
List Check Results for a Scan
Two endpoints return every check that a scan evaluated, with the number of anomalies each check produced in that scan. Use them to answer "which checks passed and which failed in scan X". Both are paginated (page, size).
Endpoint (whole scan): GET /api/operations/{id}/scan-checks
Endpoint (one container scan): GET /api/container-scans/{id}/checks
Query parameters:
| Parameter | Applies to | Type | Description |
|---|---|---|---|
search |
both | string |
Substring match on the check description or ID. |
result |
container scan | "passed" \| "failed" |
Return only checks with zero anomalies (passed) or with at least one (failed). |
sort_anomalies |
container scan | "desc" \| "asc" (default desc) |
Sort by anomaly count. |
Permission: Member role, plus the Reporter team permission on the datastore for the operation endpoint and the Viewer team permission for the container-scan endpoint. The operation endpoint is only available for scan operations.
Example request
Example response (abbreviated)
{
"items": [
{
"id": 778,
"description": "Orders must reference a customer",
"rule_type": "notNull",
"status": "Active",
"scan_anomaly_count": 37,
"container_scan_anomaly_count": 37,
"container": { "id": 235, "name": "orders" },
"container_scan_id": 456,
"fields": [{ "id": 3101, "name": "customer_id" }]
}
],
"total": 1,
"page": 1,
"size": 50,
"pages": 1
}
scan_anomaly_count is the number of distinct anomalies this check produced in the scan; 0 means the check passed. container_scan_anomaly_count is the distinct anomaly count for the whole container scan across all checks. Do not sum scan_anomaly_count across checks to get it, because one anomaly can fail several checks.
Unasserted checks appear as passed
Pass/fail on these endpoints is derived from the anomaly count. A check the scan could not evaluate (for example, a filter with invalid syntax or a field that no longer exists) produces no anomalies and therefore shows as passed, with scan_anomaly_count of 0. To distinguish unasserted from passed for a given scan, use the ASSERTION_RESULT column of the _check_metrics enrichment output. GET /api/quality-checks/{id}/insights also reports the actual result, but only for the last run of each day.
To see what a check looked like when the scan ran, pass the scan's start_time to GET /api/quality-checks/{id}/version.