Skip to main content
Policies provide fine-grained control over what operations accounts can perform. You can restrict transactions by network, address, value, message content, and more. Policies can be applied at the project level (affecting all accounts) or at the account level (affecting specific accounts).

Policy Scopes

  • Project policies: Apply to all accounts in your project
  • Account policies: Apply to specific individual accounts

Creating a Policy

1

Define policy rules

Create a policy with rules for different operations:
import { CdpClient } from "@coinbase/cdp-sdk";

const cdp = new CdpClient();

const policy = await cdp.policies.createPolicy({
  policy: {
    scope: "account",
    description: "EVM Transaction Allowlist",
    rules: [
      {
        action: "accept",
        operation: "sendEvmTransaction",
        criteria: [
          {
            type: "evmNetwork",
            networks: ["base-sepolia", "base"],
            operator: "in"
          }
        ]
      },
      {
        action: "accept",
        operation: "signEvmTransaction",
        criteria: [
          {
            type: "ethValue",
            ethValue: "1000000000000000000", // 1 ETH in wei
            operator: "<="
          },
          {
            type: "evmAddress",
            addresses: ["0x1234567890123456789012345678901234567890"],
            operator: "in"
          }
        ]
      }
    ]
  }
});

console.log(`Created policy: ${policy.id}`);
2

Apply policy to an account

Apply the policy when creating an account:
const account = await cdp.evm.createAccount({
  name: "RestrictedAccount",
  accountPolicy: policy.id
});
Or apply to an existing account:
const updated = await cdp.evm.updateAccount({
  address: account.address,
  accountPolicy: policy.id
});

Policy Operations

Policies can control the following operations:

EVM Operations

  • sendEvmTransaction: Sending transactions via CDP
  • signEvmTransaction: Signing transaction objects
  • signEvmHash: Signing raw hashes
  • signEvmMessage: Signing EIP-191 messages
  • signEvmTypedData: Signing EIP-712 typed data
  • sendEvmUserOperation: Sending ERC-4337 user operations

Solana Operations

  • signSolanaTransaction: Signing Solana transactions
  • signSolanaMessage: Signing Solana messages

Policy Criteria

EVM Network Criterion

Restrict operations to specific networks:
{
  type: "evmNetwork",
  networks: ["base", "base-sepolia", "ethereum"],
  operator: "in" // or "not in"
}

EVM Address Criterion

Restrict operations to specific addresses:
{
  type: "evmAddress",
  addresses: [
    "0x1234567890123456789012345678901234567890",
    "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
  ],
  operator: "in" // or "not in"
}

ETH Value Criterion

Limit transaction values:
{
  type: "ethValue",
  ethValue: "1000000000000000000", // 1 ETH in wei
  operator: "<=" // or "<", ">", ">=", "==", "!="
}

EVM Message Criterion

Restrict messages by regex pattern:
{
  type: "evmMessage",
  match: "^Welcome.*" // Regex pattern
}

Solana Address Criterion

Restrict Solana operations to specific addresses:
{
  type: "solanaAddress",
  addresses: ["9aE4FvpEqMj3K4cZKXXCHwDr9FQZyH2yZ8xF5Cz7T3v2"],
  operator: "in"
}

Common Policy Examples

Spend Limit Policy

Limit daily spending:
const policy = await cdp.policies.createPolicy({
  policy: {
    scope: "account",
    description: "Daily Spend Limit",
    rules: [
      {
        action: "accept",
        operation: "signEvmTransaction",
        criteria: [
          {
            type: "ethValue",
            ethValue: "100000000000000000", // 0.1 ETH
            operator: "<="
          }
        ]
      },
      {
        action: "reject",
        operation: "signEvmTransaction",
        criteria: [
          {
            type: "ethValue",
            ethValue: "100000000000000000",
            operator: ">"
          }
        ]
      }
    ]
  }
});

Address Allowlist

Only allow transactions to specific addresses:
const policy = await cdp.policies.createPolicy({
  policy: {
    scope: "account",
    description: "Approved Recipients Only",
    rules: [
      {
        action: "accept",
        operation: "signEvmTransaction",
        criteria: [
          {
            type: "evmAddress",
            addresses: [
              "0xApprovedAddress1...",
              "0xApprovedAddress2...",
              "0xApprovedAddress3..."
            ],
            operator: "in"
          }
        ]
      },
      {
        action: "reject",
        operation: "signEvmTransaction",
        criteria: [
          {
            type: "evmAddress",
            addresses: [
              "0xApprovedAddress1...",
              "0xApprovedAddress2...",
              "0xApprovedAddress3..."
            ],
            operator: "not in"
          }
        ]
      }
    ]
  }
});

Network Restriction

Only allow operations on testnet:
const policy = await cdp.policies.createPolicy({
  policy: {
    scope: "project",
    description: "Testnet Only",
    rules: [
      {
        action: "accept",
        operation: "sendEvmTransaction",
        criteria: [
          {
            type: "evmNetwork",
            networks: [
              "base-sepolia",
              "ethereum-sepolia",
              "optimism-sepolia"
            ],
            operator: "in"
          }
        ]
      },
      {
        action: "reject",
        operation: "sendEvmTransaction",
        criteria: [
          {
            type: "evmNetwork",
            networks: ["base", "ethereum", "optimism"],
            operator: "in"
          }
        ]
      }
    ]
  }
});

Updating Policies

Update an existing policy:
const updatedPolicy = await cdp.policies.updatePolicy({
  id: policy.id,
  policy: {
    description: "Updated Policy Description",
    rules: [
      {
        action: "accept",
        operation: "signEvmTransaction",
        criteria: [
          {
            type: "ethValue",
            ethValue: "2000000000000000000", // Updated to 2 ETH
            operator: "<="
          }
        ]
      }
    ]
  }
});

console.log(`Updated policy: ${updatedPolicy.id}`);

Listing Policies

List All Policies

const response = await cdp.policies.listPolicies({
  pageSize: 50,
  pageToken: "optional-token"
});

for (const policy of response.policies) {
  console.log(`${policy.id}: ${policy.description}`);
}

List Account Policies

const response = await cdp.policies.listAccountPolicies({
  scope: "account"
});

List Project Policies

const response = await cdp.policies.listProjectPolicies({
  scope: "project"
});

Getting a Policy by ID

const policy = await cdp.policies.getPolicyById({
  id: "pol_abc123..."
});

console.log(`Policy: ${policy.description}`);
console.log(`Scope: ${policy.scope}`);
console.log(`Rules: ${JSON.stringify(policy.rules, null, 2)}`);

Deleting Policies

await cdp.policies.deletePolicy({
  id: policy.id
});

console.log("Policy deleted");
Deleting a policy does not automatically remove it from accounts. Update accounts to remove the policy first.

Removing Policies from Accounts

const updated = await cdp.evm.updateAccount({
  address: account.address,
  accountPolicy: null // Remove policy
});

Policy Enforcement

When a policy is violated:
  1. The API returns a 403 Forbidden error
  2. The error message indicates which policy rule was violated
  3. The operation is not executed
Example error handling:
try {
  await account.transfer({
    to: "0x...",
    amount: 10000000000000000000n, // 10 ETH
    token: "eth",
    network: "base"
  });
} catch (error: any) {
  if (error.status === 403) {
    console.log("Transaction blocked by policy:", error.message);
  }
  throw error;
}

Best Practices

  1. Start with account policies: Use account-level policies for testing before applying project-wide
  2. Use descriptive names: Make policy descriptions clear and specific
  3. Test policies thoroughly: Verify policies work as expected before production use
  4. Combine criteria carefully: Multiple criteria within a rule are AND conditions
  5. Order matters: Rules are evaluated in order; first matching rule determines the action
  6. Monitor policy violations: Track policy rejections to identify issues

Troubleshooting

Policy Not Applied

Verify the policy is attached to the account:
const account = await cdp.evm.getAccount({ address: "0x..." });
console.log(`Policies: ${account.policies}`);

Unexpected Policy Rejection

Check the policy rules and criteria:
const policy = await cdp.policies.getPolicyById({ id: "pol_..." });
console.log(JSON.stringify(policy.rules, null, 2));

Policy Update Not Taking Effect

Policy updates are immediate but may require re-fetching the account object.

Next Steps

Build docs developers (and LLMs) love