Drift Detection
Compute behavioral baselines, score live drift, and manage drift alerts for your AI agents.
All endpoints require a Bearer token (Authorization: Bearer aira_live_xxxxx). Base URL: https://api.airaproof.com/api/v1
All drift endpoints are scoped to a specific agent: /api/v1/agents/{agent_id}/drift/...
Compute Baseline
POST /api/v1/agents/{agent_id}/drift/baseline
Authorization: Bearer aira_live_xxxxxComputes a behavioral baseline from a window of production actions. The baseline captures the action-type distribution and volume during the specified period, which is then used as the reference for drift scoring.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
window_start | string | Yes | Start of the baseline window (ISO 8601) |
window_end | string | Yes | End of the baseline window (ISO 8601) |
activate | boolean | No | Whether to immediately activate this baseline (default: true) |
Example Request
curl -X POST https://api.airaproof.com/api/v1/agents/procurement-agent/drift/baseline \
-H "Authorization: Bearer aira_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"window_start": "2026-05-01T00:00:00Z",
"window_end": "2026-05-31T23:59:59Z",
"activate": true
}'Response (201 Created)
{
"id": "bl_01J9E...",
"agent_id": "procurement-agent",
"baseline_type": "production",
"is_active": true,
"window_start": "2026-05-01T00:00:00Z",
"window_end": "2026-05-31T23:59:59Z",
"action_type_dist": {
"transaction": 0.45,
"decision": 0.30,
"tool_call": 0.25
},
"total_actions": 1240,
"avg_actions_per_day": 40.0,
"source_agent_ids": null,
"request_id": "req_01J9E..."
}Seed Synthetic Baseline
POST /api/v1/agents/{agent_id}/drift/baseline/synthetic
Authorization: Bearer aira_live_xxxxxSeeds a baseline from a config dict rather than production data. Use this at first deployment so the agent has a reference distribution before any production data accumulates.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
expected_distribution | object | Yes | Map of action types to expected proportions (must have at least one entry) |
expected_actions_per_day | number | Yes | Expected average actions per day (>= 0) |
activate | boolean | No | Whether to immediately activate this baseline (default: true) |
Example Request
curl -X POST https://api.airaproof.com/api/v1/agents/procurement-agent/drift/baseline/synthetic \
-H "Authorization: Bearer aira_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"expected_distribution": {
"transaction": 0.50,
"decision": 0.30,
"tool_call": 0.20
},
"expected_actions_per_day": 35.0,
"activate": true
}'Response (201 Created)
{
"id": "bl_01J9F...",
"agent_id": "procurement-agent",
"baseline_type": "synthetic",
"is_active": true,
"window_start": "2026-06-05T00:00:00Z",
"window_end": "2026-06-05T00:00:00Z",
"action_type_dist": {
"transaction": 0.50,
"decision": 0.30,
"tool_call": 0.20
},
"total_actions": 0,
"avg_actions_per_day": 35.0,
"source_agent_ids": null,
"request_id": "req_01J9F..."
}Pooled Baseline
POST /api/v1/agents/{agent_id}/drift/baseline/pooled
Authorization: Bearer aira_live_xxxxxBootstraps a baseline by pooling actions across a cohort of agents. Useful when a new agent shares behavior patterns with existing agents and you want to derive a baseline from their collective history.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
source_agent_ids | string[] | Yes | Agent IDs to pool actions from (at least one required) |
window_start | string | Yes | Start of the pooling window (ISO 8601) |
window_end | string | Yes | End of the pooling window (ISO 8601) |
activate | boolean | No | Whether to immediately activate this baseline (default: true) |
Example Request
curl -X POST https://api.airaproof.com/api/v1/agents/new-procurement-agent/drift/baseline/pooled \
-H "Authorization: Bearer aira_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"source_agent_ids": ["procurement-agent-eu", "procurement-agent-us"],
"window_start": "2026-04-01T00:00:00Z",
"window_end": "2026-05-31T23:59:59Z",
"activate": true
}'Response (201 Created)
{
"id": "bl_01J9G...",
"agent_id": "new-procurement-agent",
"baseline_type": "pooled",
"is_active": true,
"window_start": "2026-04-01T00:00:00Z",
"window_end": "2026-05-31T23:59:59Z",
"action_type_dist": {
"transaction": 0.48,
"decision": 0.32,
"tool_call": 0.20
},
"total_actions": 2860,
"avg_actions_per_day": 47.0,
"source_agent_ids": ["procurement-agent-eu", "procurement-agent-us"],
"request_id": "req_01J9G..."
}Get Drift Status
GET /api/v1/agents/{agent_id}/drift?lookback_hours=24
Authorization: Bearer aira_live_xxxxxScores the agent's recent behavior against its active baseline. This is a read-only endpoint -- it does not persist an alert. Use this for dashboards and monitoring UIs. To run a drift check that records an alert when the threshold is exceeded, use the Check Drift endpoint instead.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
lookback_hours | integer | No | Hours of recent activity to measure (1--720, default: 24) |
Example Request
curl https://api.airaproof.com/api/v1/agents/procurement-agent/drift?lookback_hours=48 \
-H "Authorization: Bearer aira_live_xxxxx"Response (200 OK)
{
"agent_id": "procurement-agent",
"has_baseline": true,
"baseline": {
"id": "bl_01J9E...",
"agent_id": "procurement-agent",
"baseline_type": "production",
"is_active": true,
"window_start": "2026-05-01T00:00:00Z",
"window_end": "2026-05-31T23:59:59Z",
"action_type_dist": {
"transaction": 0.45,
"decision": 0.30,
"tool_call": 0.25
},
"total_actions": 1240,
"avg_actions_per_day": 40.0,
"source_agent_ids": null
},
"current_window": {
"agent_id": "procurement-agent",
"window_start": "2026-06-03T00:00:00Z",
"window_end": "2026-06-05T00:00:00Z",
"action_type_dist": {
"transaction": 0.20,
"decision": 0.10,
"tool_call": 0.25,
"data_export": 0.45
},
"total_actions": 96,
"avg_actions_per_day": 48.0
},
"kl_divergence": 0.87,
"volume_ratio": 1.2,
"severity": "high",
"new_action_types": ["data_export"],
"is_drifting": true,
"request_id": "req_01J9H..."
}When the agent has no active baseline, the response indicates that:
{
"agent_id": "procurement-agent",
"has_baseline": false,
"is_drifting": false,
"request_id": "req_01J9H..."
}Response Fields
| Field | Type | Description |
|---|---|---|
agent_id | string | The agent being measured |
has_baseline | boolean | Whether the agent has an active baseline |
baseline | object | null | The active baseline (see Baseline Response above) |
current_window | object | null | The measured window of recent activity |
kl_divergence | number | null | Symmetric KL divergence between baseline and current distributions |
volume_ratio | number | null | Ratio of current volume to baseline volume |
severity | string | null | Computed severity: info, low, medium, high, or critical |
new_action_types | string[] | null | Action types present in the current window but absent from the baseline |
is_drifting | boolean | Whether the agent is currently drifting beyond thresholds |
Check Drift
POST /api/v1/agents/{agent_id}/drift/check?lookback_hours=24
Authorization: Bearer aira_live_xxxxxRuns a drift check and persists an alert if the threshold is exceeded. Returns the new alert, or null if no drift was detected. This endpoint is metered as a drift_check usage event.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
lookback_hours | integer | No | Hours of recent activity to measure (1--720, default: 24) |
Example Request
curl -X POST "https://api.airaproof.com/api/v1/agents/procurement-agent/drift/check?lookback_hours=24" \
-H "Authorization: Bearer aira_live_xxxxx"Response (200 OK) -- Drift Detected
{
"id": "da_01J9I...",
"agent_id": "procurement-agent",
"baseline_uuid": "bl_01J9E...",
"window_start": "2026-06-04T00:00:00Z",
"window_end": "2026-06-05T00:00:00Z",
"kl_divergence": 0.87,
"volume_ratio": 1.2,
"severity": "high",
"new_action_types": ["data_export"],
"detected_at": "2026-06-05T12:00:00Z",
"acknowledged_at": null,
"acknowledged_by": null
}Response (200 OK) -- No Drift
nullList Drift Alerts
GET /api/v1/agents/{agent_id}/drift/alerts?page=1&per_page=50
Authorization: Bearer aira_live_xxxxxReturns a paginated list of drift alerts for the agent.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default: 1, min: 1) |
per_page | integer | No | Items per page (default: 50, min: 1, max: 200) |
acknowledged | boolean | No | Filter by acknowledgement status. Omit to return all alerts |
Example Request
curl "https://api.airaproof.com/api/v1/agents/procurement-agent/drift/alerts?acknowledged=false&per_page=10" \
-H "Authorization: Bearer aira_live_xxxxx"Response (200 OK)
{
"data": [
{
"id": "da_01J9I...",
"agent_id": "procurement-agent",
"baseline_uuid": "bl_01J9E...",
"window_start": "2026-06-04T00:00:00Z",
"window_end": "2026-06-05T00:00:00Z",
"kl_divergence": 0.87,
"volume_ratio": 1.2,
"severity": "high",
"new_action_types": ["data_export"],
"detected_at": "2026-06-05T12:00:00Z",
"acknowledged_at": null,
"acknowledged_by": null
}
],
"pagination": {
"page": 1,
"per_page": 10,
"total": 3,
"has_more": false
},
"request_id": "req_01J9J..."
}Acknowledge Drift Alert
POST /api/v1/agents/{agent_id}/drift/alerts/{alert_id}/acknowledge
Authorization: Bearer <jwt_token>Acknowledges a drift alert. This endpoint requires JWT authentication (not an API key) so the system can attribute who acknowledged the alert.
Example Request
curl -X POST https://api.airaproof.com/api/v1/agents/procurement-agent/drift/alerts/da_01J9I.../acknowledge \
-H "Authorization: Bearer <jwt_token>"Response (200 OK)
{
"id": "da_01J9I...",
"agent_id": "procurement-agent",
"baseline_uuid": "bl_01J9E...",
"window_start": "2026-06-04T00:00:00Z",
"window_end": "2026-06-05T00:00:00Z",
"kl_divergence": 0.87,
"volume_ratio": 1.2,
"severity": "high",
"new_action_types": ["data_export"],
"detected_at": "2026-06-05T12:00:00Z",
"acknowledged_at": "2026-06-05T14:30:00Z",
"acknowledged_by": "alice@example.com"
}Error Codes
| Status | Code | Description |
|---|---|---|
| 401 | UNAUTHORIZED | Acknowledging drift alerts requires JWT authentication |
| 404 | NOT_FOUND | Alert does not exist |
Baseline Response Object
All baseline creation endpoints return a response with these fields:
| Field | Type | Description |
|---|---|---|
id | string | Baseline UUID |
agent_id | string | The agent this baseline belongs to |
baseline_type | string | Type of baseline: production, synthetic, or pooled |
is_active | boolean | Whether this is the currently active baseline for the agent |
window_start | string | Start of the baseline window (ISO 8601) |
window_end | string | End of the baseline window (ISO 8601) |
action_type_dist | object | Map of action types to their proportions in the baseline |
total_actions | integer | Total number of actions in the baseline window |
avg_actions_per_day | number | Average actions per day during the baseline window |
source_agent_ids | string[] | null | Agent IDs that contributed to a pooled baseline (null for other types) |
request_id | string | Request ID for tracing |
Drift Alert Response Object
| Field | Type | Description |
|---|---|---|
id | string | Alert UUID |
agent_id | string | The agent that drifted |
baseline_uuid | string | The baseline the drift was measured against |
window_start | string | Start of the measurement window (ISO 8601) |
window_end | string | End of the measurement window (ISO 8601) |
kl_divergence | number | Symmetric KL divergence score |
volume_ratio | number | Ratio of current volume to baseline volume |
severity | string | Severity level: info, low, medium, high, or critical |
new_action_types | string[] | null | Action types not present in the baseline |
detected_at | string | When the drift was detected (ISO 8601) |
acknowledged_at | string | null | When the alert was acknowledged (ISO 8601) |
acknowledged_by | string | null | Email of the user who acknowledged the alert |