Policies
Create and manage policies that automatically evaluate agent actions.
All endpoints require a Bearer token (Authorization: Bearer aira_live_xxxxx). Base URL: https://api.airaproof.com/api/v1
For a conceptual overview of how policies work, see the Policy Engine guide.
Create Policy
POST /api/v1/policies
Authorization: Bearer aira_live_xxxxxCreates a new policy. Policies are created in draft status by default and must be activated before they evaluate actions.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable policy name |
description | string | No | Policy description |
mode | string | Yes | Evaluation mode: rules, ai, or consensus |
decision | string | Yes | Decision when policy matches: allow or deny |
priority | integer | No | Evaluation priority (higher = first). Default: 0 |
conditions | object | Conditional | JSON condition object. Required when mode is rules. |
policy_text | string | Conditional | Natural language policy text. Required when mode is ai or consensus. |
models | string[] | Conditional | Model IDs for evaluation. Required when mode is ai (1 model) or consensus (2-5 models). |
scope.agent_ids | string[] | No | Limit policy to specific agents. Empty = all agents. |
scope.action_types | string[] | No | Limit policy to specific action types. Empty = all types. |
Example: Rules Policy
curl -X POST https://api.airaproof.com/api/v1/policies \
-H "Authorization: Bearer aira_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Block High-Value Transfers",
"description": "Deny wire transfers above $25,000",
"mode": "rules",
"decision": "deny",
"priority": 100,
"conditions": {
"all": [
{ "field": "action_type", "operator": "equals", "value": "wire_transfer" },
{ "field": "amount", "operator": "gt", "value": 25000 }
]
},
"scope": {
"action_types": ["wire_transfer"]
}
}'Example: AI Policy
curl -X POST https://api.airaproof.com/api/v1/policies \
-H "Authorization: Bearer aira_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "PII Export Gate",
"mode": "ai",
"decision": "deny",
"priority": 200,
"policy_text": "Deny any action that involves sending customer data to a third-party API unless the agent is the data-export-agent and the endpoint is on our approved list.",
"models": ["claude-sonnet-4-6"]
}'Example: Consensus Policy
curl -X POST https://api.airaproof.com/api/v1/policies \
-H "Authorization: Bearer aira_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Financial Decision Review",
"mode": "consensus",
"decision": "deny",
"priority": 300,
"policy_text": "Deny any financial transaction above $25,000 unless the customer has been verified in the last 30 days.",
"models": ["claude-sonnet-4-6", "gpt-5.4", "gemini-3.1-pro"]
}'Response (201 Created)
{
"id": "pol_01JAB...",
"name": "Block High-Value Transfers",
"description": "Deny wire transfers above $25,000",
"mode": "rules",
"decision": "deny",
"priority": 100,
"status": "draft",
"conditions": {
"all": [
{ "field": "action_type", "operator": "equals", "value": "wire_transfer" },
{ "field": "amount", "operator": "gt", "value": 25000 }
]
},
"policy_text": null,
"models": null,
"scope": {
"agent_ids": [],
"action_types": ["wire_transfer"]
},
"created_at": "2026-04-05T10:00:00.000Z",
"updated_at": "2026-04-05T10:00:00.000Z",
"request_id": "req_01JAB..."
}Error Codes
| Status | Code | Description |
|---|---|---|
| 400 | INVALID_MODE | Mode must be rules, ai, or consensus |
| 400 | CONDITIONS_REQUIRED | Rules mode requires conditions field |
| 400 | POLICY_TEXT_REQUIRED | AI/consensus mode requires policy_text field |
| 400 | MODELS_REQUIRED | AI/consensus mode requires models field |
| 400 | INVALID_MODEL | One or more model IDs are not supported |
List Policies
GET /api/v1/policies?page=1&per_page=20
Authorization: Bearer aira_live_xxxxxReturns a paginated list of policies for the organization.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
per_page | integer | Items per page (default: 20, max: 100) |
mode | string | Filter by mode: rules, ai, consensus |
status | string | Filter by status: draft, active, inactive |
Response (200 OK)
{
"policies": [
{
"id": "pol_01JAB...",
"name": "Block High-Value Transfers",
"mode": "rules",
"decision": "deny",
"priority": 100,
"status": "active",
"created_at": "2026-04-05T10:00:00.000Z"
},
{
"id": "pol_01JAC...",
"name": "PII Export Gate",
"mode": "ai",
"decision": "deny",
"priority": 200,
"status": "active",
"created_at": "2026-04-05T10:05:00.000Z"
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total": 2
}
}Get Policy
GET /api/v1/policies/{policy_uuid}
Authorization: Bearer aira_live_xxxxxReturns full policy details including conditions, policy text, and scope.
Response (200 OK)
{
"id": "pol_01JAB...",
"name": "Block High-Value Transfers",
"description": "Deny wire transfers above $25,000",
"mode": "rules",
"decision": "deny",
"priority": 100,
"status": "active",
"conditions": {
"all": [
{ "field": "action_type", "operator": "equals", "value": "wire_transfer" },
{ "field": "amount", "operator": "gt", "value": 25000 }
]
},
"policy_text": null,
"models": null,
"scope": {
"agent_ids": [],
"action_types": ["wire_transfer"]
},
"evaluation_count": 1482,
"last_evaluated_at": "2026-04-05T14:22:00.000Z",
"created_at": "2026-04-05T10:00:00.000Z",
"updated_at": "2026-04-05T10:00:00.000Z",
"request_id": "req_01JAB..."
}Error Codes
| Status | Code | Description |
|---|---|---|
| 404 | POLICY_NOT_FOUND | Policy does not exist |
Update Policy
PATCH /api/v1/policies/{policy_uuid}
Authorization: Bearer aira_live_xxxxxUpdates a policy. Only the provided fields are changed. Active policies can be updated — changes take effect immediately.
Request Body
All fields from Create Policy are accepted. Only include the fields you want to change.
curl -X PATCH https://api.airaproof.com/api/v1/policies/pol_01JAB... \
-H "Authorization: Bearer aira_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"priority": 150,
"description": "Updated: deny wire transfers above $25,000"
}'Response (200 OK)
Returns the full updated policy object (same shape as Get Policy).
Error Codes
| Status | Code | Description |
|---|---|---|
| 404 | POLICY_NOT_FOUND | Policy does not exist |
| 400 | INVALID_MODE | Cannot change mode of an existing policy |
Delete Policy
DELETE /api/v1/policies/{policy_uuid}
Authorization: Bearer aira_live_xxxxxDeletes a policy. Active policies must be deactivated first.
Response (200 OK)
{
"id": "pol_01JAB...",
"deleted": true,
"request_id": "req_01JAB..."
}Error Codes
| Status | Code | Description |
|---|---|---|
| 404 | POLICY_NOT_FOUND | Policy does not exist |
| 409 | POLICY_ACTIVE | Cannot delete an active policy. Deactivate it first. |
Activate Policy
POST /api/v1/policies/{policy_uuid}/activate
Authorization: Bearer aira_live_xxxxxActivates a draft or inactive policy. Once active, the policy evaluates actions on every authorize() call.
Response (200 OK)
{
"id": "pol_01JAB...",
"status": "active",
"activated_at": "2026-04-05T11:00:00.000Z",
"request_id": "req_01JAB..."
}Error Codes
| Status | Code | Description |
|---|---|---|
| 404 | POLICY_NOT_FOUND | Policy does not exist |
| 409 | ALREADY_ACTIVE | Policy is already active |
Deactivate Policy
POST /api/v1/policies/{policy_uuid}/deactivate
Authorization: Bearer aira_live_xxxxxDeactivates an active policy. Deactivated policies are not evaluated.
Response (200 OK)
{
"id": "pol_01JAB...",
"status": "inactive",
"deactivated_at": "2026-04-05T12:00:00.000Z",
"request_id": "req_01JAB..."
}Error Codes
| Status | Code | Description |
|---|---|---|
| 404 | POLICY_NOT_FOUND | Policy does not exist |
| 409 | NOT_ACTIVE | Policy is not currently active |
Dry Run
POST /api/v1/policies/{policy_uuid}/dry-run
Authorization: Bearer aira_live_xxxxxTests a policy against a simulated action without recording the evaluation or producing a receipt. Works on both draft and active policies.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
action_type | string | Yes | Simulated action type |
details | string | Yes | Simulated action details |
agent_id | string | No | Simulated agent ID |
model_id | string | No | Simulated model ID |
Example Request
curl -X POST https://api.airaproof.com/api/v1/policies/pol_01JAB.../dry-run \
-H "Authorization: Bearer aira_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"action_type": "wire_transfer",
"details": "Transfer $50,000 to vendor account",
"agent_id": "payments-agent",
"model_id": "claude-sonnet-4-6"
}'Response (200 OK)
{
"policy_uuid": "pol_01JAB...",
"policy_name": "Block High-Value Transfers",
"decision": "deny",
"reasoning": "Wire transfer amount exceeds $25,000 threshold.",
"confidence": 0.96,
"dry_run": true,
"request_id": "req_01JAB..."
}Error Codes
| Status | Code | Description |
|---|---|---|
| 404 | POLICY_NOT_FOUND | Policy does not exist |
Policy Decisions on the Authorization Response
Policy evaluation results are not returned as a separate object on the Authorization response. Instead, the outcome is reflected directly in the action's lifecycle:
| Decision | Resulting status | Notes |
|---|---|---|
allow | authorized | Agent may execute immediately. |
require_approval | pending_approval | Held for human review; a warning may be included in the warnings field. |
deny | request fails | The API returns 403 POLICY_DENIED; the action is recorded with status denied_by_policy. |
When a policy raises a warning (for example, an approval policy firing), the message appears in the warnings array on the Authorization response:
{
"action_uuid": "act_01JAB...",
"status": "pending_approval",
"created_at": "2026-04-07T14:30:00.000Z",
"request_id": "req_01JAB...",
"warnings": [
"Action held for approval by policy 'High-Value Transfers'."
]
}A denial is surfaced as a 403 POLICY_DENIED error containing the policy_uuid in details:
{
"code": "POLICY_DENIED",
"message": "Action denied by policy 'Block High-Value Transfers': Transfer amount exceeds 25,000 EUR threshold.",
"details": {
"action_uuid": "act_01JAB...",
"policy_uuid": "pol_01JAB..."
},
"request_id": "req_01JAB..."
}