---
title: "Agent wallets: the session and permission model for AI agents"
description: "How AI agents get scoped, revocable wallet access without holding private keys: sessions, delegated signing, and instant revocation."
---

# Agent wallets: the session and permission model for AI agents

<ImageBlock
  src="https://media.alchemy.com/agent-wallets-1.png"
  alt="Agent wallets: the session and permission model for AI agents"
  width={3840}
  height={1800}
  priority
/>

An AI agent trading onchain is one signature away from moving real money. It's read the market, picked a route through a DEX, and it's ready to execute. Shipping this safely comes down to one question: what happens when the agent is wrong, hijacked, or just buggy? Can it drain the wallet, and can you stop it before the damage is done?

## What is an agent wallet, and how is it different from a regular crypto wallet?

A regular wallet assumes a person reviews and signs every transaction with a key only they hold. An agent wallet assumes the opposite: an AI agent or automated process signs continuously, with no human clicking approve each time, while the person or company that owns the funds keeps ultimate control.

The difference comes down to the permission model wrapped around the signing key, not the balance or address sitting in the wallet: what the agent is allowed to do (scoped capabilities), how long it's allowed to do it (a time-bound session), and how fast you can cut it off if something goes wrong.

[Agent Wallets](https://www.alchemy.com/docs/agent-wallets) handles each of these directly:

- Scoped capabilities: a CLI session only includes the specific signing methods you grant it, like sends, swaps, bridges, or contract calls. Restricting a key to one contract's functions is a [Wallet API session-key permission](https://www.alchemy.com/docs/wallets/smart-contracts/modular-account-v2/session-keys/session-key-permissions), not a CLI capability.
- A time-bound session: every grant carries an expiry, so access lapses on its own even if no one revokes it.
- Fast shutoff: revoking a CLI session from the Alchemy dashboard or with `alchemy wallet disconnect` takes effect at the verification layer immediately, no transaction required.

Scoped capabilities and expiries show up whether you're using the Agent Wallets CLI product directly, across EVM and Solana, or building on the underlying Wallet APIs session-key primitive for your own users. Instant shutoff without a mined transaction is the CLI path. Removing a Wallet API session key is an onchain uninstall.

## How do agent wallets keep the private key away from the agent?

Designing secure transactions for agents means separating what a regular wallet bundles into one key: custody (who holds the private key), authorization (what's allowed), and control (who can approve or shut it off).

- [Turnkey](https://docs.turnkey.com/features/policies/delegated-access/agentic-wallets) keeps custody inside a hardware secure enclave and runs its policy engine in that same enclave, so a signature only comes out after the request passes the rules, and the agent never touches the key.
- [Crossmint](https://docs.crossmint.com/wallets/concepts/signers) and [Cobo](https://www.cobo.com/products/agentic-wallet/manual/developer/technical-architecture) split a wallet into an owner key and an agent key instead (Cobo uses MPC across independent parties rather than a single key), so the agent's key only works inside limits the owner set.
- Alchemy [built the same separation into the CLI](https://www.alchemy.com/blog/agent-wallets-alchemy-cli): a locally generated session signer authenticates the agent, while a separate custodian holds the actual private key, so the agent authenticates and signs without ever touching it.

Here's what that looks like in practice.

- Run `alchemy wallet connect`, and the CLI generates a P-256 keypair locally that never leaves your machine.
- You approve the session in the Alchemy dashboard, which attaches that public key as a signer scoped to specific capabilities and an expiry you set.
- The wallet's actual private key sits with an embedded wallet partner, Privy by default.
- Every signing call is a two-step check: Alchemy's backend builds the exact payload the custodian expects, your CLI signs it locally, and the request only reaches the custodian if the session is still valid. The agent never receives or handles the private key.

## What infrastructure should you use for provisioning and permission controls?

There are two paths, depending on who you're building for.

If you're giving a coding agent or an internal automation a wallet, [Agent Wallets in the Alchemy CLI](https://www.alchemy.com/docs/agent-wallets) is the fastest path, and the same approach that replaces [pasting a private key straight into Cursor](https://www.alchemy.com/overviews/stop-pasting-private-keys-into-cursor) with something an agent can actually use safely.

Create a wallet in the dashboard, run `alchemy wallet connect --mode session`, approve the session's capabilities and expiry, and the agent gets a scoped session it can use immediately for sends and contract calls, plus swaps and bridges on EVM mainnet. No SDK integration needed, and the CLI's `agent-prompt` command hands the agent a full manifest of commands, flags, and error codes so it doesn't have to go read docs to use the surface correctly.

If you're building a product where your own users delegate signing to an agent, leverage [Wallet APIs session keys](https://www.alchemy.com/docs/wallets/reference/wallet-apis-session-keys/api). A user's smart account gets delegated onchain under [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702), you call `wallet_createSession` (or `client.grantPermissions()` in the SDK) with a session key and a permissions array, the user signs one EIP-712 authorization, and the agent signs every action after that with the session key, never the owner's key.

## What can you delegate, and how granular are the permissions?

Delegation works at two layers here: which actions a session is allowed to call at all, and, one level deeper, how much value or which specific contracts those calls can touch.

At the CLI session level, that first layer is a list of allowed methods.

- A session can include `evm.signMessage`, `evm.signTypedData`, `evm.signAuthorization`, `evm.prepareCalls`, `evm.sendCalls`, and `solana.signTransaction`.
- Everything routes through Alchemy's wallet calls (`wallet_prepareCalls` and `wallet_sendCalls`) so that transaction logistics, like ordering and batching, and gas sponsorship are handled for you.

The tradeoff is that a session can't sign an arbitrary raw EVM transaction the way a standalone private key can, so if your agent needs to plug into a third-party SDK or protocol that expects to hand it a raw EVM transaction to sign, that flow doesn't work through a CLI session today. [Reach out to us](https://www.alchemy.com/contact-sales) if this is a use case you need.

At the Wallet APIs level, [session-key permissions](https://www.alchemy.com/docs/wallets/smart-contracts/modular-account-v2/session-keys/session-key-permissions) are more configurable. The CLI's capability list only answers yes or no: can this session call `sendCalls` at all? Wallet API permissions add limits on top of that: not just whether a transfer is allowed, but how much can move, in which token, and through which specific contract. If an agent needs actual spend caps, like a 100 USDC cap over a 24-hour window on one token, not just a switch for which actions are turned on, leverage Wallet APIs:

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 240, title: "Permission type", dataType: "object" },
      { key: "2", width: 400, title: "What it restricts", dataType: "object" },
    ],
    data: [
      {
        "1": {
          title: "<p><code>native-token-transfer</code></p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>Caps how much native token (ETH, say) the key can move, via a fixed allowance</p>",
          tooltip: "",
          icon: "",
        },
        id: 0,
      },
      {
        "1": {
          title: "<p><code>erc20-token-transfer</code></p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>Caps cumulative ERC-20 transfers and approvals for one token contract to a set allowance</p>",
          tooltip: "",
          icon: "",
        },
        id: 1,
      },
      {
        "1": { title: "<p><code>gas-limit</code></p>", tooltip: "", icon: "" },
        "2": {
          title: "<p>Caps how much gas the key can spend across transactions</p>",
          tooltip: "",
          icon: "",
        },
        id: 2,
      },
      {
        "1": {
          title: "<p><code>contract-access</code></p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>Allows every function on one named contract, nothing else</p>",
          tooltip: "",
          icon: "",
        },
        id: 3,
      },
      {
        "1": {
          title:
            "<p><code>functions-on-contract</code> / <code>account-functions</code> / <code>functions-on-all-contracts</code></p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>Allows only specific function selectors, on one contract, on the account itself, or everywhere</p>",
          tooltip: "",
          icon: "",
        },
        id: 4,
      },
      {
        "1": { title: "<p><code>root</code></p>", tooltip: "", icon: "" },
        "2": {
          title:
            "<p>Full access to everything, a very dangerous permission to grant. Use judiciously.</p>",
          tooltip: "",
          icon: "",
        },
        id: 5,
      },
    ],
  }}
/>

Every permission also carries an `expirySec`, so one grant can scope a session key to, say, one staking contract, a 100 USDC cap, and a 24-hour window, all at once.

## How to approve, verify, and revoke an agent's wallet session

Approval happens once, by a human. In the CLI flow, that's the dashboard approval step when you connect a session. In the Wallet APIs flow, that's the owner signing the EIP-712 typed data that authorizes the session key's permissions.

Verification should happen before every action that changes state, not just at setup. Run `alchemy --json --no-interactive wallet status --verify` before an agent does anything irreversible. It returns the active signer, session expiry, and enabled capabilities, so the agent (or your orchestration code) confirms the session is still live before proceeding.

Revocation has two mechanics:

- From the dashboard or with `alchemy wallet disconnect`, a session gets revoked at the verification layer. The next signing attempt is rejected before it ever reaches the custodian, immediately, with no transaction required.
- If you're managing session keys at the smart-account level directly (outside the CLI product), [removing a session key](https://www.alchemy.com/docs/wallets/smart-contracts/modular-account-v2/session-keys/removing-session-keys) means uninstalling its validator with a user operation, which has to be sent and mined like any other onchain action.

## How to make sure revoking an agent's access is instant

Say you spot the agent doing something wrong and you hit revoke. If your kill switch works by changing a rule stored onchain, that change still has to be sent as a transaction and mined before it's real, so there's a window, block time, maybe longer, where the agent can still act even though you already told the system to stop it. The question is how to design revocation so it doesn't have that gap.

It comes down to where enforcement lives. If the only thing standing between an agent and the chain is a rule stored inside a smart contract, turning that rule off means sending a transaction to change the contract's state, and that transaction has to be mined before the change is real. If enforcement happens instead at a layer that checks the request before it's ever signed or broadcast, revoking is just deleting or invalidating that check, which takes effect the moment you do it.

Alchemy's Agent Wallets, Turnkey's policy engine, and Cobo's pact system all use the latter pattern.

- Turnkey deletes the non-root agent user, and every subsequent request from that credential fails at the enclave.
- Cobo revokes a pact and its API key server-side and states plainly that the agent's next API call gets rejected.
- Alchemy revokes the session at the backend verification layer, and the next signing attempt is rejected before it leaves Alchemy's infrastructure, before it ever reaches the custodian.

Crossmint takes a different approach: its permissions live inside the smart contract wallet itself, so removing an agent's signer is a change to that contract's onchain state. While the rule being enforced by the chain itself, rather than a server, is [harder for a compromised agent to route around](https://www.crossmint.com/learn/agent-wallets-compared), the tradeoff is speed: changing an onchain permission means sending a transaction, so revocation inherits whatever settlement time the chain has, which the backend-check approach avoids entirely.

## Agent Wallets vs. Wallet API session keys

Both Agent Wallets and using session keys via the Wallet APIs keep the private key away from the agent. What differs is how much control you need, who's actually delegating to the agent, and how revocation works. CLI sessions are cut off at the verification layer with no transaction. Uninstalling a Wallet API session key waits on a mined user operation.

<EmbeddedTable
  table={{
    columns: [
      {
        key: "1",
        width: 280,
        title: "Use Agent Wallets (the CLI)",
        dataType: "object",
      },
      {
        key: "2",
        width: 320,
        title: "Use Wallet APIs session keys",
        dataType: "object",
      },
    ],
    data: [
      {
        "1": {
          title:
            "<p>You're wiring up a coding agent or an internal script and want it signing in minutes, no SDK integration required.</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>You're building a product where your own end users delegate signing to an agent on their own smart account.</p>",
          tooltip: "",
          icon: "",
        },
        id: 0,
      },
      {
        "1": {
          title:
            "<p>A yes/no capability list, can this session send, swap, bridge, or make contract calls, is enough scoping for what the agent does.</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>You need an actual spend cap, like a fixed allowance on native token or one ERC-20, enforced by the permission itself.</p>",
          tooltip: "",
          icon: "",
        },
        id: 1,
      },
      {
        "1": {
          title:
            "<p>The Alchemy dashboard is a fine place to create the wallet and approve sessions by hand.</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>You need contract- or function-level allowlists as the real enforcement boundary, not just a capability flag.</p>",
          tooltip: "",
          icon: "",
        },
        id: 2,
      },
      {
        "1": {
          title:
            "<p>The CLI already handles what the agent needs to do: sending, batching calls, and getting its gas sponsored across EVM and Solana, plus swapping and bridging on EVM mainnet.</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            '<p>You need to grant session keys from your own app. Neither path signs an arbitrary raw EVM transaction for a third-party SDK today. <a href="https://www.alchemy.com/contact-sales">Reach out to us</a> if that\'s the use case.</p>',
          tooltip: "",
          icon: "",
        },
        id: 3,
      },
    ],
  }}
/>

## How Alchemy compares to Turnkey, Crossmint, and Cobo

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 180, title: "Provider", dataType: "object" },
      { key: "2", width: 240, title: "Where custody lives", dataType: "object" },
      {
        key: "3",
        width: 260,
        title: "Where policy is enforced",
        dataType: "object",
      },
      {
        key: "4",
        width: 280,
        title: "Instant revoke without a mined transaction",
        dataType: "object",
      },
    ],
    data: [
      {
        "1": { title: "<p>Alchemy Agent Wallets</p>", tooltip: "", icon: "" },
        "2": {
          title:
            "<p>Embedded wallet partner (Privy by default) for CLI sessions, or any signer you choose via Wallet APIs</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>Backend session-verification layer for CLI sessions; onchain session-key permissions on the smart account for custom Wallet APIs integrations</p>",
          tooltip: "",
          icon: "",
        },
        "4": {
          title:
            "<p>Yes for CLI sessions, via dashboard or <code>wallet disconnect</code>. Wallet API session keys: no, uninstalling the validator is a mined user operation</p>",
          tooltip: "",
          icon: "",
        },
        id: 0,
      },
      {
        "1": { title: "<p>Turnkey</p>", tooltip: "", icon: "" },
        "2": {
          title: "<p>AWS Nitro secure enclave (TEE)</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>Policy engine running inside the same enclave, evaluated before every signature</p>",
          tooltip: "",
          icon: "",
        },
        "4": {
          title:
            "<p>Yes, delete the non-root agent user or toggle a DENY policy</p>",
          tooltip: "",
          icon: "",
        },
        id: 1,
      },
      {
        "1": { title: "<p>Cobo Agentic Wallet</p>", tooltip: "", icon: "" },
        "2": {
          title:
            "<p>MPC across independent parties, no single key</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>Three-stage server-side policy engine (permission, rule, counter), evaluated on every request</p>",
          tooltip: "",
          icon: "",
        },
        "4": {
          title:
            "<p>Yes, freeze or revoke a pact; the API key gets invalidated server-side</p>",
          tooltip: "",
          icon: "",
        },
        id: 2,
      },
      {
        "1": { title: "<p>Crossmint</p>", tooltip: "", icon: "" },
        "2": {
          title:
            "<p>Dual-key smart contract wallet: owner key plus an agent key sealed in a TEE</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>Onchain, inside the smart contract itself (per-transaction limits, allowlists, time windows checked at execution)</p>",
          tooltip: "",
          icon: "",
        },
        "4": {
          title:
            "<p>By design, no. Removing a signer changes the wallet contract's onchain signer set, so it settles like any other onchain operation rather than a synchronous backend check</p>",
          tooltip: "",
          icon: "",
        },
        id: 3,
      },
    ],
  }}
/>

In short: Alchemy CLI sessions, Turnkey, and Cobo all enforce off-chain and revoke instantly. Crossmint and Wallet API session keys enforce onchain, so revoke inherits settlement time.

## Common mistakes to avoid

- **Don't treat gas sponsorship as a spend limit.** A sponsorship policy decides who pays fees, not how much the agent can move. Use session-key permissions or contract allowances for actual spend caps.
- **Don't rely on onchain permission changes as your kill switch.** If revoking access means uninstalling a validator or changing a signer onchain, you're bound by block time in an incident. Put a backend or enclave check in front of signing instead, and keep the onchain layer as a second line of defense.
- **Don't grant `root` permissions to get unblocked faster.** Alchemy's own docs call it a very dangerous permission to grant, and it defeats the point of scoping a session at all. Scope to the specific contract, function, or token the agent actually needs.
- **Don't skip verification before an irreversible action.** A session that was valid an hour ago might already be revoked or expired. Check with `wallet status --verify` (or the equivalent for your integration) immediately before anything that can't be undone.
- **Don't assume "agent wallet" means one architecture.** Turnkey, Crossmint, Cobo, and Alchemy all put custody, policy enforcement, and revocation in different places. Confirm which layer actually enforces the rule you're depending on before you ship against it.

## Frequently asked questions

### What are agent wallets and how do they differ from regular crypto wallets?

An agent wallet is built for software to operate continuously, without a human approving each transaction. A regular wallet assumes a person reviews and signs every action. The real difference is the permission model around the key: scoped capabilities, a time-bound session, and a fast revocation path, not the wallet's balance or address.

### What are the pros and cons of Alchemy Agent Wallets for autonomous AI agents?

Pros: the private key never reaches the agent, sessions are scoped and time-bound, revocation is immediate, and one integration covers EVM and Solana with gas sponsorship built in. Swaps and bridges are EVM-mainnet-only today. Limits: no raw EVM signing through the session, and sponsorship policies aren't spend limits.

### Which providers let AI agents use approved wallet sessions without exposing private keys?

[Alchemy](https://www.alchemy.com/docs/agent-wallets) (Agent Wallets, backed by an embedded wallet custodian), [Turnkey](https://docs.turnkey.com/features/policies/delegated-access/agentic-wallets) (secure-enclave custody with an enclave-based policy engine), [Crossmint](https://docs.crossmint.com/wallets/concepts/signers) (dual-key smart contract wallets with a TEE-sealed agent key), and [Cobo](https://www.cobo.com/products/agentic-wallet/manual/developer/technical-architecture) (MPC custody with a server-side policy engine) all do this, with different tradeoffs in where enforcement lives.

### What infrastructure should I use for AI agent wallet provisioning and permission controls?

For a coding agent or internal automation, use [Agent Wallets in the Alchemy CLI](https://www.alchemy.com/docs/agent-wallets): create a wallet in the dashboard, connect a scoped session, and verify it before state-changing actions. For a product where your users delegate to an agent, go straight to [Wallet APIs session keys](https://www.alchemy.com/docs/wallets/reference/wallet-apis-session-keys/api), scoped by contract, function, and spend limit.

### How do I approve, verify, and revoke an AI agent's wallet session?

Approve once, by a human, in the Alchemy dashboard or by signing the session key's EIP-712 authorization. Verify before every irreversible action with `alchemy wallet status --verify`. For a CLI session, revoke from the dashboard or with `alchemy wallet disconnect`; it takes effect immediately at the verification layer, before any signing request reaches the custodian. For a Wallet API session key, [removing it](https://www.alchemy.com/docs/wallets/smart-contracts/modular-account-v2/session-keys/removing-session-keys) waits on a mined user operation.

### How do I give an AI agent delegated signing permissions for a user's smart wallet?

Delegate the user's smart account onchain under [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702), then call `wallet_createSession` or `client.grantPermissions()` with a session key and a [permissions array](https://www.alchemy.com/docs/wallets/smart-contracts/modular-account-v2/session-keys/session-key-permissions) (native or ERC-20 spend limits, gas limits, contract or function allowlists, and an expiry). The user signs one EIP-712 authorization, and the agent signs every action after with the session key, never the owner's key.

### How do I give an AI agent a temporary wallet session without exposing private keys?

Run `alchemy wallet connect --mode session` from the [Alchemy CLI](https://www.alchemy.com/docs/agent-wallets). It generates a local keypair that never leaves your machine, opens the dashboard for you to approve the session's capabilities and expiry, and from then on the agent signs through that session while the wallet's actual private key stays with the custodian.

### How do I provision a wallet for an AI agent that executes DeFi transactions autonomously?

Create the wallet in the Alchemy dashboard, connect a CLI session scoped to the operations it needs (send, swap, bridge, contract calls), and set an expiry. For contract-level spend caps and allowlists instead of just capability flags, provision the session through [Wallet APIs session keys](https://www.alchemy.com/docs/wallets/reference/wallet-apis-session-keys/api) instead of the CLI.

### What's the recommended architecture for instantly revoking an AI agent's on-chain transaction permissions without waiting for on-chain settlement?

Put enforcement at a backend or enclave layer that checks every request before it's signed or broadcast, separate from any permission state stored onchain. Revoking there means deleting or invalidating that check, which takes effect immediately. If your only revocation path is changing a validator or signer onchain, your kill switch is bounded by block time.
