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

# Policies

> Wallet governance — what policies are, how rules work, and how policy evaluation decides whether a transaction is authorized.

A **policy** governs which transactions a wallet can authorize. Every wallet must have at least one policy attached before it can sign outbound transactions — Dakota's policy engine **default-denies** any transaction on a wallet with zero attached policies (`"transaction denied: No policies found for wallet"`, HTTP 403). Inbound deposits are independent of policies: an on-chain address can always receive crypto regardless of the wallet's governance.

Policies are versioned, mutable resources. You attach them to wallets, and a wallet can have multiple policies layered on top of one another. The policy engine evaluates all attached policies for every transaction and applies the result.

## Anatomy of a Policy

A policy is three things:

1. **A signer group that governs the policy itself.** Future mutations of the policy — adding rules, deleting it, updating limits — must be signed by members of this group via the [endorsed-request flow](/documentation/wallet-signing#modifying-policies-wallets-and-signer-groups). It can be the same group attached to the wallet, or a separate admin group for stricter compartmentalization.
2. **One or more rules.** Each rule has a `rule_type`, an `action` (`allow` or `deny`), and a `definition` whose shape depends on the rule type.
3. **Metadata.** A human-readable `name` and optional `description`.

```json theme={null}
{
  "id": "pol_2LfQm5KMnRvLFtRP7nJJug4zJEP",
  "client_id": "1NFHrqBHb3cTfLVkFSGmHZqdDPi",
  "signer_group_id": "grp_2LfPqT9VmQzKDvQP9rGHth3yHCN",
  "version": 1,
  "name": "Treasury default policy",
  "description": "Single-signature for transfers under $10k; two signatures otherwise",
  "rules": [
    { "rule_type": "approval_threshold", "action": "allow",
      "definition": { "threshold": 1 } },
    { "rule_type": "amount_threshold",   "action": "deny",
      "definition": {
        "min_amount": 1000000,
        "threshold": 0,
        "asset": { "id": "USD", "name": "US Dollar" }
      } }
  ],
  "created_at": 1640995200,
  "updated_at": 1640995200
}
```

## Rule Types

There are three rule types. Each evaluates a different aspect of the transaction.

### `approval_threshold`

Requires a minimum number of valid signatures from the policy's signer group.

```json theme={null}
{
  "rule_type": "approval_threshold",
  "action": "allow",
  "definition": { "threshold": 2, "description": "Requires 2-of-N approval" }
}
```

* `threshold` — minimum number of signers required.
* The rule **always applies** to every transaction (it's a count check, not a conditional).
* If the threshold is met → emit the rule's `action` (allow or deny). If not met → emit the inverted action.

The minimum permissive policy — *"any single member can authorize anything"* — is `approval_threshold` with `threshold: 1` and `action: allow`.

### `amount_threshold`

Sets transaction-value limits. Useful for tiered approval (small transfers single-sig, large transfers multi-sig) or hard caps.

```json theme={null}
{
  "rule_type": "amount_threshold",
  "action": "deny",
  "definition": {
    "min_amount": 1000000,
    "threshold": 0,
    "asset": { "id": "USD", "name": "US Dollar" }
  }
}
```

* `min_amount` — integer in the smallest currency unit (USD → cents). The example above is \$10,000.00.
* `threshold` — number of approvals required to override. `0` means hard deny; higher values mean N approvers can let it through.
* `asset` — object with `id` (asset symbol, e.g. `USD`) and `name` (display name).
* The rule applies only when the transaction's amount in `asset` is at or above `min_amount`. Below the threshold, the rule does not apply (does not contribute allow or deny).

### `address_list`

Restricts which on-chain destinations a wallet can send to. Allow-list (only these) or deny-list (block these).

```json theme={null}
{
  "rule_type": "address_list",
  "action": "allow",
  "definition": {
    "addresses": [
      "0x742d35Cc6634C0532925a3b8D404fA40b5398Ad2",
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    ]
  }
}
```

* The rule applies only when the destination address is in the `addresses` list.
* For an allow-list, set `action: allow` and pair with a default-deny in another rule (or rely on the policy engine's default-deny on no-applicable-policy).
* For a deny-list, set `action: deny` and the listed addresses are blocked outright.

## Evaluation Order

For a given transaction, the policy engine:

1. **Loads every policy attached to the wallet.** If zero policies, return `deny` immediately (`"No policies found for wallet"`).
2. **For each policy, evaluates each rule in turn.** A rule produces one of: applied + allow, applied + deny, or not-applicable.
3. **Aggregates per policy:** if any rule denies → policy = deny. Else if any rule allows → policy = allow. Else (no rule applied) → policy = not-applicable.
4. **Aggregates across policies:** if any policy denies → transaction = deny. Else if any policy allows → transaction = allow. Else (no applicable policy) → transaction = deny (default).

Translation: **deny wins, allow loses, silence is deny**. Layering policies is safe — adding more policies can only block transactions, never relax existing controls.

## Lifecycle

| Operation          | Endpoint                                           | Endorsed? | Signed by                                 |
| ------------------ | -------------------------------------------------- | --------- | ----------------------------------------- |
| Create policy      | `POST /policies`                                   | No        | API key only                              |
| Add a rule         | `POST /policies/{policy_id}/rules`                 | Yes       | Policy's own signer group                 |
| Update a rule      | `PATCH /policies/{policy_id}/rules/{rule_id}`      | Yes       | Policy's own signer group                 |
| Remove a rule      | `DELETE /policies/{policy_id}/rules/{rule_id}`     | Yes       | Policy's own signer group                 |
| Delete policy      | `DELETE /policies/{policy_id}`                     | Yes       | Policy's own signer group                 |
| Attach to wallet   | `PUT /policies/{policy_id}/wallets/{wallet_id}`    | Yes       | A signer group attached to the **wallet** |
| Detach from wallet | `DELETE /policies/{policy_id}/wallets/{wallet_id}` | Yes       | A signer group attached to the **wallet** |

Policy creation itself is **not** endorsed — it's a regular API request authenticated only by your API key. Once the policy exists, every subsequent mutation goes through the [endorsed-request flow](/documentation/wallet-signing#modifying-policies-wallets-and-signer-groups): canonicalize the intent per RFC 8785 JCS, sign with ECDSA P-256, encode as DER + base64.

## Practical Examples

### "Default permissive" — single signature, no restrictions

For sandbox testing or low-risk accounts:

```json theme={null}
{
  "name": "Default single-signature policy",
  "signer_group_id": "grp_admin",
  "rules": [
    { "rule_type": "approval_threshold", "action": "allow",
      "definition": { "threshold": 1 } }
  ]
}
```

### "Tiered approval by amount" — single-sig under \$10k, dual-sig above

```json theme={null}
{
  "name": "Tiered approval policy",
  "signer_group_id": "grp_admin",
  "rules": [
    { "rule_type": "approval_threshold", "action": "allow",
      "definition": { "threshold": 1 } },
    { "rule_type": "amount_threshold", "action": "deny",
      "definition": {
        "min_amount": 1000000,
        "threshold": 0,
        "asset": { "id": "USD", "name": "US Dollar" }
      } },
    { "rule_type": "approval_threshold", "action": "allow",
      "definition": { "threshold": 2 } }
  ]
}
```

The deny-wins logic blocks single-sig above \$10k; the second `approval_threshold` rule lets dual-sig through.

### "Sanctions deny-list" — block specific addresses outright

```json theme={null}
{
  "name": "OFAC blocklist",
  "signer_group_id": "grp_compliance",
  "rules": [
    { "rule_type": "address_list", "action": "deny",
      "definition": { "addresses": ["0xSanctionedAddress1", "0xSanctionedAddress2"] } }
  ]
}
```

Stack this alongside other policies — its deny will override any allow from sibling policies.

## Related

* [Common Flows — Create a Policy](/documentation/common-flows#create-a-policy) — happy-path curl walk-through.
* [Wallet Transaction Signing](/documentation/wallet-signing#modifying-policies-wallets-and-signer-groups) — endorsed-request flow for mutating an existing policy or attaching/detaching to a wallet.
* [Wallets](/documentation/wallets) — architectural overview of signer groups, policies, and intents.
