SidClaw

Policy Endpoints

Create, list, update, and test policy rules that govern agent behavior.

Policy Endpoints

Policy rules define what agents are allowed to do, what requires human approval, and what is denied outright. The policy engine evaluates rules by priority -- higher priority rules take precedence. Each rule change is versioned automatically.

Endpoint Summary

MethodPathDescriptionAuth
POST/api/v1/policiesCreate a policy ruleAdmin
GET/api/v1/policiesList policy rules with filtersAny
GET/api/v1/policies/:idGet policy rule detailAny
PATCH/api/v1/policies/:idUpdate a policy ruleAdmin
DELETE/api/v1/policies/:idSoft-delete (deactivate) a policy ruleAdmin
GET/api/v1/policies/:id/versionsGet version historyAny
POST/api/v1/policies/testDry-run policy evaluationAny

POST /api/v1/policies

Create a new policy rule.

Auth: API key with admin scope, or session with admin role.

Request Body

FieldTypeRequiredDescription
agent_idstringYesUUID of the agent this rule applies to
policy_namestringYesHuman-readable policy name
target_integrationstringYesIntegration this rule matches (e.g., "gmail", "*" for all)
operationstringYesOperation this rule matches (e.g., "send_email", "*" for all)
resource_scopestringYesResource scope pattern (e.g., "production/*")
data_classificationstringYesOne of: public, internal, confidential, restricted
policy_effectstringYesOne of: allow, approval_required, deny
rationalestringYesExplanation for the policy (10-1000 chars, shown to reviewers)
priorityintegerYesPriority (higher = evaluated first)
conditionsobject | nullYesOptional conditions for advanced matching
max_session_ttlinteger | nullYesApproval TTL in seconds (null = use tenant default, which is 86400)
modified_bystringYesName of the person creating the rule
modified_atstringYesISO 8601 datetime

Response

Status: 201 Created

{
  "data": {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "agent_id": "550e8400-...",
    "policy_name": "Require approval for confidential email",
    "target_integration": "gmail",
    "operation": "send_email",
    "resource_scope": "external-recipients",
    "data_classification": "confidential",
    "policy_effect": "approval_required",
    "rationale": "All outbound emails containing confidential data require human approval before sending.",
    "priority": 100,
    "conditions": null,
    "max_session_ttl": 3600,
    "is_active": true,
    "policy_version": 1,
    "modified_by": "Alice Johnson",
    "modified_at": "2026-03-21T10:00:00.000Z",
    "created_at": "2026-03-21T10:00:00.000Z",
    "updated_at": "2026-03-21T10:00:00.000Z"
  }
}

Example

curl -X POST http://localhost:4000/api/v1/policies \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "550e8400-e29b-41d4-a716-446655440000",
    "policy_name": "Require approval for confidential email",
    "target_integration": "gmail",
    "operation": "send_email",
    "resource_scope": "external-recipients",
    "data_classification": "confidential",
    "policy_effect": "approval_required",
    "rationale": "All outbound emails containing confidential data require human approval before sending.",
    "priority": 100,
    "conditions": null,
    "max_session_ttl": 3600,
    "modified_by": "Alice Johnson",
    "modified_at": "2026-03-21T10:00:00.000Z"
  }'

Error Codes

StatusErrorDescription
400validation_errorInvalid or missing fields
401unauthorizedAuthentication required
403forbiddenAdmin role/scope required

GET /api/v1/policies

List policy rules with optional filters and pagination.

Auth: API key with any scope, or any authenticated session.

Query Parameters

ParameterTypeDescription
agent_idstringFilter by agent UUID
effectstringFilter by policy effect (allow, approval_required, deny)
data_classificationstringFilter by data classification
is_activestringFilter by active status (true or false)
searchstringSearch policy names and rationales
limitintegerItems per page (default: 20, max: 100)
offsetintegerNumber of items to skip (default: 0)

Response

Status: 200 OK

{
  "data": [
    {
      "id": "660e8400-...",
      "policy_name": "Require approval for confidential email",
      "policy_effect": "approval_required",
      "is_active": true,
      "priority": 100,
      ...
    }
  ],
  "pagination": {
    "total": 8,
    "limit": 20,
    "offset": 0
  }
}

Example

curl "http://localhost:4000/api/v1/policies?agent_id=550e8400-...&effect=approval_required" \
  -H "Authorization: Bearer sk_live_abc123"

GET /api/v1/policies/:id

Get a single policy rule with full detail.

Auth: API key with any scope, or any authenticated session.

Path Parameters

ParameterTypeDescription
idstringPolicy rule UUID

Response

Status: 200 OK

{
  "data": {
    "id": "660e8400-...",
    "agent_id": "550e8400-...",
    "policy_name": "Require approval for confidential email",
    "target_integration": "gmail",
    "operation": "send_email",
    "resource_scope": "external-recipients",
    "data_classification": "confidential",
    "policy_effect": "approval_required",
    "rationale": "All outbound emails containing confidential data require human approval.",
    "priority": 100,
    "conditions": null,
    "max_session_ttl": 3600,
    "is_active": true,
    "policy_version": 3,
    "modified_by": "Alice Johnson",
    "modified_at": "2026-03-21T12:00:00.000Z",
    "created_at": "2026-03-21T10:00:00.000Z",
    "updated_at": "2026-03-21T12:00:00.000Z"
  }
}

Error Codes

StatusErrorDescription
404not_foundPolicy rule does not exist

PATCH /api/v1/policies/:id

Update a policy rule. At least one field must be provided. Each update automatically increments the policy version and creates a version history entry.

Auth: API key with admin scope, or session with admin role.

Path Parameters

ParameterTypeDescription
idstringPolicy rule UUID

Request Body

All fields are optional. Only provided fields are updated.

FieldTypeDescription
policy_namestringUpdated policy name
target_integrationstringUpdated target integration
operationstringUpdated operation
resource_scopestringUpdated resource scope
data_classificationstringUpdated data classification
policy_effectstringUpdated effect (allow, approval_required, deny)
rationalestringUpdated rationale (10-1000 chars)
priorityintegerUpdated priority
conditionsobject | nullUpdated conditions
max_session_ttlinteger | nullUpdated approval TTL in seconds

Response

Status: 200 OK

{
  "data": {
    "id": "660e8400-...",
    "policy_version": 4,
    ...
  }
}

Example

curl -X PATCH http://localhost:4000/api/v1/policies/660e8400-e29b-41d4-a716-446655440001 \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "priority": 200,
    "rationale": "Updated: all outbound emails with confidential data require manager approval."
  }'

Error Codes

StatusErrorDescription
400validation_errorNo fields provided, or invalid field values
403forbiddenAdmin role/scope required
404not_foundPolicy rule does not exist

DELETE /api/v1/policies/:id

Soft-delete (deactivate) a policy rule. The rule remains in the database for audit purposes but is no longer evaluated by the policy engine.

Auth: API key with admin scope, or session with admin role.

Path Parameters

ParameterTypeDescription
idstringPolicy rule UUID

Response

Status: 200 OK

Returns the deactivated policy rule with is_active: false.

{
  "data": {
    "id": "660e8400-...",
    "is_active": false,
    ...
  }
}

Example

curl -X DELETE http://localhost:4000/api/v1/policies/660e8400-e29b-41d4-a716-446655440001 \
  -H "Authorization: Bearer sk_live_abc123"

Error Codes

StatusErrorDescription
403forbiddenAdmin role/scope required
404not_foundPolicy rule does not exist

GET /api/v1/policies/:id/versions

Get the version history of a policy rule. Each update creates a new version snapshot.

Auth: API key with any scope, or any authenticated session.

Path Parameters

ParameterTypeDescription
idstringPolicy rule UUID

Query Parameters

ParameterTypeDescription
limitintegerItems per page (default: 20)
offsetintegerNumber of items to skip (default: 0)

Response

Status: 200 OK

{
  "data": [
    {
      "id": "880e8400-...",
      "policy_rule_id": "660e8400-...",
      "version": 2,
      "policy_name": "Require approval for confidential email",
      "operation": "send_email",
      "target_integration": "gmail",
      "resource_scope": "external-recipients",
      "data_classification": "confidential",
      "policy_effect": "approval_required",
      "rationale": "Previous rationale text...",
      "priority": 100,
      "conditions": null,
      "max_session_ttl": 3600,
      "modified_by": "Alice Johnson",
      "modified_at": "2026-03-21T11:00:00.000Z",
      "change_summary": null
    }
  ],
  "pagination": {
    "total": 3,
    "limit": 20,
    "offset": 0
  }
}

Example

curl "http://localhost:4000/api/v1/policies/660e8400-.../versions?limit=10" \
  -H "Authorization: Bearer sk_live_abc123"

POST /api/v1/policies/test

Dry-run a policy evaluation without creating an audit trace. Useful for testing policy configurations before deploying them.

Auth: API key with any scope, or any authenticated session.

Request Body

FieldTypeRequiredDescription
agent_idstringYesAgent UUID to evaluate against
operationstringYesOperation to test
target_integrationstringYesTarget integration to test
resource_scopestringYesResource scope to test
data_classificationstringYesData classification to test

Response

Status: 200 OK

Returns the policy engine decision without creating any audit records.

{
  "effect": "approval_required",
  "rule_id": "660e8400-...",
  "rationale": "Confidential data access requires human approval",
  "policy_version": 3
}

Example

curl -X POST http://localhost:4000/api/v1/policies/test \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "550e8400-e29b-41d4-a716-446655440000",
    "operation": "send_email",
    "target_integration": "gmail",
    "resource_scope": "external-recipients",
    "data_classification": "confidential"
  }'

Error Codes

StatusErrorDescription
400validation_errorMissing required fields