Skip to main content
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

MethodEndpointDescription
GET/api/v1/sdk/metrics/{asset_id}/summaryGet 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}/captureTrigger metric capture
GET/api/v1/sdk/metrics/{asset_id}/{metric_id}/snapshotsList metric snapshots

Metric Types

TypeDescriptionRequires Column
row_countTotal row count of the tableNo
null_percentPercentage of null valuesYes
distinct_countCount of distinct valuesYes
duplicate_countCount of duplicate valuesYes
min_valueMinimum numeric valueYes
max_valueMaximum numeric valueYes
avg_valueAverage numeric valueYes
percentilePercentile 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

ParameterTypeDefaultDescription
metric_typestring-Filter by type (e.g., row_count, null_percent)
is_activeboolean-Filter by active status
limitinteger50Max results (max: 100)
offsetinteger0Results 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

ParameterTypeDefaultDescription
include_snapshotsbooleantrueInclude recent snapshots
snapshot_limitinteger30Max 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

FieldTypeRequiredDescription
metric_typestringYesMetric type (see table above)
table_pathstringYesFull table path (catalog.schema.table)
column_namestringFor column metricsColumn name
capture_intervalstringNohourly, daily, weekly (default: daily)
sensitivityfloatNoAnomaly detection sensitivity (default: 1.0)
group_by_columnsarrayNoColumns to group by
percentile_valuefloatNoPercentile 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

FieldTypeDescription
is_activebooleanWhether metric is active
capture_intervalstringCapture interval
sensitivityfloatAnomaly 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

ParameterTypeDefaultDescription
limitinteger100Max results
offsetinteger0Results 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
  }
}
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"}
  }
}