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"
}
| 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 |
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 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" |
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
| 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:
{
"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:
- Country check: If
recipientCountry is provided in the payment context, it’s checked against the OFAC sanctioned countries list. Blocked immediately if matched.
- 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)
| 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 |
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):
| 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:
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 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.
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 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
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"] }
]
}'