Policies

Spending rules that are evaluated on every agent transaction. Policies are attached to agent wallets and enforced server-side — agents cannot bypass them.

Policy Types

Daily Spend Cap

spend_cap_daily

Limits the total USDC an agent can spend within a rolling 24-hour window. Resets daily from first transaction.

{ "type": "spend_cap_daily", "params": { "limit": "50.00" } }

Total Spend Cap

spend_cap_total

Hard lifetime limit on total spending from this agent wallet. Once reached, all further transactions are blocked until the policy is updated.

{ "type": "spend_cap_total", "params": { "limit": "500.00" } }

Address Whitelist

address_whitelist

Only allow transactions to pre-approved Ethereum addresses. Any payment to an unlisted address is rejected.

{ "type": "address_whitelist", "params": { "addresses": ["0x742d...2bD68", "0xABc...123"] } }

How Evaluation Works

When an agent calls send_payment, the policy engine evaluates all active policies on that wallet before execution:

  1. 1Agent calls send_payment(toAddress, amount)
  2. 2Policy engine loads all active policies for the wallet
  3. 3Each policy is evaluated independently — all must pass
  4. 4If any policy fails → transaction is rejected with violations
  5. 5If all pass → transaction is signed and broadcast on-chain

Managing Policies

From the dashboard or via REST API:

  • Create — attach a new policy to an agent wallet
  • Update — change params (e.g., raise the daily cap) or toggle active/inactive
  • Delete — permanently remove a policy
  • Deactivate — set active: false to temporarily suspend without deleting

Agent-Side Handling

When a payment is denied, the SDK throws a PolicyDeniedError with the specific violations. Smart agents can use this to request human approval:

try {
  await client.sendPayment({ toAddress: '0x...', amount: '100' });
} catch (err) {
  if (err instanceof PolicyDeniedError) {
    // Read which policy blocked us
    for (const v of err.violations) {
      console.log(`${v.policyType}: ${v.reason}`);
    }

    // Escalate to human
    await client.requestApproval({
      toAddress: '0x...',
      amount: '100',
      reason: 'Exceeds daily spend cap — requesting override',
    });
  }
}