# Removing session keys

> Removing session keys from your Modular Account V2

> For the complete documentation index, see [llms.txt](/docs/llms.txt).

<Tip title="Most projects should use @alchemy/wallet-apis">
  [`@alchemy/wallet-apis`](/docs/wallets/quickstart) supports session keys through [`wallet_createSession`](/docs/wallets/reference/wallet-apis-session-keys/api) and the [`grantPermissions`](/docs/wallets/reference/wallet-apis-session-keys/sdk) SDK flow. This page covers the lower-level path: uninstalling Modular Account V2 session-key validations directly with `@alchemy/smart-accounts` and viem's bundler client. Use it when you need lower-level control for custom onchain validation and permission wiring.
</Tip>

To remove a session key, extend the bundler client with `installValidationActions` and call `encodeUninstallValidation`. It returns calldata; send it as a user operation from the account.

```ts twoslash
import { createBundlerClient } from "viem/account-abstraction";
import { createClient } from "viem";
import { sepolia } from "viem/chains";
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
import { alchemyTransport } from "@alchemy/common";
import {
  toModularAccountV2,
  installValidationActions,
  SingleSignerValidationModule,
  DefaultModuleAddress,
} from "@alchemy/smart-accounts";
import { estimateFeesPerGas } from "@alchemy/aa-infra";

const transport = alchemyTransport({ apiKey: "your-api-key" });
const rpcClient = createClient({ chain: sepolia, transport });

const account = await toModularAccountV2({
  client: rpcClient,
  owner: privateKeyToAccount(generatePrivateKey()),
});

const bundlerClient = createBundlerClient({
  account,
  client: rpcClient,
  chain: sepolia,
  transport,
  userOperation: { estimateFeesPerGas },
}).extend(installValidationActions);

const sessionKeyEntityId = 1;

const callData = await bundlerClient.encodeUninstallValidation({
  moduleAddress: DefaultModuleAddress.SINGLE_SIGNER_VALIDATION,
  entityId: sessionKeyEntityId,
  uninstallData: SingleSignerValidationModule.encodeOnUninstallData({
    entityId: sessionKeyEntityId,
  }),
  hookUninstallDatas: [],
});
await bundlerClient.sendUserOperation({ callData });
```

If the validation has hooks installed, you have to provide uninstall data for each one. Every module exports an `encodeOnUninstallData` helper.

```ts twoslash
import { createBundlerClient } from "viem/account-abstraction";
import { createClient } from "viem";
import { sepolia } from "viem/chains";
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
import { alchemyTransport } from "@alchemy/common";
import {
  toModularAccountV2,
  installValidationActions,
  SingleSignerValidationModule,
  AllowlistModule,
  DefaultModuleAddress,
} from "@alchemy/smart-accounts";
import { estimateFeesPerGas } from "@alchemy/aa-infra";

const transport = alchemyTransport({ apiKey: "your-api-key" });
const rpcClient = createClient({ chain: sepolia, transport });

const account = await toModularAccountV2({
  client: rpcClient,
  owner: privateKeyToAccount(generatePrivateKey()),
});

const bundlerClient = createBundlerClient({
  account,
  client: rpcClient,
  chain: sepolia,
  transport,
  userOperation: { estimateFeesPerGas },
}).extend(installValidationActions);

const sessionKeyEntityId = 1;
const hookEntityId = 1;
const target = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045";

// Removing a session key with an allowlist hook
const callData = await bundlerClient.encodeUninstallValidation({
  moduleAddress: DefaultModuleAddress.SINGLE_SIGNER_VALIDATION,
  entityId: sessionKeyEntityId,
  uninstallData: SingleSignerValidationModule.encodeOnUninstallData({
    entityId: sessionKeyEntityId,
  }),
  hookUninstallDatas: [
    AllowlistModule.encodeOnUninstallData({
      entityId: hookEntityId,
      inputs: [
        {
          target,
          hasSelectorAllowlist: false,
          hasERC20SpendLimit: false,
          erc20SpendLimit: 0n,
          selectors: [],
        },
      ],
    }),
  ],
});
await bundlerClient.sendUserOperation({ callData });
```