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

# Configure Wallet Recovery

> Set up a recovery signer so users can regain wallet access from a new device.

<Note>
  **This page has been updated for Wallets SDK V1.** If you are using the previous version,
  see the [previous version docs](/wallets/v0/overview) or the [V1 migration guide](/wallets/guides/migrate-to-v1).
</Note>

A recovery signer lets users regain access to their wallet when their primary (device) signer is no longer available — for example, when they switch to a new phone or clear their browser data. The recovery signer authorizes the enrollment of a new device signer on the new device.

Recovery signers are configured at **wallet creation time**. You can choose from email OTP, SMS OTP, or a server signer depending on your application's needs.

<Note>
  Recovery signers can also sign transactions when needed — they are not limited to recovery only. However, they involve higher friction (OTP verification or server-side signing), so they are best reserved for recovery flows and as a fallback.
</Note>

## Prerequisites

* A Crossmint API key with `wallets.create` scope
* For email OTP: the user's email address
* For SMS OTP: the user's phone number in E.164 format (e.g., `+1234567890`)
* For server signer: a [signer secret](/wallets/guides/signers/server-signer#generate-a-signer-secret) stored on your server

## Email OTP Recovery

The user verifies ownership of their email address via a one-time password sent by Crossmint. This is the most common recovery method for consumer applications.

<Tabs>
  <Tab title="React">
    Using `createOnLogin` on the provider (recommended):

    ```tsx theme={null}
    import {
        CrossmintProvider,
        CrossmintAuthProvider,
        CrossmintWalletProvider,
    } from "@crossmint/client-sdk-react-ui";

    function App({ children }) {
        return (
            <CrossmintProvider apiKey="YOUR_CLIENT_API_KEY">
                <CrossmintAuthProvider
                    loginMethods={["email", "google"]}
                >
                    <CrossmintWalletProvider
                        createOnLogin={{
                            chain: "base-sepolia",
                            recovery: { type: "email" },
                        }}
                    >
                        {children}
                    </CrossmintWalletProvider>
                </CrossmintAuthProvider>
            </CrossmintProvider>
        );
    }
    ```

    Or using `createWallet` directly:

    ```typescript theme={null}
    import { useWallet } from "@crossmint/client-sdk-react-ui";

    const { createWallet } = useWallet();

    const wallet = await createWallet({
        chain: "base-sepolia",
        recovery: {
            type: "email",
            email: "user@example.com", // Omit when using CrossmintAuthProvider (auto-populated)
        },
    });
    ```
  </Tab>

  <Tab title="Node.js">
    ```ts theme={null}
    import {
        createCrossmint,
        CrossmintWallets,
    } from "@crossmint/wallets-sdk";

    const crossmint = createCrossmint({
        apiKey: "YOUR_SERVER_API_KEY",
    });
    const crossmintWallets = CrossmintWallets.from(crossmint);

    try {
        const wallet = await crossmintWallets.createWallet({
            chain: "base-sepolia",
            owner: "email:user@example.com",
            recovery: {
                type: "email",
                email: "user@example.com",
            },
        });
    } catch (error) {
        console.error("Failed to create wallet:", error);
    }
    ```
  </Tab>

  <Tab title="React Native">
    ```tsx theme={null}
    import {
        CrossmintProvider,
        CrossmintAuthProvider,
        CrossmintWalletProvider,
    } from "@crossmint/client-sdk-react-native-ui";

    function App({ children }) {
        return (
            <CrossmintProvider apiKey="YOUR_CLIENT_API_KEY">
                <CrossmintAuthProvider
                    loginMethods={["email", "google"]}
                >
                    <CrossmintWalletProvider
                        createOnLogin={{
                            chain: "base-sepolia",
                            recovery: { type: "email" },
                        }}
                    >
                        {children}
                    </CrossmintWalletProvider>
                </CrossmintAuthProvider>
            </CrossmintProvider>
        );
    }
    ```
  </Tab>

  <Tab title="Flutter">
    ```dart theme={null}
    import 'package:flutter/material.dart';
    import 'package:crossmint_flutter/crossmint_flutter_ui.dart';

    class MyApp extends StatelessWidget {
      const MyApp({super.key});

      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: CrossmintWalletProvider(
            config: CrossmintWalletProviderConfig(
              clientConfig: const CrossmintClientConfig(
                apiKey: 'YOUR_CLIENT_API_KEY',
                appScheme: 'myapp',
              ),
              walletControllerConfig: const CrossmintWalletControllerConfig(
                createOnLogin: CrossmintCreateOnLoginConfig(
                  chain: 'base-sepolia',
                  recovery: CrossmintEmailSignerConfig(),
                ),
              ),
              otpPromptBuilder: crossmintDefaultOtpPromptBuilder,
            ),
            child: const HomeScreen(),
          ),
        );
      }
    }
    ```

    When `CrossmintEmailSignerConfig()` is used with `createOnLogin`, the email is
    auto-populated from the authenticated user.
  </Tab>

  <Tab title="REST">
    <CodeGroup>
      ```bash cURL theme={null}
      curl --request POST \
          --url https://staging.crossmint.com/api/2025-06-09/wallets \
          --header 'Content-Type: application/json' \
          --header 'X-API-KEY: YOUR_SERVER_API_KEY' \
          --data '{
              "type": "evm-smart-wallet",
              "config": {
                  "adminSigner": {
                      "type": "email",
                      "email": "user@example.com"
                  }
              }
          }'
      ```

      ```js Node.js theme={null}
      const url =
          "https://staging.crossmint.com/api/2025-06-09/wallets";

      const payload = {
          type: "evm-smart-wallet",
          config: {
              adminSigner: {
                  type: "email",
                  email: "user@example.com",
              },
          },
      };

      const response = await fetch(url, {
          method: "POST",
          headers: {
              "X-API-KEY": "YOUR_SERVER_API_KEY",
              "Content-Type": "application/json",
          },
          body: JSON.stringify(payload),
      });

      const data = await response.json();
      console.log(data);
      ```

      ```python Python theme={null}
      import requests

      url = "https://staging.crossmint.com/api/2025-06-09/wallets"

      payload = {
          "type": "evm-smart-wallet",
          "config": {
              "adminSigner": {
                  "type": "email",
                  "email": "user@example.com"
              }
          }
      }
      headers = {
          "X-API-KEY": "YOUR_SERVER_API_KEY",
          "Content-Type": "application/json"
      }

      response = requests.post(url, json=payload, headers=headers)
      print(response.json())
      ```
    </CodeGroup>

    <Note>
      The REST API uses the legacy field name `adminSigner` for the recovery signer. The SDK uses `recovery`.
    </Note>
  </Tab>
</Tabs>

## SMS OTP Recovery

The user verifies ownership of their phone number via a one-time password delivered by SMS (or optionally WhatsApp). This is ideal for mobile-first applications.

<Tabs>
  <Tab title="React">
    Using `createOnLogin` on the provider:

    ```tsx theme={null}
    import {
        CrossmintProvider,
        CrossmintAuthProvider,
        CrossmintWalletProvider,
    } from "@crossmint/client-sdk-react-ui";

    function App({ children }) {
        return (
            <CrossmintProvider apiKey="YOUR_CLIENT_API_KEY">
                <CrossmintAuthProvider
                    loginMethods={["email", "google"]}
                >
                    <CrossmintWalletProvider
                        createOnLogin={{
                            chain: "base-sepolia",
                            recovery: {
                                type: "phone",
                                phone: "+1234567890",
                            },
                        }}
                    >
                        {children}
                    </CrossmintWalletProvider>
                </CrossmintAuthProvider>
            </CrossmintProvider>
        );
    }
    ```

    Or using `createWallet` directly:

    ```typescript theme={null}
    import { useWallet } from "@crossmint/client-sdk-react-ui";

    const { createWallet } = useWallet();

    const wallet = await createWallet({
        chain: "base-sepolia",
        recovery: {
            type: "phone",
            phone: "+1234567890", // E.164 format required
        },
    });
    ```
  </Tab>

  <Tab title="Node.js">
    ```ts theme={null}
    import {
        createCrossmint,
        CrossmintWallets,
    } from "@crossmint/wallets-sdk";

    const crossmint = createCrossmint({
        apiKey: "YOUR_SERVER_API_KEY",
    });
    const crossmintWallets = CrossmintWallets.from(crossmint);

    try {
        const wallet = await crossmintWallets.createWallet({
            chain: "base-sepolia",
            owner: "phone:+12223334444",
            recovery: {
                type: "phone",
                phone: "+12223334444", // E.164 format required
            },
        });
    } catch (error) {
        console.error("Failed to create wallet:", error);
    }
    ```
  </Tab>

  <Tab title="React Native">
    ```tsx theme={null}
    import {
        CrossmintProvider,
        CrossmintAuthProvider,
        CrossmintWalletProvider,
    } from "@crossmint/client-sdk-react-native-ui";

    function App({ children }) {
        return (
            <CrossmintProvider apiKey="YOUR_CLIENT_API_KEY">
                <CrossmintAuthProvider
                    loginMethods={["email", "google"]}
                >
                    <CrossmintWalletProvider
                        createOnLogin={{
                            chain: "base-sepolia",
                            recovery: {
                                type: "phone",
                                phone: "+1234567890",
                            },
                        }}
                    >
                        {children}
                    </CrossmintWalletProvider>
                </CrossmintAuthProvider>
            </CrossmintProvider>
        );
    }
    ```
  </Tab>

  <Tab title="Flutter">
    ```dart theme={null}
    import 'package:crossmint_flutter/crossmint_flutter_ui.dart';

    CrossmintWalletProvider(
      config: CrossmintWalletProviderConfig(
        clientConfig: const CrossmintClientConfig(
          apiKey: 'YOUR_CLIENT_API_KEY',
          appScheme: 'myapp',
        ),
        walletControllerConfig: const CrossmintWalletControllerConfig(
          createOnLogin: CrossmintCreateOnLoginConfig(
            chain: 'base-sepolia',
            recovery: CrossmintPhoneSignerConfig(phone: 'YOUR_E164_PHONE_NUMBER'),
          ),
        ),
        otpPromptBuilder: crossmintDefaultOtpPromptBuilder,
      ),
      child: const HomeScreen(),
    )
    ```

    Phone numbers must be in E.164 format (e.g. `+1234567890`).
  </Tab>

  <Tab title="REST">
    <CodeGroup>
      ```bash cURL theme={null}
      curl --request POST \
          --url https://staging.crossmint.com/api/2025-06-09/wallets \
          --header 'Content-Type: application/json' \
          --header 'X-API-KEY: YOUR_SERVER_API_KEY' \
          --data '{
              "type": "evm-smart-wallet",
              "config": {
                  "adminSigner": {
                      "type": "phone",
                      "phone": "+1234567890"
                  }
              }
          }'
      ```

      ```js Node.js theme={null}
      const url =
          "https://staging.crossmint.com/api/2025-06-09/wallets";

      const payload = {
          type: "evm-smart-wallet",
          config: {
              adminSigner: {
                  type: "phone",
                  phone: "+1234567890",
              },
          },
      };

      const response = await fetch(url, {
          method: "POST",
          headers: {
              "X-API-KEY": "YOUR_SERVER_API_KEY",
              "Content-Type": "application/json",
          },
          body: JSON.stringify(payload),
      });

      const data = await response.json();
      console.log(data);
      ```

      ```python Python theme={null}
      import requests

      url = "https://staging.crossmint.com/api/2025-06-09/wallets"

      payload = {
          "type": "evm-smart-wallet",
          "config": {
              "adminSigner": {
                  "type": "phone",
                  "phone": "+1234567890"
              }
          }
      }
      headers = {
          "X-API-KEY": "YOUR_SERVER_API_KEY",
          "Content-Type": "application/json"
      }

      response = requests.post(url, json=payload, headers=headers)
      print(response.json())
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Server Signer as Recovery

Use a server signer as the recovery signer when you want your backend to manage recovery without user-facing OTP flows. This is common for AI agents, backend automation, and hybrid architectures where the server creates wallets that clients later use.

```ts theme={null}
import {
    createCrossmint,
    CrossmintWallets,
} from "@crossmint/wallets-sdk";

const crossmint = createCrossmint({
    apiKey: "YOUR_SERVER_API_KEY",
});
const crossmintWallets = CrossmintWallets.from(crossmint);

const wallet = await crossmintWallets.createWallet({
    chain: "base-sepolia",
    recovery: {
        type: "server",
        secret: process.env.CROSSMINT_SIGNER_SECRET,
    },
});
```

For more on generating and managing server signer secrets, see the [Server Signer guide](/wallets/guides/signers/server-signer).

## How Recovery Works on a New Device

When a user accesses their wallet from a new device where no device signer exists:

1. The user authenticates via your app — the SDK retrieves the wallet
2. The SDK detects no local device signer on this device
3. On the first transaction (or when `recover()` is called), the SDK triggers the recovery flow:
   * **Email OTP**: Crossmint sends a one-time code to the user's email
   * **SMS OTP**: Crossmint sends a one-time code to the user's phone
   * **Server signer**: your backend signs the recovery approval automatically
4. The recovery signer authorizes a new device signer for this device
5. All subsequent transactions on the new device are frictionless

```typescript theme={null}
import { useWallet } from "@crossmint/client-sdk-react-ui";

const { wallet } = useWallet();

// Check if recovery is needed on this device
if (wallet.needsRecovery()) {
    // Trigger recovery proactively (optional)
    await wallet.recover();
}
```

<Note>
  The previous device's signer remains valid. Each device maintains its own independent device signer.
</Note>

## Choosing a Recovery Method

| Method        | Best For                                   | User Friction       | Server Required |
| ------------- | ------------------------------------------ | ------------------- | --------------- |
| Email OTP     | Consumer apps with email-based auth        | Medium (OTP prompt) | No              |
| SMS OTP       | Mobile-first apps                          | Medium (OTP prompt) | No              |
| Server signer | AI agents, backend automation, hybrid apps | None (automatic)    | Yes             |

<Warning>
  Email and phone recovery signers can only be configured at wallet creation time. They cannot be added later via `addSigner()`. Plan your recovery strategy before creating wallets.
</Warning>

## Next Steps

<CardGroup cols={3}>
  <Card title="Device Signer" icon="microchip" href="/wallets/guides/signers/device-signer">
    Understand how the default client-side signer works
  </Card>

  <Card title="Server Signer" icon="server" href="/wallets/guides/signers/server-signer">
    Set up server-side signing with key derivation
  </Card>

  <Card title="Add Signers" icon="key" href="/wallets/guides/signers/add-signers">
    Add passkeys or external wallets to an existing wallet
  </Card>
</CardGroup>
