# Rule Management API

This document describes the Rule Management API endpoints for the Attune automation platform.

## Overview

Rules are the core automation logic in Attune that connect triggers to actions. When a trigger fires an event that matches a rule's conditions, the associated action is executed. Rules enable powerful event-driven automation workflows.

**Base Path:** `/api/v1/rules`

## Data Model

### Rule

```json
{
  "id": 1,
  "ref": "mypack.notify_on_error",
  "pack": 1,
  "pack_ref": "mypack",
  "label": "Notify on Error",
  "description": "Send notification when error event is detected",
  "action": 5,
  "action_ref": "slack.send_message",
  "trigger": 3,
  "trigger_ref": "core.error_event",
  "conditions": {
    "and": [
      {"var": "event.severity", ">=": 3},
      {"var": "event.status", "==": "error"}
    ]
  },
  "action_params": {
    "channel": "#alerts",
    "message": "Error in {{ event.payload.service }}: {{ event.payload.message }}",
    "severity": "{{ event.payload.severity }}"
  },
  "enabled": true,
  "created": "2024-01-13T10:00:00Z",
  "updated": "2024-01-13T10:00:00Z"
}
```

**Field Descriptions:**

- `id` (integer) - Unique identifier
- `ref` (string) - Unique reference in format `pack.name`
- `pack` (integer) - Pack ID this rule belongs to
- `pack_ref` (string) - Pack reference
- `label` (string) - Human-readable name
- `description` (string) - Rule description
- `action` (integer) - Action ID to execute
- `action_ref` (string) - Action reference
- `trigger` (integer) - Trigger ID that activates this rule
- `trigger_ref` (string) - Trigger reference
- `conditions` (object) - JSON Logic conditions for rule evaluation
- `action_params` (object) - Parameters to pass to the action (supports dynamic templates)
- `enabled` (boolean) - Whether the rule is active
- `created` (timestamp) - Creation time
- `updated` (timestamp) - Last update time

**Action Parameters:**

The `action_params` field supports both static values and dynamic templates:

- **Static values**: `"channel": "#alerts"`
- **Dynamic from event payload**: `"message": "{{ event.payload.message }}"`
- **Dynamic from pack config**: `"token": "{{ pack.config.api_token }}"`
- **System variables**: `"timestamp": "{{ system.timestamp }}"`

See [Rule Parameter Mapping](./rule-parameter-mapping.md) for complete documentation.

### Rule Summary (List View)

```json
{
  "id": 1,
  "ref": "mypack.notify_on_error",
  "pack_ref": "mypack",
  "label": "Notify on Error",
  "description": "Send notification when error event is detected",
  "action_ref": "slack.send_message",
  "trigger_ref": "core.error_event",
  "enabled": true,
  "created": "2024-01-13T10:00:00Z",
  "updated": "2024-01-13T10:00:00Z"
}
```

## Endpoints

### List All Rules

Retrieve a paginated list of all rules.

**Endpoint:** `GET /api/v1/rules`

**Query Parameters:**
- `page` (integer, optional): Page number (default: 1)
- `per_page` (integer, optional): Items per page (default: 20, max: 100)

**Response:** `200 OK`

```json
{
  "data": [
    {
      "id": 1,
      "ref": "mypack.notify_on_error",
      "pack_ref": "mypack",
      "label": "Notify on Error",
      "description": "Send notification when error event is detected",
      "action_ref": "slack.send_message",
      "trigger_ref": "core.error_event",
      "enabled": true,
      "created": "2024-01-13T10:00:00Z",
      "updated": "2024-01-13T10:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 1,
    "total_pages": 1
  }
}
```

---

### List Enabled Rules

Retrieve only rules that are currently enabled.

**Endpoint:** `GET /api/v1/rules/enabled`

**Query Parameters:**
- `page` (integer, optional): Page number (default: 1)
- `per_page` (integer, optional): Items per page (default: 20, max: 100)

**Response:** `200 OK`

```json
{
  "data": [
    {
      "id": 1,
      "ref": "mypack.notify_on_error",
      "pack_ref": "mypack",
      "label": "Notify on Error",
      "description": "Send notification when error event is detected",
      "action_ref": "slack.send_message",
      "trigger_ref": "core.error_event",
      "enabled": true,
      "created": "2024-01-13T10:00:00Z",
      "updated": "2024-01-13T10:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 1,
    "total_pages": 1
  }
}
```

---

### List Rules by Pack

Retrieve all rules belonging to a specific pack.

**Endpoint:** `GET /api/v1/packs/:pack_ref/rules`

**Path Parameters:**
- `pack_ref` (string): Pack reference identifier

**Query Parameters:**
- `page` (integer, optional): Page number (default: 1)
- `per_page` (integer, optional): Items per page (default: 20, max: 100)

**Response:** `200 OK`

**Errors:**
- `404 Not Found`: Pack with the specified ref does not exist

---

### List Rules by Action

Retrieve all rules that execute a specific action.

**Endpoint:** `GET /api/v1/actions/:action_ref/rules`

**Path Parameters:**
- `action_ref` (string): Action reference identifier

**Query Parameters:**
- `page` (integer, optional): Page number (default: 1)
- `per_page` (integer, optional): Items per page (default: 20, max: 100)

**Response:** `200 OK`

**Errors:**
- `404 Not Found`: Action with the specified ref does not exist

---

### List Rules by Trigger

Retrieve all rules that are activated by a specific trigger.

**Endpoint:** `GET /api/v1/triggers/:trigger_ref/rules`

**Path Parameters:**
- `trigger_ref` (string): Trigger reference identifier

**Query Parameters:**
- `page` (integer, optional): Page number (default: 1)
- `per_page` (integer, optional): Items per page (default: 20, max: 100)

**Response:** `200 OK`

**Errors:**
- `404 Not Found`: Trigger with the specified ref does not exist

---

### Get Rule by Reference

Retrieve a single rule by its reference identifier.

**Endpoint:** `GET /api/v1/rules/:ref`

**Path Parameters:**
- `ref` (string): Rule reference identifier (e.g., "mypack.notify_on_error")

**Response:** `200 OK`

```json
{
  "data": {
    "id": 1,
    "ref": "mypack.notify_on_error",
    "pack": 1,
    "pack_ref": "mypack",
    "label": "Notify on Error",
    "description": "Send notification when error event is detected",
    "action": 5,
    "action_ref": "slack.send_message",
    "trigger": 3,
    "trigger_ref": "core.error_event",
    "conditions": {
      "and": [
        {"var": "event.severity", ">=": 3},
        {"var": "event.status", "==": "error"}
      ]
    },
    "enabled": true,
    "created": "2024-01-13T10:00:00Z",
    "updated": "2024-01-13T10:00:00Z"
  }
}
```

**Errors:**
- `404 Not Found`: Rule with the specified ref does not exist

---



### Create Rule

Create a new rule in the system.

**Endpoint:** `POST /api/v1/rules`

**Request Body:**

```json
{
  "ref": "mypack.notify_on_error",
  "pack_ref": "mypack",
  "label": "Notify on Error",
  "description": "Send notification when error event is detected",
  "action_ref": "slack.send_message",
  "trigger_ref": "core.error_event",
  "conditions": {
    "and": [
      {"var": "event.severity", ">=": 3},
      {"var": "event.status", "==": "error"}
    ]
  },
  "action_params": {
    "channel": "#alerts",
    "message": "Error detected: {{ event.payload.message }}",
    "severity": "{{ event.payload.severity }}"
  },
  "enabled": true
}
```

**Required Fields:**
- `ref`: Unique reference identifier (alphanumeric, dots, underscores, hyphens)
- `pack_ref`: Reference to the parent pack (must exist)
- `label`: Human-readable name (1-255 characters)
- `description`: Rule description (min 1 character)
- `action_ref`: Reference to action to execute (must exist)
- `trigger_ref`: Reference to trigger that activates rule (must exist)

**Optional Fields:**
- `conditions`: JSON Logic conditions for rule evaluation (default: `{}`)
- `action_params`: Parameters to pass to the action (default: `{}`)
  - Supports static values: `"channel": "#alerts"`
  - Supports dynamic templates: `"message": "{{ event.payload.message }}"`
  - Supports pack config: `"token": "{{ pack.config.api_token }}"`
- `enabled`: Whether the rule is active (default: `true`)

**Response:** `201 Created`

```json
{
  "data": {
    "id": 1,
    "ref": "mypack.notify_on_error",
    "pack": 1,
    "pack_ref": "mypack",
    "label": "Notify on Error",
    "description": "Send notification when error event is detected",
    "action": 5,
    "action_ref": "slack.send_message",
    "trigger": 3,
    "trigger_ref": "core.error_event",
    "conditions": {
      "and": [
        {"var": "event.severity", ">=": 3},
        {"var": "event.status", "==": "error"}
      ]
    },
    "action_params": {
      "channel": "#alerts",
      "message": "Error detected: {{ event.payload.message }}",
      "severity": "{{ event.payload.severity }}"
    },
    "enabled": true,
    "created": "2024-01-13T10:00:00Z",
    "updated": "2024-01-13T10:00:00Z"
  },
  "message": "Rule created successfully"
}
```

**Errors:**
- `400 Bad Request`: Invalid request data or validation failure
- `404 Not Found`: Referenced pack, action, or trigger does not exist
- `409 Conflict`: Rule with the same ref already exists

---

### Update Rule

Update an existing rule's properties.

**Endpoint:** `PUT /api/v1/rules/:ref`

**Path Parameters:**
- `ref` (string): Rule reference identifier

**Request Body:**

All fields are optional. Only provided fields will be updated.

```json
{
  "label": "Notify on Critical Errors",
  "description": "Enhanced error notification with filtering",
  "conditions": {
    "and": [
      {"var": "event.severity", ">=": 4},
      {"var": "event.status", "==": "error"}
    ]
  },
  "action_params": {
    "channel": "#critical-alerts",
    "message": "CRITICAL: {{ event.payload.service }} - {{ event.payload.message }}",
    "priority": "high"
  },
  "enabled": false
}
```

**Note:** You cannot change `pack_ref`, `action_ref`, or `trigger_ref` via update. Create a new rule instead.

**Response:** `200 OK`

```json
{
  "data": {
    "id": 1,
    "ref": "mypack.notify_on_error",
    "pack": 1,
    "pack_ref": "mypack",
    "label": "Updated Notify on Error",
    "description": "Updated description",
    "action": 5,
    "action_ref": "slack.send_message",
    "trigger": 3,
    "trigger_ref": "core.error_event",
    "conditions": {
      "and": [
        {"var": "event.severity", ">=": 4},
        {"var": "event.status", "==": "error"}
      ]
    },
    "action_params": {
      "channel": "#critical-alerts",
      "message": "CRITICAL: {{ event.payload.service }} - {{ event.payload.message }}",
      "priority": "high"
    },
    "enabled": false,
    "created": "2024-01-13T10:00:00Z",
    "updated": "2024-01-13T12:00:00Z"
  },
  "message": "Rule updated successfully"
}
```

**Errors:**
- `400 Bad Request`: Invalid request data or validation failure
- `404 Not Found`: Rule with the specified ref does not exist

---

### Enable Rule

Enable a rule to activate it for event processing.

**Endpoint:** `POST /api/v1/rules/:ref/enable`

**Path Parameters:**
- `ref` (string): Rule reference identifier

**Response:** `200 OK`

```json
{
  "data": {
    "id": 1,
    "ref": "mypack.notify_on_error",
    "pack": 1,
    "pack_ref": "mypack",
    "label": "Notify on Error",
    "description": "Send notification when error event is detected",
    "action": 5,
    "action_ref": "slack.send_message",
    "trigger": 3,
    "trigger_ref": "core.error_event",
    "conditions": { ... },
    "enabled": true,
    "created": "2024-01-13T10:00:00Z",
    "updated": "2024-01-13T12:00:00Z"
  },
  "message": "Rule enabled successfully"
}
```

**Errors:**
- `404 Not Found`: Rule with the specified ref does not exist

---

### Disable Rule

Disable a rule to prevent it from processing events.

**Endpoint:** `POST /api/v1/rules/:ref/disable`

**Path Parameters:**
- `ref` (string): Rule reference identifier

**Response:** `200 OK`

```json
{
  "data": {
    "id": 1,
    "ref": "mypack.notify_on_error",
    "pack": 1,
    "pack_ref": "mypack",
    "label": "Notify on Error",
    "description": "Send notification when error event is detected",
    "action": 5,
    "action_ref": "slack.send_message",
    "trigger": 3,
    "trigger_ref": "core.error_event",
    "conditions": { ... },
    "enabled": false,
    "created": "2024-01-13T10:00:00Z",
    "updated": "2024-01-13T12:00:00Z"
  },
  "message": "Rule disabled successfully"
}
```

**Errors:**
- `404 Not Found`: Rule with the specified ref does not exist

---

### Delete Rule

Delete a rule from the system.

**Endpoint:** `DELETE /api/v1/rules/:ref`

**Path Parameters:**
- `ref` (string): Rule reference identifier

**Response:** `200 OK`

```json
{
  "success": true,
  "message": "Rule 'mypack.notify_on_error' deleted successfully"
}
```

**Errors:**
- `404 Not Found`: Rule with the specified ref does not exist

---

## Rule Conditions

Rules use conditions to determine whether an action should be executed when a trigger fires. Conditions are evaluated against the event payload.

### Condition Format

Attune supports JSON Logic format for conditions:

```json
{
  "and": [
    {"var": "event.severity", ">=": 3},
    {"var": "event.status", "==": "error"}
  ]
}
```

### Common Operators

- **Comparison:** `==`, `!=`, `<`, `<=`, `>`, `>=`
- **Logical:** `and`, `or`, `not`
- **Membership:** `in`, `contains`
- **Existence:** `var` (check if variable exists)

### Condition Examples

**Simple equality check:**
```json
{
  "var": "event.status",
  "==": "error"
}
```

**Multiple conditions (AND):**
```json
{
  "and": [
    {"var": "event.severity", ">=": 3},
    {"var": "event.type", "==": "alert"}
  ]
}
```

**Multiple conditions (OR):**
```json
{
  "or": [
    {"var": "event.status", "==": "error"},
    {"var": "event.status", "==": "critical"}
  ]
}
```

**Nested conditions:**
```json
{
  "and": [
    {"var": "event.severity", ">=": 3},
    {
      "or": [
        {"var": "event.type", "==": "alert"},
        {"var": "event.type", "==": "warning"}
      ]
    }
  ]
}
```

**Always match (empty conditions):**
```json
{}
```

---

## Examples

### Creating a Simple Rule

```bash
curl -X POST http://localhost:3000/api/v1/rules \
  -H "Content-Type: application/json" \
  -d '{
    "ref": "mypack.alert_on_high_cpu",
    "pack_ref": "mypack",
    "label": "Alert on High CPU",
    "description": "Send alert when CPU usage exceeds 90%",
    "action_ref": "slack.send_message",
    "trigger_ref": "system.cpu_monitor",
    "conditions": {
      "var": "cpu_percent",
      ">": 90
    },
    "enabled": true
  }'
```

### Creating a Rule with Complex Conditions

```bash
curl -X POST http://localhost:3000/api/v1/rules \
  -H "Content-Type: application/json" \
  -d '{
    "ref": "security.failed_login_alert",
    "pack_ref": "security",
    "label": "Failed Login Alert",
    "description": "Alert on multiple failed login attempts",
    "action_ref": "pagerduty.create_incident",
    "trigger_ref": "auth.login_failure",
    "conditions": {
      "and": [
        {"var": "failed_attempts", ">=": 5},
        {"var": "time_window_minutes", "<=": 10},
        {"var": "user.is_admin", "==": true}
      ]
    }
  }'
```

### Listing Enabled Rules

```bash
curl http://localhost:3000/api/v1/rules/enabled
```

### Listing Rules by Pack

```bash
curl http://localhost:3000/api/v1/packs/mypack/rules
```

### Updating Rule Conditions

```bash
curl -X PUT http://localhost:3000/api/v1/rules/mypack.alert_on_high_cpu \
  -H "Content-Type: application/json" \
  -d '{
    "conditions": {
      "var": "cpu_percent",
      ">": 95
    }
  }'
```

### Disabling a Rule

```bash
curl -X POST http://localhost:3000/api/v1/rules/mypack.alert_on_high_cpu/disable
```

### Enabling a Rule

```bash
curl -X POST http://localhost:3000/api/v1/rules/mypack.alert_on_high_cpu/enable
```

### Deleting a Rule

```bash
curl -X DELETE http://localhost:3000/api/v1/rules/mypack.alert_on_high_cpu
```

---

## Validation Rules

### Rule Reference (`ref`)
- Must be unique across all rules
- Can contain alphanumeric characters, dots (.), underscores (_), and hyphens (-)
- Typically follows the pattern: `pack_name.rule_name`
- Example: `mypack.notify_on_error`, `security.failed_login_alert`

### Pack Reference (`pack_ref`)
- Must reference an existing pack
- The pack must exist before creating rules for it

### Action Reference (`action_ref`)
- Must reference an existing action
- The action will be executed when rule conditions match

### Trigger Reference (`trigger_ref`)
- Must reference an existing trigger
- The trigger determines when the rule is evaluated

### Conditions
- Must be valid JSON
- Typically follows JSON Logic format
- Empty object `{}` means rule always matches
- Conditions are evaluated against event payload

---

## Rule Evaluation Flow

1. **Trigger Fires:** An event occurs that activates a trigger
2. **Find Rules:** System finds all enabled rules for that trigger
3. **Evaluate Conditions:** Each rule's conditions are evaluated against the event payload
4. **Execute Action:** If conditions match, the associated action is executed
5. **Record Enforcement:** Execution is logged as an enforcement record

```
Event → Trigger → Rule Evaluation → Condition Match? → Execute Action
                      ↓                     ↓
                   (conditions)          (yes/no)
```

---

## Best Practices

1. **Naming Conventions**
   - Use descriptive, hierarchical names: `pack.purpose`
   - Keep names concise but meaningful
   - Use lowercase with dots as separators

2. **Condition Design**
   - Start simple, add complexity as needed
   - Test conditions with sample event data
   - Document complex condition logic
   - Consider edge cases and null values

3. **Rule Organization**
   - Group related rules in the same pack
   - One rule per specific automation task
   - Avoid overly complex conditions (split into multiple rules)

4. **Performance**
   - Keep conditions efficient
   - Disable unused rules rather than deleting
   - Use specific conditions to reduce unnecessary action executions

5. **Testing**
   - Test rules in development environment first
   - Start with rules disabled, enable after testing
   - Monitor enforcement records to verify behavior
   - Use `/rules/:ref/disable` to quickly stop problematic rules

6. **Maintenance**
   - Document rule purpose and expected behavior
   - Review and update conditions regularly
   - Clean up obsolete rules
   - Version your condition logic in comments

---

## Common Patterns

### Alert on Threshold

```json
{
  "ref": "monitoring.disk_space_alert",
  "trigger_ref": "system.disk_check",
  "action_ref": "slack.notify",
  "conditions": {
    "var": "disk_usage_percent",
    ">": 85
  }
}
```

### Multi-Condition Filter

```json
{
  "ref": "security.suspicious_activity",
  "trigger_ref": "security.access_log",
  "action_ref": "security.investigate",
  "conditions": {
    "and": [
      {"var": "request.method", "==": "POST"},
      {"var": "response.status", "==": 401},
      {"var": "ip_reputation_score", "<": 50}
    ]
  }
}
```

### Time-Based Rule

```json
{
  "ref": "backup.daily_backup",
  "trigger_ref": "schedule.daily",
  "action_ref": "backup.full_backup",
  "conditions": {
    "var": "hour",
    "==": 2
  }
}
```

---

## Related Documentation

- [Pack Management API](./api-packs.md)
- [Action Management API](./api-actions.md)
- [Trigger Management API](./api-triggers.md)
- [Execution API](./api-executions.md)
- [Event System](./events.md)

---

**Last Updated:** January 13, 2026