> ## Documentation Index
> Fetch the complete documentation index at: https://developers.circle.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Before reading these docs, install the relevant Circle Skill to get pre-loaded context — skills are LLM-optimized and cover architecture decisions, correct flows, and common pitfalls. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills. Available skills: use-usdc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md (balances, transfers, approvals on EVM and Solana); EURC has no skill — see https://developers.circle.com/stablecoins/what-is-eurc.md; bridge-stablecoin https://github.com/circlefin/skills/blob/master/plugins/circle/skills/bridge-stablecoin/SKILL.md (crosschain transfers via CCTP, USDC, EURC, and third-party assets); use-arc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md (Arc chain config, contract deployment, USDC bridging — Arc docs: https://docs.arc.io/llms.txt); use-circle-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md (choose wallet type); use-developer-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md (custodial wallets for payouts and treasury); use-user-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md (embedded wallets with Web2 login); use-modular-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md (smart contract wallets with passkeys and ERC-4337); use-gateway https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md (unified USDC balance, nanopayments); use-smart-contract-platform https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md (deploy, interact, monitor contracts). Pair any skill with the Circle MCP server for live SDK signatures, contract addresses, and chain IDs: {"mcpServers":{"circle":{"url":"https://api.circle.com/v1/codegen/mcp"}}}.
> Read the product overview first. Each product has an overview explaining when and why to use it. Read it before quickstarts.
> Pick the right wallet type. Developer-controlled (you hold keys), user-controlled (end user holds keys via PIN/social login), or modular (smart contract wallets with passkeys). See https://developers.circle.com/wallets.md.
> Use CCTP V2 for crosschain transfers. CCTP natively transfers USDC and EURC via burn-and-mint, and supports permissionless wrapping of third-party assets via lock-and-mint. V1 is legacy; always use V2 unless V1 is specified or the chain requires it (Noble, Sui, and Aptos still require V1). Migration guide: https://developers.circle.com/cctp/migration-from-v1-to-v2.md.
> Use Bridge Kit for frontend bridging. Wraps CCTP with a simpler SDK for user-facing apps. Use CCTP directly for backend transfers.
> Gas Station vs Paymaster. Gas Station sponsors gas for Circle Wallet transactions. Paymaster lets users pay gas in USDC. Different use cases — read both overviews.
> Gateway Nanopayments for sub-cent payments. Gasless USDC micropayments down to $0.000001 via x402 and batched settlement. For pay-per-request APIs, AI agent payments, streaming.
> Look up USDC addresses per chain. Never hardcode — use https://developers.circle.com/stablecoins/usdc-contract-addresses.md.
> Prefer SDKs over raw API calls. Node.js and Python SDKs handle auth, retries, and errors.
> API key required. Bearer token in Authorization header. Testnet and mainnet use separate keys and may use different base URLs depending on the product.
> Set up webhooks when available. Most operations are async. Webhooks deliver transaction confirmations and state changes.
> When calling list endpoints, paginate using pageSize and pageAfter until no nextPageAfter cursor is returned—stopping at the first page silently misses records.
> Building an AI agent? Start with the Agent Stack—Circle CLI, agent wallets, and nanopayments built for autonomous use cases: https://developers.circle.com/agent-stack.md.

# How-to: Set up passkey recovery

> Register a recovery key for a modular wallet so users can restore access to their MSCA if they lose their primary passkey.

Passkeys live on a user's device. If the device is lost or the passkey is
deleted, the user can't sign for their MSCA anymore. Passkey recovery solves
this by adding a second signer to the MSCA, an
[externally owned account (EOA)](/wallets/account-types#externally-owned-accounts-eoa)
controlled by a mnemonic the user stores securely. The EOA is the backup signer.
If the user ever loses their passkey, they can sign with the recovery EOA to
register a new passkey on the same MSCA.

<Info>
  For a complete working app, see the [Passkey Recovery
  example](https://github.com/circlefin/modularwallets-web-sdk/tree/master/examples/passkey-recovery)
  in the modular wallets web SDK repository.
</Info>

## Before you begin

Before you begin, ensure that you've:

* [Created a modular wallet](/wallets/modular/create-a-modular-wallet) and have
  access to the `smartAccount`, `bundlerClient`, `client`, `modularTransport`,
  and `passkeyTransport` from that tutorial.
* Installed [`viem`](https://viem.sh/) for mnemonic and EOA generation.

## Steps

<Steps>
  <Step title="Register a recovery key">
    <Warning>
      Register the recovery key while the user still has their original passkey. If
      both the passkey and the recovery mnemonic are lost, the wallet is permanently
      inaccessible.
    </Warning>

    Generate a recovery mnemonic, derive an EOA from it, and register the EOA's
    address as a signer on the MSCA. Extend the bundler client with
    `recoveryActions` to expose the recovery methods.

    Gas options:

    * Pass `paymaster: true` to sponsor gas through your
      [Gas Station](/wallets/gas-station) policy.
    * Call `estimateRegisterRecoveryAddressGas` first to surface the cost to the
      user instead of sponsoring it.

    ```typescript Web SDK (TypeScript) theme={null}
    import { english, generateMnemonic, mnemonicToAccount } from "viem/accounts";
    import { recoveryActions } from "@circle-fin/modular-wallets-core";

    const recoveryClient = bundlerClient.extend(recoveryActions);

    const mnemonic = generateMnemonic(english);
    const recoveryEoa = mnemonicToAccount(mnemonic);

    await recoveryClient.registerRecoveryAddress({
      account: smartAccount,
      recoveryAddress: recoveryEoa.address,
      paymaster: true,
    });
    ```

    `registerRecoveryAddress` submits a user operation and resolves once it lands.
    The recovery EOA is now a signer on the MSCA.

    The mnemonic is the only credential the user needs to recover later. Prompt them
    to store it somewhere safe (a password manager, hardware wallet, or written
    backup) before continuing.
  </Step>

  <Step title="Recover access after passkey loss">
    When the original passkey is gone, take the user's recovery mnemonic and use it
    to add a new passkey to the same MSCA. The flow recreates the recovery EOA,
    registers a new passkey credential, binds that passkey to the original MSCA, and
    rebuilds the smart account using the new credential.

    ```typescript Web SDK (TypeScript) theme={null}
    import { mnemonicToAccount } from "viem/accounts";
    import {
      createBundlerClient,
      toWebAuthnAccount,
    } from "viem/account-abstraction";
    import {
      recoveryActions,
      toCircleSmartAccount,
      toWebAuthnCredential,
      WebAuthnMode,
    } from "@circle-fin/modular-wallets-core";

    // Recreate the recovery EOA and a temporary smart account from it.
    const localAccount = mnemonicToAccount(savedMnemonic);

    const tempSmartAccount = await toCircleSmartAccount({
      client,
      owner: localAccount,
    });

    // Register a new passkey credential.
    const newCredential = await toWebAuthnCredential({
      transport: passkeyTransport,
      mode: WebAuthnMode.Register,
      username: "recovery-passkey",
    });

    // Sign the recovery userOp with the temporary EOA account.
    const recoveryClient = createBundlerClient({
      account: tempSmartAccount,
      chain,
      transport: modularTransport,
    }).extend(recoveryActions);

    // Bind the new passkey to the original MSCA.
    await recoveryClient.executeRecovery({
      account: tempSmartAccount,
      credential: newCredential,
      paymaster: true,
    });

    // Rebuild the smart account using the new passkey.
    const recoveredAccount = await toCircleSmartAccount({
      client,
      owner: toWebAuthnAccount({ credential: newCredential }),
    });
    ```

    The user can now sign with the new passkey.

    <Note>
      Recovery adds the new passkey as an owner on the MSCA. It does not remove the
      original passkey. If the user still has the old credential on a device, both
      might be able to sign.
    </Note>
  </Step>
</Steps>

## Best practices

* **Educate users.** Make it explicit that losing both the passkey and the
  recovery mnemonic permanently locks the wallet. Encourage password managers or
  hardware backups.
* **Offer redundancy.** The MSCA supports multiple recovery addresses. Letting
  users register more than one reduces single-point failure.
* **Test the recovery path.** Walk through the full lose-and-recover flow on
  testnet across the browsers and devices you support before enabling recovery
  in production.
* **Revoke stolen passkeys separately.** Recovery restores access, it does not
  invalidate the original passkey. If a passkey might have been stolen rather
  than lost, add a separate owner-removal flow to your security model.
