> ## Documentation Index
> Fetch the complete documentation index at: https://docs.steward.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Policy Engine

> Declarative policy evaluation on every agent action — default deny, composable rules.

# Policy Engine

The Policy Engine evaluates declarative policies before every agent action. It enforces **default deny** — if no policy explicitly allows an action, it's rejected.

## Design Principles

* **Default deny** — new agents can't do anything until policies are assigned
* **Declarative** — JSON-based policy definitions, no custom DSL to learn
* **Composable** — multiple policies evaluated in order; ALL must pass
* **Fast** — \< 5ms evaluation, cached in Redis

## Policy Types

### Spending Limit

Controls how much value an agent can transact:

```json theme={null}
{
  "id": "spending-limit-1",
  "type": "spending-limit",
  "enabled": true,
  "config": {
    "maxPerTransaction": "100000000000000000",
    "maxPerDay": "500000000000000000",
    "maxPerWeek": "2000000000000000000"
  }
}
```

Values are in **wei** (for EVM) or **lamports** (for Solana). The engine tracks cumulative spend per agent over rolling time windows.

### Approved Addresses

Whitelist of addresses an agent can interact with:

```json theme={null}
{
  "id": "approved-addrs-1",
  "type": "approved-addresses",
  "enabled": true,
  "config": {
    "addresses": [
      "0x1111111254EEB25477B68fb85Ed929f73A960582",
      "0xDef1C0ded9bec7F1a1670819833240f027b25EfF"
    ]
  }
}
```

<Note>
  Approved addresses work as a **whitelist**. If enabled, only transactions to listed addresses are allowed. Disable this policy to allow transactions to any address.
</Note>

### Auto-Approve Threshold

Transactions below this value are auto-approved; above requires manual approval:

```json theme={null}
{
  "id": "auto-approve-1",
  "type": "auto-approve-threshold",
  "enabled": true,
  "config": {
    "maxValue": "50000000000000000"
  }
}
```

When a transaction exceeds the threshold but passes other policies, it enters the **approval queue**. A tenant admin must explicitly approve or reject it.

### Rate Limit

Controls how many transactions an agent can submit:

```json theme={null}
{
  "id": "rate-limit-1",
  "type": "rate-limit",
  "enabled": true,
  "config": {
    "maxPerMinute": 10,
    "maxPerHour": 100
  }
}
```

### Time Window

Restricts when an agent can transact:

```json theme={null}
{
  "id": "time-window-1",
  "type": "time-window",
  "enabled": true,
  "config": {
    "allowedHours": { "start": 8, "end": 22 },
    "timezone": "UTC"
  }
}
```

### Allowed Chains

Restricts which blockchain networks an agent can use:

```json theme={null}
{
  "id": "allowed-chains-1",
  "type": "allowed-chains",
  "enabled": true,
  "config": {
    "chainIds": [8453, 1]
  }
}
```

## Evaluation Flow

```
Incoming Request
    │
    ├─ Load applicable policies (cached, 30s TTL)
    │
    ├─ Evaluate in order:
    │   1. allowed-chains    → DENY/ALLOW
    │   2. approved-addresses → DENY/ALLOW
    │   3. spending-limit    → DENY/ALLOW
    │   4. rate-limit        → DENY/ALLOW
    │   5. time-window       → DENY/ALLOW
    │   6. auto-approve      → AUTO/QUEUE
    │
    │   ALL must pass. First DENY short-circuits.
    │
    ├── ALLOW → Execute action, log result
    ├── DENY  → Return 403, log denial
    └── QUEUE → Hold for manual approval, notify via webhook
```

## Value Units

Policy values are evaluated in the units accepted by the API for the action being checked. EVM transaction limits such as `maxPerTransaction`, `maxPerDay`, and `maxValue` are normally passed as integer wei strings. UI and operator docs may display human ETH/USD equivalents, but policy enforcement should be configured with exact integer values to avoid rounding surprises.

## Policy Results

Every policy evaluation returns detailed results:

```json theme={null}
{
  "approved": false,
  "requiresManualApproval": true,
  "results": [
    { "type": "spending-limit", "passed": true, "reason": "Within daily limit" },
    { "type": "approved-addresses", "passed": true, "reason": "Address whitelisted" },
    { "type": "auto-approve-threshold", "passed": false, "reason": "Value 0.1 ETH exceeds auto-approve threshold of 0.05 ETH" }
  ]
}
```

These results are stored with every transaction record and returned in API responses, making it easy to debug why a transaction was denied or queued.

## Approval Queue

Transactions that pass all policies except auto-approve enter the approval queue:

```typescript theme={null}
// List pending approvals
const pending = await fetch(
  `https://api.steward.fi/vault/${agentId}/pending`,
  { headers: { Authorization: `Bearer ${agentToken}` } }
);

// Approve (requires tenant-level auth)
await fetch(
  `https://api.steward.fi/vault/${agentId}/approve/${txId}`,
  {
    method: "POST",
    headers: { "X-Steward-Key": "tenant-key" },
  }
);

// Reject
await fetch(
  `https://api.steward.fi/vault/${agentId}/reject/${txId}`,
  {
    method: "POST",
    headers: { "X-Steward-Key": "tenant-key" },
  }
);
```

<Note>
  Webhooks are dispatched for `approval_required`, `tx_signed`, `tx_rejected`, and `tx_failed` events. Configure your webhook URL via the [Tenants API](/api-reference/tenants).
</Note>

## Related

* [Policies Guide](/guides/policies) — Configuring policies step-by-step
* [Policies API Reference](/api-reference/policies) — CRUD API for policy management
* [Vault API Reference](/api-reference/vault) — Signing and approval endpoints
