Skip to content
Alchemy Logo

Use existing session keys

Use session keys installed via installValidation with Wallet APIs

This guide is for session keys that were manually installed onchain via installValidation. For new session keys, use wallet_createSession or grantPermissions instead — they handle installation, permissions, and context automatically.

If you have session keys installed directly on a Modular Account V2 (for example, from a v4 @account-kit/wallet-client integration) and are migrating to Wallet APIs (@alchemy/wallet-apis v5), you can use those existing keys without reinstalling them. Build a permissions context hex string and pass it when sending transactions.

  • The smart wallet must be a Modular Account V2 (sma-b) or an EIP-7702 account delegated to Modular Account V2.
  • The session key must already be installed onchain with a known entityId via installValidation.
  • You must know whether the session key was installed as a global validation (isGlobal: true) or scoped to specific selectors.

The permissions context tells Wallet APIs how to locate and validate the session key onchain. Construct it by concatenating three values:

Byte(s)ValueMeaning
0x02Fixed prefixIndicates a session key installed outside of Wallet APIs
0x01 or 0x00isGlobal flag0x01 if the key was installed with isGlobal: true, 0x00 otherwise
4 bytesentityIdThe entityId used in the installValidation call, as a uint32 hex value
import { concatHex, toHex } from "viem";
 
const isGlobal = true; // match the value used in installValidation
const entityId = 1; // match the entityId used in installValidation
 
const permissionsContext = concatHex([
  "0x02",
  isGlobal ? "0x01" : "0x00",
  toHex(entityId, { size: 4 }),
]);

Pass the permissions context in capabilities.permissions.context when sending transactions.

import { privateKeyToAccount } from "viem/accounts";
import { arbitrumSepolia } from "viem/chains";
import { concatHex, toHex } from "viem";
import { createSmartWalletClient, alchemyWalletTransport } from "@alchemy/wallet-apis";
 
const sessionKey = privateKeyToAccount("0xSESSION_PRIVATE_KEY" as const);
 
// The address of the account that the session key is installed on
const accountAddress = "0xACCOUNT_ADDRESS";
 
const isGlobal = true;
const entityId = 1;
 
const permissionsContext = concatHex([
  "0x02",
  isGlobal ? "0x01" : "0x00",
  toHex(entityId, { size: 4 }),
]);
 
const client = createSmartWalletClient({
  transport: alchemyWalletTransport({
    apiKey: "YOUR_API_KEY",
  }),
  chain: arbitrumSepolia,
  signer: sessionKey,
  account: accountAddress,
});
 
const { id } = await client.sendCalls({
  calls: [{ to: "0x...", value: BigInt(0) }],
  capabilities: {
    permissions: {
      context: permissionsContext,
    },
  },
});
 
await client.waitForCallsStatus({ id });
Was this page helpful?