Documentation Index
Fetch the complete documentation index at: https://docs.anomalyarmor.ai/llms.txt
Use this file to discover all available pages before exploring further.
For LLM agents: documentation index at
/llms.txt, full text at
/llms-full.txt. Append .md to any page URL for plain markdown.
The Metrics API enables programmatic management of data quality metrics. Use it to track trends in your data over time, detect anomalies, and integrate quality monitoring into your pipelines.
Endpoints
| Method | Endpoint | Description |
|---|
| GET | /api/v1/sdk/metrics/{asset_id}/summary | Get metrics summary for an asset |
| GET | /api/v1/sdk/metrics/{asset_id} | List metrics for an asset |
| GET | /api/v1/sdk/metrics/{asset_id}/{metric_id} | Get metric details |
| POST | /api/v1/sdk/metrics/{asset_id} | Create a new metric |
| PATCH | /api/v1/sdk/metrics/{asset_id}/{metric_id} | Update a metric |
| DELETE | /api/v1/sdk/metrics/{asset_id}/{metric_id} | Delete a metric |
| POST | /api/v1/sdk/metrics/{asset_id}/{metric_id}/capture | Trigger metric capture |
| GET | /api/v1/sdk/metrics/{asset_id}/{metric_id}/snapshots | List metric snapshots |
Metric Types
| Type | Description | Requires Column |
|---|
row_count | Total row count of the table | No |
null_percent | Percentage of null values | Yes |
distinct_count | Count of distinct values | Yes |
duplicate_count | Count of duplicate values | Yes |
min_value | Minimum numeric value | Yes |
max_value | Maximum numeric value | Yes |
mean | Average numeric value | Yes |
percentile | Percentile value (requires percentile_value) | Yes |
Get Metrics Summary
GET /api/v1/sdk/metrics/{asset_id}/summary
Returns aggregate metrics statistics for an asset.
curl -H "Authorization: Bearer aa_live_xxx" \
"https://api.anomalyarmor.ai/api/v1/sdk/metrics/550e8400-e29b-41d4-a716-446655440000/summary"
Response
{
"data": {
"total_metrics": 15,
"active_metrics": 12,
"total_checks": 8,
"passing": 6,
"failing": 1,
"warning": 1,
"error": 0,
"health_percentage": 87.5
}
}
List Metrics
GET /api/v1/sdk/metrics/{asset_id}
Query Parameters
| Parameter | Type | Default | Description |
|---|
metric_type | string | - | Filter by type (e.g., row_count, null_percent) |
is_active | boolean | - | Filter by active status |
limit | integer | 50 | Max results (max: 100) |
offset | integer | 0 | Results to skip |
curl -H "Authorization: Bearer aa_live_xxx" \
"https://api.anomalyarmor.ai/api/v1/sdk/metrics/550e8400-e29b-41d4-a716-446655440000?metric_type=null_percent&limit=10"
Response
{
"data": {
"items": [
{
"id": "m_550e8400-e29b-41d4-a716-446655440001",
"internal_id": 123,
"asset_id": 456,
"table_path": "snowflake.prod.warehouse.orders",
"column_name": "customer_email",
"metric_type": "null_percent",
"capture_interval": "daily",
"sensitivity": 3,
"is_active": true,
"created_at": "2026-01-01T10:00:00Z"
}
]
},
"pagination": {
"total": 15,
"limit": 50,
"offset": 0,
"has_more": false
}
}
Get Metric Details
GET /api/v1/sdk/metrics/{asset_id}/{metric_id}
Query Parameters
| Parameter | Type | Default | Description |
|---|
include_snapshots | boolean | true | Include recent snapshots |
snapshot_limit | integer | 30 | Max snapshots to include |
curl -H "Authorization: Bearer aa_live_xxx" \
"https://api.anomalyarmor.ai/api/v1/sdk/metrics/550e8400-e29b-41d4-a716-446655440000/m_550e8400-e29b-41d4-a716-446655440001?include_snapshots=true&snapshot_limit=10"
Response
{
"data": {
"id": "m_550e8400-e29b-41d4-a716-446655440001",
"internal_id": 123,
"asset_id": 456,
"table_path": "snowflake.prod.warehouse.orders",
"column_name": "customer_email",
"metric_type": "null_percent",
"capture_interval": "daily",
"sensitivity": 3,
"is_active": true,
"created_at": "2026-01-01T10:00:00Z"
}
}
Create Metric
POST /api/v1/sdk/metrics/{asset_id}
Requires read-write or admin scope.
Request Body
| Field | Type | Required | Description |
|---|
metric_type | string | Yes | Metric type (see table above) |
table_path | string | Yes | Full table path (catalog.schema.table) |
column_name | string | For column metrics | Column name |
capture_interval | string | No | hourly, daily, weekly (default: daily) |
sensitivity | float | No | Anomaly detection sensitivity (default: 1.0) |
group_by_columns | array | No | Columns to group by |
percentile_value | float | No | Percentile value (for percentile type) |
curl -X POST -H "Authorization: Bearer aa_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"metric_type": "null_percent",
"table_path": "snowflake.prod.warehouse.orders",
"column_name": "customer_email",
"capture_interval": "daily"
}' \
"https://api.anomalyarmor.ai/api/v1/sdk/metrics/550e8400-e29b-41d4-a716-446655440000"
Response
{
"data": {
"id": "m_550e8400-e29b-41d4-a716-446655440001",
"internal_id": 123,
"asset_id": 456,
"table_path": "snowflake.prod.warehouse.orders",
"column_name": "customer_email",
"metric_type": "null_percent",
"capture_interval": "daily",
"sensitivity": 1.0,
"is_active": true,
"created_at": "2026-01-04T10:30:00Z"
}
}
Update Metric
PATCH /api/v1/sdk/metrics/{asset_id}/{metric_id}
Requires read-write or admin scope.
Request Body
| Field | Type | Description |
|---|
is_active | boolean | Whether metric is active |
capture_interval | string | Capture interval |
sensitivity | float | Anomaly detection sensitivity |
curl -X PATCH -H "Authorization: Bearer aa_live_xxx" \
-H "Content-Type: application/json" \
-d '{"is_active": false}' \
"https://api.anomalyarmor.ai/api/v1/sdk/metrics/550e8400-e29b-41d4-a716-446655440000/m_550e8400-e29b-41d4-a716-446655440001"
Delete Metric
DELETE /api/v1/sdk/metrics/{asset_id}/{metric_id}
Requires read-write or admin scope.
curl -X DELETE -H "Authorization: Bearer aa_live_xxx" \
"https://api.anomalyarmor.ai/api/v1/sdk/metrics/550e8400-e29b-41d4-a716-446655440000/m_550e8400-e29b-41d4-a716-446655440001"
Response
{
"data": {
"success": true,
"message": "Metric deleted"
}
}
Trigger Metric Capture
POST /api/v1/sdk/metrics/{asset_id}/{metric_id}/capture
Requires read-write or admin scope.
Triggers an immediate capture of the metric value.
curl -X POST -H "Authorization: Bearer aa_live_xxx" \
"https://api.anomalyarmor.ai/api/v1/sdk/metrics/550e8400-e29b-41d4-a716-446655440000/m_550e8400-e29b-41d4-a716-446655440001/capture"
Response
{
"data": {
"snapshot_count": 1,
"snapshots": [
{
"id": 789,
"value": 2.5,
"captured_at": "2026-01-04T10:35:00Z",
"is_anomaly": false,
"status": "PASS"
}
]
}
}
List Metric Snapshots
GET /api/v1/sdk/metrics/{asset_id}/{metric_id}/snapshots
Query Parameters
| Parameter | Type | Default | Description |
|---|
limit | integer | 100 | Max results |
offset | integer | 0 | Results to skip |
curl -H "Authorization: Bearer aa_live_xxx" \
"https://api.anomalyarmor.ai/api/v1/sdk/metrics/550e8400-e29b-41d4-a716-446655440000/m_550e8400-e29b-41d4-a716-446655440001/snapshots?limit=30"
Response
{
"data": {
"items": [
{
"id": 789,
"metric_definition_id": 123,
"value": 2.5,
"captured_at": "2026-01-04T10:35:00Z",
"is_anomaly": false,
"z_score": 0.3,
"status": "PASS"
},
{
"id": 788,
"metric_definition_id": 123,
"value": 15.2,
"captured_at": "2026-01-03T10:35:00Z",
"is_anomaly": true,
"z_score": 4.2,
"status": "FAIL"
}
]
},
"pagination": {
"total": 90,
"limit": 30,
"offset": 0,
"has_more": true
}
}
Use Case: Monitor Row Count Trends
Track daily row counts to detect unexpected data volume changes:
from anomalyarmor import Client
client = Client()
asset_id = "550e8400-e29b-41d4-a716-446655440000"
# Create row count metric
metric = client.metrics.create(
asset_id,
metric_type="row_count",
table_path="snowflake.prod.warehouse.orders",
capture_interval="daily",
sensitivity=2.0, # Alert on 2+ standard deviations
)
# Trigger initial capture
result = client.metrics.capture(asset_id, metric.id)
print(f"Initial row count: {result['snapshots'][0]['value']}")
# Later: check for anomalies
snapshots = client.metrics.snapshots(asset_id, metric.id, limit=7)
anomalies = [s for s in snapshots if s.is_anomaly]
if anomalies:
print(f"Found {len(anomalies)} anomalies in the last 7 captures")
Error Responses
Metric Not Found (404)
{
"error": {
"code": "METRIC_NOT_FOUND",
"message": "Metric not found",
"details": {"metric_id": "m_invalid-uuid"}
}
}
Validation Error (400)
{
"error": {
"code": "VALIDATION_ERROR",
"message": "column_name is required for null_percent metrics",
"details": {"field": "column_name", "metric_type": "null_percent"}
}
}
Forbidden (403)
{
"error": {
"code": "FORBIDDEN",
"message": "Insufficient permissions. Required scope: read-write",
"details": {"current_scope": "read-only", "required_scope": "read-write"}
}
}
Common Questions
What’s the difference between a metric and a validity rule?
Metrics track numeric values over time (row counts, null percentages, mean, percentile) and alert on statistical anomalies via the sensitivity parameter. Validity rules (Validity API) enforce deterministic pass/fail constraints like NOT NULL, REGEX, or RANGE. Use metrics to catch drift, validity to catch explicit contract violations.
How does the sensitivity parameter affect anomaly detection?
Sensitivity is the z-score threshold for flagging a snapshot as anomalous, defaulting to 1.0. Raise it (e.g. 2.0 or 3.0) to reduce false positives on noisy data, lower it to catch subtler shifts. Each captured snapshot returns z_score and is_anomaly so you can tune in production.
Can I capture a metric on demand outside its scheduled interval?
Yes. POST /api/v1/sdk/metrics/{asset_id}/{metric_id}/capture (or client.metrics.capture(...)) triggers an immediate capture and returns the new snapshot with anomaly status. This is useful for backfilling after creating a metric and for post-deploy validation without waiting for the next scheduled run.
Which metric types require a column_name?
Column-level types (null_percent, distinct_count, duplicate_count, min_value, max_value, mean, percentile) require column_name. row_count operates on the whole table and ignores column_name. percentile additionally needs percentile_value in the request body.