Spend Permissions let you designate a trusted spender that can spend tokens on behalf of your Smart Account. After you sign the permission, the spender can initiate token spending within the limits you define. You can define limits based on token, time period, and amount.
Smart Accounts must have spend permissions enabled at the time of creation. You cannot create spend permissions on accounts that were created without spend permissions enabled.
There are two parties involved in a Spend Permission:
Account - The smart account that creates the Spend Permission and approves it onchain.
Spender - The entity that can spend tokens on behalf of the account within the limits defined by a Spend Permission. Can be a Smart Account or a regular account.
Spender - The entity that can spend tokens on behalf of the account.
Token - The token that the Spend Permission is for. Use "eth" or "usdc" as shortcuts (Base and Base Sepolia only), or provide an ERC-20 contract address for other tokens.
Allowance - The amount of the token the spender is allowed to spend, in the token’s smallest unit (e.g. wei for ETH, 6-decimal units for USDC).
Time period - Use periodInDays for simple daily/weekly limits, or period, start, and end for advanced rolling windows and fixed time ranges.
Salt - A random value to differentiate between permissions with the same parameters. Generated automatically by the SDK.
Extra Data - Arbitrary data for additional information about the permission.
Use useCreateSpendPermission to create a permission. Creating a permission is a user operation that requires gas — use useCdpPaymaster: true on Base or provide a paymasterUrl.
Once a permission is created, the designated spender lists the account’s permissions to find theirs, then calls useSpendPermission to spend within the defined limits.
all_permissions = await cdp.evm.list_spend_permissions( address=smart_account.address,)permissions = [ p for p in all_permissions.spend_permissions if p.permission.spender.lower() == spender.address.lower()]if not permissions: print("No spend permissions found for this spender") exit(1)spend = await spender.use_spend_permission( spend_permission=permissions[0].permission, value=parse_units("0.005", 6), network="base-sepolia",)receipt = await spender.wait_for_user_operation(spend)print(f"Spend completed: {receipt}")
// As the account: see all permissions you've grantedconst permissions = await cdp.evm.listSpendPermissions({ address: smartAccount.address,});console.log("Permissions granted:", permissions);// As the spender: query the account's permissions and filter by your addressconst allPermissions = await cdp.evm.listSpendPermissions({ address: "0xAccountAddress",});const myPermissions = allPermissions.spendPermissions.filter( (p) => p.permission.spender.toLowerCase() === spender.address.toLowerCase());
# As the account: see all permissions you've grantedpermissions = await cdp.evm.list_spend_permissions( address=smart_account.address,)print("Permissions granted:", permissions)# As the spender: query the account's permissions and filter by your addressall_permissions = await cdp.evm.list_spend_permissions( address="0xAccountAddress",)my_permissions = [ p for p in all_permissions.spend_permissions if p.permission.spender.lower() == spender.address.lower()]