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

# Advanced Policies

> Advanced policy configurations and rule engine

# Advanced Policies

Advanced policy types and the rule engine for complex business requirements.

## Policy Rules

Each policy consists of one or more **rules**. Rules define specific conditions and actions:

### Rule Structure

```json theme={null}
{
  "ruleType": "MAX_AMOUNT",
  "operator": "GREATER_THAN",
  "value": "500",
  "action": "REQUIRE_APPROVAL"
}
```

| Field      | Description                                                                  |
| ---------- | ---------------------------------------------------------------------------- |
| `ruleType` | Type of condition (see below)                                                |
| `operator` | Comparison operator                                                          |
| `value`    | JSON-encoded value for comparison. Store objects and arrays as JSON strings. |
| `action`   | `ALLOW`, `DENY`, or `REQUIRE_APPROVAL`                                       |

<Info>
  `POST /api/policies` accepts inline `rules` and is the safest API path for advanced rule types
  today. The standalone `POST /api/policies/{policyId}/rules` route currently accepts the standard
  rule subset and rejects x402, MPP, card, AgentScore, and Fairscale rule types until its schema is
  widened.
</Info>

### Supported Rule Types

Each rule type below maps to a dedicated strategy module in the policy engine.
The engine dispatches evaluation through a registry, so adding a new rule type
means adding a new strategy file rather than modifying core engine code.

| Rule Type                | Description                       | Example Value                                                                                |
| ------------------------ | --------------------------------- | -------------------------------------------------------------------------------------------- |
| `MAX_AMOUNT`             | Per-transaction amount            | `"500"`                                                                                      |
| `DAILY_LIMIT`            | Daily spend cap                   | `"1000"`                                                                                     |
| `WEEKLY_LIMIT`           | Weekly spend cap                  | `"5000"`                                                                                     |
| `MONTHLY_LIMIT`          | Monthly spend cap                 | `"20000"`                                                                                    |
| `BUDGET_CAP`             | Budget allocation                 | `"{\"amount\": 50000, \"period\": \"MONTHLY\"}"`                                             |
| `TIME_WINDOW`            | Time window restriction           | `"{\"start\": \"09:00\", \"end\": \"18:00\"}"`                                               |
| `DAY_OF_WEEK`            | Day restriction                   | `"[\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\"]"`                                            |
| `DATE_RANGE`             | Temporal validity                 | `"{\"start\": \"2025-07-01\", \"end\": \"2025-09-30\"}"`                                     |
| `BLACKOUT_PERIOD`        | Block during windows              | `"{\"windows\": [{\"start\": \"02:00\", \"end\": \"06:00\", \"reason\": \"Maintenance\"}]}"` |
| `ALLOWED_CATEGORIES`     | Allowed categories                | `"[\"software\", \"infrastructure\"]"`                                                       |
| `BLOCKED_CATEGORIES`     | Blocked categories                | `"[\"gambling\", \"adult\"]"`                                                                |
| `ALLOWED_COUNTERPARTIES` | Allowed addresses                 | `"[\"0x123...\", \"0x456...\"]"`                                                             |
| `BLOCKED_COUNTERPARTIES` | Blocked addresses                 | `"[\"0xdead...\"]"`                                                                          |
| `VELOCITY_LIMIT`         | Transaction frequency             | `"{\"maxCount\": 10, \"period\": \"HOUR\"}"`                                                 |
| `REQUIRE_APPROVAL_ABOVE` | Approval threshold                | `"2500"`                                                                                     |
| `GEOGRAPHIC_RESTRICTION` | Blocked countries                 | `"[\"CU\", \"IR\", \"KP\", \"SY\", \"RU\"]"`                                                 |
| `TRUST_SCORE`            | Min trust score                   | `"0.7"`                                                                                      |
| `COUNTERPARTY_STATUS`    | Trust level requirement           | `"{\"status\": \"TRUSTED\"}"`                                                                |
| `CONTRACT_ALLOWLIST`     | Allowed contracts                 | `"{\"contracts\": [\"0x...\"], \"protocols\": [\"uniswap\"]}"`                               |
| `FAIRSCALE_MIN_SCORE`    | Min Fairscale reputation (Solana) | `"0.7"`                                                                                      |

<Warning>
  The current payment evaluation context does not populate `fairscaleScore` directly, so
  `FAIRSCALE_MIN_SCORE` fails closed when configured as an `ALLOW` rule. Use `TRUST_SCORE` for
  production policy gates until the Fairscale context is wired through the payment flow.
</Warning>

### Supported Operators

| Operator       | Description                            |
| -------------- | -------------------------------------- |
| `EQUALS`       | Exact match                            |
| `NOT_EQUALS`   | Not equal                              |
| `GREATER_THAN` | Greater than                           |
| `GTE`          | Greater than or equal                  |
| `LESS_THAN`    | Less than                              |
| `LTE`          | Less than or equal                     |
| `IN`           | Value in list (also `IN_LIST`)         |
| `NOT_IN`       | Value not in list (also `NOT_IN_LIST`) |
| `BETWEEN`      | Within range                           |
| `NOT_BETWEEN`  | Outside range                          |

### Rule Actions

* **`ALLOW`** - The condition describes what is permitted. If it does not match, the payment is denied.
* **`DENY`** - The condition describes what is blocked. If it matches, the payment is denied.
* **`REQUIRE_APPROVAL`** - The condition describes what needs review. If it matches and no DENY fires, the payment requires manual approval.

### Example: High-Value Approval Rule

Block transactions over \$500 unless manually approved:

```json theme={null}
{
  "name": "High Value Transaction Review",
  "policyType": "APPROVAL_THRESHOLD",
  "priority": 80,
  "rules": [
    {
      "ruleType": "REQUIRE_APPROVAL_ABOVE",
      "operator": "GREATER_THAN",
      "value": "500",
      "action": "REQUIRE_APPROVAL"
    }
  ]
}
```

## Geographic Restrictions (OFAC)

Geographic restrictions include both **built-in enforcement** (always active) and **configurable rules** (via policies).

### Built-in Enforcement

The policy evaluator automatically performs two checks before any other policy is evaluated:

1. **Country check**: If `recipientCountry` is provided in the payment context, it's checked against the OFAC sanctioned countries list. Blocked immediately if matched.
2. **Address sanctions screening**: The recipient address is screened against sanctions lists via the configured provider (Chainalysis, TRM Labs, or a local OFAC SDN list). Blocked immediately if flagged.

Configure the sanctions provider via the `SANCTIONS_PROVIDER` environment variable:

* `chainalysis`: Chainalysis Risk API (requires `CHAINALYSIS_API_KEY`)
* `trm`: TRM Labs API (requires `TRM_API_KEY`)
* `local`: Local OFAC SDN list (default, no API key needed)

### Local Provider Lifecycle

When `SANCTIONS_PROVIDER=local`, Conto checks recipient addresses against the `SanctionedAddress`
table in the application database rather than a hardcoded sample list.

* The `20260506000000_add_sanctioned_address` migration seeds the table with known
  high-confidence matches so new deployments are never empty.
* The `sanctions-list-refresh` scheduled job refreshes the table from configured OFAC feeds and
  records refresh metadata for auditability.
* If upstream feeds are temporarily unavailable, the seeded dataset remains in place so sanctions
  screening still has a conservative baseline.

<Info>
  To enable country-based blocking, include `recipientCountry` (ISO 3166-1 alpha-2, e.g., `"US"`,
  `"IR"`) in the `PaymentContext` when calling the evaluator. The SDK payment endpoints populate
  this automatically when available.
</Info>

### Configurable Rules

Add custom country allow/deny lists on top of the built-in checks:

```bash theme={null}
curl -X POST https://conto.finance/api/policies/{policyId}/rules \
  -H "Authorization: Bearer $CONTO_API_KEY" \
  -d '{
    "rules": [
      {
        "ruleType": "GEOGRAPHIC_RESTRICTION",
        "operator": "IN_LIST",
        "value": "[\"US\", \"GB\", \"DE\", \"FR\"]",
        "action": "ALLOW"
      }
    ]
  }'
```

### OFAC Sanctioned Countries (Built-in)

| Code | Country     |
| ---- | ----------- |
| CU   | Cuba        |
| IR   | Iran        |
| KP   | North Korea |
| SY   | Syria       |
| RU   | Russia      |
| BY   | Belarus     |
| MM   | Myanmar     |
| VE   | Venezuela   |
| SD   | Sudan       |
| SS   | South Sudan |
| LB   | Lebanon     |
| LY   | Libya       |
| SO   | Somalia     |
| YE   | Yemen       |

<Warning>
  Always consult legal counsel for compliance requirements. This is not legal advice.
</Warning>

## Approval Thresholds

Require manual approval above certain amounts:

```json theme={null}
{
  "name": "Approval Over 500",
  "policyType": "APPROVAL_THRESHOLD",
  "priority": 70,
  "rules": [
    {
      "ruleType": "REQUIRE_APPROVAL_ABOVE",
      "operator": "GREATER_THAN",
      "value": "500",
      "action": "REQUIRE_APPROVAL"
    }
  ]
}
```

When triggered:

* Payment returns `REQUIRES_APPROVAL`
* Approvers are notified
* Payment held until approved or denied

Conto records only one final approval decision for each request, even if multiple approvers act at nearly the same time. This prevents the same payment from being resolved twice.

For external channels, email approvals use per-user confirmation links. Shared channels such as Slack, Telegram, WhatsApp, and generic webhooks deep-link back to the dashboard until the acting approver can be verified reliably.

When you pair policy rules with approval workflows, you can also scope the
workflow itself to a specific set of agent IDs. That is useful for verifier
pilots where only one or two agents should route into an external approval
channel while the rest of the org keeps its normal flow.

Approval workflows are evaluated for every non-denied payment, so a matching
workflow can still hold a request after the policy engine would otherwise allow
it. Use this for layered controls, such as routing approved invoice payments
through an external verifier before execution.

## Velocity Limits

Control transaction frequency:

```bash theme={null}
curl -X POST https://conto.finance/api/policies/{policyId}/rules \
  -H "Authorization: Bearer $CONTO_API_KEY" \
  -d '{
    "rules": [
      {
        "ruleType": "VELOCITY_LIMIT",
        "operator": "LESS_THAN",
        "value": "{\"maxCount\": 10, \"period\": \"HOUR\"}",
        "action": "ALLOW"
      },
      {
        "ruleType": "VELOCITY_LIMIT",
        "operator": "LESS_THAN",
        "value": "{\"maxAmount\": 1000, \"period\": \"DAILY\"}",
        "action": "ALLOW"
      }
    ]
  }'
```

<Note>
  Velocity counting is **per-wallet, per-agent**. It counts transactions with status CONFIRMED or
  PENDING. The current transaction is included in the count (+1).
</Note>

Use cases:

* Prevent rapid drain attacks
* Detect unusual patterns
* Rate limit agent activity

## Category Restrictions

Allow or block specific categories:

```bash theme={null}
curl -X POST https://conto.finance/api/policies/{policyId}/rules \
  -H "Authorization: Bearer $CONTO_API_KEY" \
  -d '{
    "rules": [
      {
        "ruleType": "BLOCKED_CATEGORIES",
        "operator": "IN_LIST",
        "value": "[\"gambling\", \"adult\", \"weapons\"]",
        "action": "DENY"
      },
      {
        "ruleType": "ALLOWED_CATEGORIES",
        "operator": "IN_LIST",
        "value": "[\"infrastructure\", \"ai_services\", \"marketing\"]",
        "action": "ALLOW"
      }
    ]
  }'
```

<Note>
  Category matching is **case-insensitive**. If no `category` is provided in the payment request,
  `ALLOWED_CATEGORIES` rules with `ALLOW` action deny for safety because the allow condition cannot
  be verified. `BLOCKED_CATEGORIES` rules skip when no category is present.
</Note>

## Contract Allowlist

Restrict agent interactions to approved smart contracts, protocols, and function selectors. Contract metadata is auto-populated from the **Contract Registry**.

### Setting Up the Contract Registry

Register known contracts so the policy evaluator can enrich payment requests with protocol metadata:

```bash theme={null}
curl -X POST https://conto.finance/api/contract-registry \
  -H "Authorization: Bearer $CONTO_ORG_API_KEY" \
  -d '{
    "address": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
    "protocolName": "uniswap",
    "protocolCategory": "DEX",
    "label": "Uniswap V2 Router",
    "chainId": "1"
  }'
```

### Contract Allowlist Rules

```json theme={null}
{
  "policyType": "CONTRACT_ALLOWLIST",
  "rules": [
    {
      "ruleType": "CONTRACT_ALLOWLIST",
      "operator": "IN_LIST",
      "value": "{\"protocols\": [\"uniswap\", \"aave\"], \"categories\": [\"DEX\", \"LENDING\"]}",
      "action": "ALLOW"
    }
  ]
}
```

The value supports four filter types (all optional):

| Field        | Description                       | Example                        |
| ------------ | --------------------------------- | ------------------------------ |
| `contracts`  | Allowed contract addresses        | `["0x7a25...", "0x1f98..."]`   |
| `protocols`  | Allowed protocol names            | `["uniswap", "aave"]`          |
| `categories` | Allowed protocol categories       | `["DEX", "LENDING", "BRIDGE"]` |
| `functions`  | Allowed 4-byte function selectors | `["0xa9059cbb", "0x095ea7b3"]` |

### Passing Contract Context in Payment Requests

Include `targetContractAddress` (and optionally `functionSelector`) in payment requests:

```typescript theme={null}
const result = await conto.payments.request({
  amount: 100,
  recipientAddress: '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
  purpose: 'Swap USDC for ETH',
  targetContractAddress: '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
  functionSelector: '0x38ed1739',
});
```

The evaluator automatically looks up `protocolName` and `protocolCategory` from the Contract Registry. If the caller provides them explicitly, those values take precedence over the registry lookup.

<Note>
  If a `CONTRACT_ALLOWLIST` rule with `ALLOW` action exists but the payment request does not include
  `targetContractAddress`, the request is **denied** (fail-closed). This prevents bypassing the
  allowlist by omitting context.
</Note>

## Budget Allocations

Cap cumulative spend over a period with a `BUDGET_CAP` rule. Scope it to a team or project by
assigning the policy to the agents that belong to that team:

```json theme={null}
{
  "name": "Engineering Monthly Budget",
  "policyType": "BUDGET_ALLOCATION",
  "priority": 60,
  "rules": [
    {
      "ruleType": "BUDGET_CAP",
      "operator": "LTE",
      "value": "{\"amount\": 50000, \"period\": \"MONTHLY\"}",
      "action": "ALLOW"
    }
  ]
}
```

`BUDGET_CAP` aggregates the agent's spend for the period and allows the payment only if the running
total stays at or under `amount`.

## Expiration Policies

Limit a permission to a date window with a `DATE_RANGE` rule. Outside the window the `ALLOW` rule
stops matching, so the payment is denied:

```json theme={null}
{
  "name": "Trial Period Access",
  "policyType": "EXPIRATION",
  "priority": 60,
  "rules": [
    {
      "ruleType": "DATE_RANGE",
      "operator": "BETWEEN",
      "value": "{\"start\": \"2026-07-01T00:00:00Z\", \"end\": \"2026-09-30T23:59:59Z\"}",
      "action": "ALLOW"
    }
  ]
}
```

Use cases:

* Temporary elevated access
* Trial periods
* Contract-based time limits

## Composite Policies

A `COMPOSITE` policy groups several rules that must **all** pass. Conto combines rules within a
policy, and all policies assigned to an agent, with AND logic. There is no nested OR condition tree.
To allow alternatives, widen a single rule's allowlist rather than trying to OR two rules together.

```json theme={null}
{
  "name": "Infrastructure Spend Guardrail",
  "policyType": "COMPOSITE",
  "priority": 70,
  "rules": [
    {
      "ruleType": "MAX_AMOUNT",
      "operator": "LTE",
      "value": "1000",
      "action": "ALLOW"
    },
    {
      "ruleType": "ALLOWED_CATEGORIES",
      "operator": "IN_LIST",
      "value": "[\"infrastructure\"]",
      "action": "ALLOW"
    }
  ]
}
```

## Example: High-Security Agent

Complete configuration for a high-security agent. Each policy holds real rules, and all four are
evaluated together with AND logic:

```json theme={null}
[
  {
    "name": "OFAC Compliance",
    "policyType": "GEOGRAPHIC",
    "priority": 100,
    "rules": [
      {
        "ruleType": "GEOGRAPHIC_RESTRICTION",
        "operator": "NOT_IN",
        "value": "[\"KP\", \"IR\", \"SY\", \"CU\", \"RU\"]",
        "action": "ALLOW"
      }
    ]
  },
  {
    "name": "Whitelist Only",
    "policyType": "WHITELIST",
    "priority": 90,
    "rules": [
      {
        "ruleType": "ALLOWED_COUNTERPARTIES",
        "operator": "IN_LIST",
        "value": "[\"0x1234567890abcdef1234567890abcdef12345678\"]",
        "action": "ALLOW"
      }
    ]
  },
  {
    "name": "Strict Limits",
    "policyType": "SPEND_LIMIT",
    "priority": 80,
    "rules": [
      { "ruleType": "MAX_AMOUNT", "operator": "LTE", "value": "100", "action": "ALLOW" },
      { "ruleType": "DAILY_LIMIT", "operator": "LTE", "value": "500", "action": "ALLOW" }
    ]
  },
  {
    "name": "All Require Approval",
    "policyType": "APPROVAL_THRESHOLD",
    "priority": 70,
    "rules": [
      {
        "ruleType": "REQUIRE_APPROVAL_ABOVE",
        "operator": "GREATER_THAN",
        "value": "0",
        "action": "REQUIRE_APPROVAL"
      }
    ]
  }
]
```

### x402 Protocol Rules

These rules govern HTTP 402 micropayments made through the x402 protocol:

| Rule Type                    | Description                        | Value Format                                         |
| ---------------------------- | ---------------------------------- | ---------------------------------------------------- |
| `X402_MAX_PER_REQUEST`       | Maximum amount per x402 request    | `N` or `{"amount": N}`                               |
| `X402_PRICE_CEILING`         | Price ceiling for any x402 payment | `N` or `{"amount": N}`                               |
| `X402_MAX_PER_ENDPOINT`      | Limit per API endpoint             | `{"maxAmount": N, "maxCalls": N, "period": "DAILY"}` |
| `X402_MAX_PER_SERVICE`       | Limit per service domain           | `{"maxAmount": N, "maxCalls": N, "period": "DAILY"}` |
| `X402_ALLOWED_SERVICES`      | Allowlist of service domains       | `["api.example.com", "data.service.io"]`             |
| `X402_BLOCKED_SERVICES`      | Blocklist of service domains       | `["malicious.site"]`                                 |
| `X402_ALLOWED_FACILITATORS`  | Allowed x402 facilitator addresses | `["0x..."]`                                          |
| `X402_VELOCITY_PER_ENDPOINT` | Rate limit per endpoint            | `{"maxCalls": N, "period": "HOUR"}`                  |
| `X402_SESSION_BUDGET`        | Session-level spending budget      | `N`                                                  |

`X402_SESSION_BUDGET` evaluates spend from x402 records that share the same `sessionId`. The
counter ignores generic wallet transactions and other x402 sessions.

### MPP Protocol Rules

These rules govern Machine Payment Protocol (MPP) session-based micropayments:

| Rule Type                     | Description                        | Value Format                                         |
| ----------------------------- | ---------------------------------- | ---------------------------------------------------- |
| `MPP_MAX_PER_REQUEST`         | Maximum per MPP credential charge  | `N` or `{"amount": N}`                               |
| `MPP_PRICE_CEILING`           | Price ceiling for MPP payments     | `N` or `{"amount": N}`                               |
| `MPP_MAX_PER_ENDPOINT`        | Limit per MPP resource endpoint    | `{"maxAmount": N, "maxCalls": N}`                    |
| `MPP_MAX_PER_SERVICE`         | Limit per MPP service domain       | `{"maxAmount": N, "maxCalls": N, "period": "DAILY"}` |
| `MPP_ALLOWED_SERVICES`        | Allowlist of MPP service domains   | `["api.example.com"]`                                |
| `MPP_BLOCKED_SERVICES`        | Blocklist of MPP service domains   | `["blocked.site"]`                                   |
| `MPP_SESSION_BUDGET`          | Session-level spending budget      | `N`                                                  |
| `MPP_MAX_SESSION_DEPOSIT`     | Hard cap on session deposit amount | `N`                                                  |
| `MPP_MAX_CONCURRENT_SESSIONS` | Max active sessions per agent      | `N`                                                  |
| `MPP_MAX_SESSION_DURATION`    | Maximum session duration in hours  | `N`                                                  |
| `MPP_BLOCK_SESSION_INTENT`    | Block opening MPP sessions         | any value; condition checks `intent === "session"`   |
| `MPP_VELOCITY_PER_ENDPOINT`   | Rate limit per MPP endpoint        | `{"maxCalls": N, "period": "HOUR"}`                  |

`MPP_SESSION_BUDGET` evaluates spend from MPP records that share the same `sessionId`. Record
settled per-call detail in `batchItems` when multiple charges are included in one settlement.

<Warning>
  Avoid `MPP_ALLOWED_METHODS` until the runtime check is fixed. The current strategy is inverted and
  can deny methods that are listed as allowed.
</Warning>

### AgentScore Commerce Rules

These rules fold merchant identity and compliance checks into the normal Conto policy engine. They
apply when the payment flow includes an AgentScore assess step, either because your agent is paying
an AgentScore-gated merchant or because the merchant uses a conto-hosted gate.

| Rule Type                          | Purpose                                    | Example Value |
| ---------------------------------- | ------------------------------------------ | ------------- |
| `AGENTSCORE_REQUIRE_VERIFIED`      | Require a verified human behind the agent  | `"true"`      |
| `AGENTSCORE_ALLOWED_JURISDICTIONS` | Allow only specific operator jurisdictions | `["US","CA"]` |
| `AGENTSCORE_BLOCKED_JURISDICTIONS` | Deny specific operator jurisdictions       | `["IR","KP"]` |

When a merchant gate needs more identity proof, Conto returns a `402`/`403` step-up response with a
verification URL, stores an `AgentScoreVerification` session, and resumes the payment after the
session reaches `VERIFIED`. The final allow/deny decision still runs back through the policy
evaluator so AgentScore-derived jurisdiction or verification status can trip normal deny rules.

### Card Payment Rules

These rules govern card-based payments (virtual or physical):

| Rule Type                | Description                     | Value Format           |
| ------------------------ | ------------------------------- | ---------------------- |
| `CARD_MAX_AMOUNT`        | Maximum per card transaction    | `"500"`                |
| `CARD_ALLOWED_MCCS`      | Allowed merchant category codes | `["5411", "5812"]`     |
| `CARD_BLOCKED_MCCS`      | Blocked merchant category codes | `["7995"]`             |
| `CARD_ALLOWED_MERCHANTS` | Allowed merchant names          | `["Amazon", "Stripe"]` |
| `CARD_BLOCKED_MERCHANTS` | Blocked merchant names          | `["Casino.com"]`       |

## Bulk Policy Operations

### Create Multiple Policies

```bash theme={null}
curl -X POST https://conto.finance/api/policies/bulk \
  -H "Authorization: Bearer $CONTO_API_KEY" \
  -d '{
    "policies": [
      { "name": "Policy 1", "policyType": "SPEND_LIMIT", ... },
      { "name": "Policy 2", "policyType": "TIME_WINDOW", ... }
    ]
  }'
```

### Assign to Multiple Agents

```bash theme={null}
curl -X PUT https://conto.finance/api/policies/bulk \
  -H "Authorization: Bearer $CONTO_API_KEY" \
  -d '{
    "assignments": [
      { "policyId": "cmm5c2pol002n49h7dmsuc33r", "agentIds": ["cmm5a4agt005q49h7bjqza66u", "cmm5a5agt006r49h7bjqza77v"] },
      { "policyId": "cmm5c3pol003o49h7dmsuc44s", "agentIds": ["cmm5a6agt007s49h7bjqza88w"] }
    ]
  }'
```
