Skip to main content

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

{
  "ruleType": "MAX_AMOUNT",
  "operator": "GREATER_THAN",
  "value": "500",
  "action": "REQUIRE_APPROVAL"
}
FieldDescription
ruleTypeType of condition (see below)
operatorComparison operator
valueJSON-encoded value for comparison. Store objects and arrays as JSON strings.
actionALLOW, DENY, or REQUIRE_APPROVAL
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.

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 TypeDescriptionExample Value
MAX_AMOUNTPer-transaction amount"500"
DAILY_LIMITDaily spend cap"1000"
WEEKLY_LIMITWeekly spend cap"5000"
MONTHLY_LIMITMonthly spend cap"20000"
BUDGET_CAPBudget allocation"{\"amount\": 50000, \"period\": \"MONTHLY\"}"
TIME_WINDOWTime window restriction"{\"start\": \"09:00\", \"end\": \"18:00\"}"
DAY_OF_WEEKDay restriction"[\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\"]"
DATE_RANGETemporal validity"{\"start\": \"2025-07-01\", \"end\": \"2025-09-30\"}"
BLACKOUT_PERIODBlock during windows"{\"windows\": [{\"start\": \"02:00\", \"end\": \"06:00\", \"reason\": \"Maintenance\"}]}"
ALLOWED_CATEGORIESAllowed categories"[\"software\", \"infrastructure\"]"
BLOCKED_CATEGORIESBlocked categories"[\"gambling\", \"adult\"]"
ALLOWED_COUNTERPARTIESAllowed addresses"[\"0x123...\", \"0x456...\"]"
BLOCKED_COUNTERPARTIESBlocked addresses"[\"0xdead...\"]"
VELOCITY_LIMITTransaction frequency"{\"maxCount\": 10, \"period\": \"HOUR\"}"
REQUIRE_APPROVAL_ABOVEApproval threshold"2500"
GEOGRAPHIC_RESTRICTIONBlocked countries"[\"CU\", \"IR\", \"KP\", \"SY\", \"RU\"]"
TRUST_SCOREMin trust score"0.7"
COUNTERPARTY_STATUSTrust level requirement"{\"status\": \"TRUSTED\"}"
CONTRACT_ALLOWLISTAllowed contracts"{\"contracts\": [\"0x...\"], \"protocols\": [\"uniswap\"]}"
FAIRSCALE_MIN_SCOREMin Fairscale reputation (Solana)"0.7"
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.

Supported Operators

OperatorDescription
EQUALSExact match
NOT_EQUALSNot equal
GREATER_THANGreater than
GTEGreater than or equal
LESS_THANLess than
LTELess than or equal
INValue in list (also IN_LIST)
NOT_INValue not in list (also NOT_IN_LIST)
BETWEENWithin range
NOT_BETWEENOutside 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:
{
  "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.
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.

Configurable Rules

Add custom country allow/deny lists on top of the built-in checks:
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)

CodeCountry
CUCuba
IRIran
KPNorth Korea
SYSyria
RURussia
BYBelarus
MMMyanmar
VEVenezuela
SDSudan
SSSouth Sudan
LBLebanon
LYLibya
SOSomalia
YEYemen
Always consult legal counsel for compliance requirements. This is not legal advice.

Approval Thresholds

Require manual approval above certain amounts:
{
  "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:
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"
      }
    ]
  }'
Velocity counting is per-wallet, per-agent. It counts transactions with status CONFIRMED or PENDING. The current transaction is included in the count (+1).
Use cases:
  • Prevent rapid drain attacks
  • Detect unusual patterns
  • Rate limit agent activity

Category Restrictions

Allow or block specific categories:
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"
      }
    ]
  }'
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.

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:
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

{
  "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):
FieldDescriptionExample
contractsAllowed contract addresses["0x7a25...", "0x1f98..."]
protocolsAllowed protocol names["uniswap", "aave"]
categoriesAllowed protocol categories["DEX", "LENDING", "BRIDGE"]
functionsAllowed 4-byte function selectors["0xa9059cbb", "0x095ea7b3"]

Passing Contract Context in Payment Requests

Include targetContractAddress (and optionally functionSelector) in payment requests:
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.
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.

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:
{
  "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:
{
  "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.
{
  "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:
[
  {
    "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 TypeDescriptionValue Format
X402_MAX_PER_REQUESTMaximum amount per x402 requestN or {"amount": N}
X402_PRICE_CEILINGPrice ceiling for any x402 paymentN or {"amount": N}
X402_MAX_PER_ENDPOINTLimit per API endpoint{"maxAmount": N, "maxCalls": N, "period": "DAILY"}
X402_MAX_PER_SERVICELimit per service domain{"maxAmount": N, "maxCalls": N, "period": "DAILY"}
X402_ALLOWED_SERVICESAllowlist of service domains["api.example.com", "data.service.io"]
X402_BLOCKED_SERVICESBlocklist of service domains["malicious.site"]
X402_ALLOWED_FACILITATORSAllowed x402 facilitator addresses["0x..."]
X402_VELOCITY_PER_ENDPOINTRate limit per endpoint{"maxCalls": N, "period": "HOUR"}
X402_SESSION_BUDGETSession-level spending budgetN
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 TypeDescriptionValue Format
MPP_MAX_PER_REQUESTMaximum per MPP credential chargeN or {"amount": N}
MPP_PRICE_CEILINGPrice ceiling for MPP paymentsN or {"amount": N}
MPP_MAX_PER_ENDPOINTLimit per MPP resource endpoint{"maxAmount": N, "maxCalls": N}
MPP_MAX_PER_SERVICELimit per MPP service domain{"maxAmount": N, "maxCalls": N, "period": "DAILY"}
MPP_ALLOWED_SERVICESAllowlist of MPP service domains["api.example.com"]
MPP_BLOCKED_SERVICESBlocklist of MPP service domains["blocked.site"]
MPP_SESSION_BUDGETSession-level spending budgetN
MPP_MAX_SESSION_DEPOSITHard cap on session deposit amountN
MPP_MAX_CONCURRENT_SESSIONSMax active sessions per agentN
MPP_MAX_SESSION_DURATIONMaximum session duration in hoursN
MPP_BLOCK_SESSION_INTENTBlock opening MPP sessionsany value; condition checks intent === "session"
MPP_VELOCITY_PER_ENDPOINTRate 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.
Avoid MPP_ALLOWED_METHODS until the runtime check is fixed. The current strategy is inverted and can deny methods that are listed as allowed.

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 TypePurposeExample Value
AGENTSCORE_REQUIRE_VERIFIEDRequire a verified human behind the agent"true"
AGENTSCORE_ALLOWED_JURISDICTIONSAllow only specific operator jurisdictions["US","CA"]
AGENTSCORE_BLOCKED_JURISDICTIONSDeny 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 TypeDescriptionValue Format
CARD_MAX_AMOUNTMaximum per card transaction"500"
CARD_ALLOWED_MCCSAllowed merchant category codes["5411", "5812"]
CARD_BLOCKED_MCCSBlocked merchant category codes["7995"]
CARD_ALLOWED_MERCHANTSAllowed merchant names["Amazon", "Stripe"]
CARD_BLOCKED_MERCHANTSBlocked merchant names["Casino.com"]

Bulk Policy Operations

Create Multiple Policies

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

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"] }
    ]
  }'