> ## 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.

# Registering a Signer

> Register an operational signer on an existing Crossmint wallet.

<Warning>
  **You are viewing docs for the previous version of the Wallets SDK.** We recommend upgrading to V1.
  See the [updated version of this page](/wallets/guides/signers/add-signers) or the [V1 migration guide](/wallets/guides/migrate-to-v1).
</Warning>

<Warning>
  Previous versions of these guides used the term **delegated signer**. We have moved to **operational signer** as the standard terminology. The next breaking API / SDK version will adopt this naming convention in method signatures and types. Until then, the code snippets below still reference `addDelegatedSigner` and `delegatedSigners`.
</Warning>

Register an operational signer on an existing wallet for day-to-day operations. This signer can be set up with the wallet owner — for example, a device key for user wallets or a server key for company wallets.

For an overview of available signer types, see [Wallet Signers](/wallets/v0/concepts/wallet-signers).

## Prerequisites

* Ensure you have a wallet created.
* **API Key**: Ensure you have an API key with the scopes: `wallets:signatures.create` and `wallets:transactions.create`.

## Adding an operational signer

<Tabs>
  <Tab title="React">
    ```typescript theme={null}
    import { useWallet } from '@crossmint/client-sdk-react-ui';

    const { wallet } = useWallet();

    const externalSigner = {
        type: "external-wallet",
        address: "0x1234567890123456789012345678901234567890"
    }

    await wallet.addDelegatedSigner({
        signer: externalSigner,
    });
    ```

    See the [React SDK reference](/sdk-reference/wallets/v0/react/hooks#wallet-methods) for more details.
  </Tab>

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

    const crossmint = createCrossmint({
        apiKey: "<your-server-api-key>",
    });

    const crossmintWallets = CrossmintWallets.from(crossmint);
    const apiClient = new WalletsApiClient(crossmint);

    // The wallet's admin (recovery) signer — used to approve adding the new signer
    const adminAccount = privateKeyToAccount(
        process.env.ADMIN_WALLET_PRIVATE_KEY as `0x${string}`
    );

    // The new operational signer to register
    const operationalSignerAddress = "0x1234567890123456789012345678901234567890";

    const wallet = await crossmintWallets.getWallet(
        "<wallet-address>",
        { chain: "base-sepolia", signer: { type: "external-wallet" } }
    );

    // 1. Add the operational signer in prepare-only mode
    const { signatureId } = await wallet.addDelegatedSigner({
        signer: `external-wallet:${operationalSignerAddress}`,
        options: { experimental_prepareOnly: true },
    });

    // 2. Fetch the pending signature to get the message that needs signing
    const delegatedSignatureResponse = await apiClient.getSignature(
        wallet.address,
        signatureId
    );
    if ("error" in delegatedSignatureResponse) {
        throw new Error(
            `Failed to get signature: ${JSON.stringify(delegatedSignatureResponse)}`
        );
    }

    const pendingApproval = delegatedSignatureResponse.approvals?.pending?.[0];
    if (!pendingApproval) {
        throw new Error("No pending approval found");
    }

    // 3. Sign the pending approval with the admin signer's private key
    //    (the wallet's original signer, not the signer being added)
    const signature = await adminAccount.signMessage({
        message: { raw: pendingApproval.message as `0x${string}` },
    });

    // 4. Submit the approval using the admin signer
    await wallet.approve({
        signatureId,
        options: {
            experimental_approval: {
                signature,
                signer: `external-wallet:${adminAccount.address}`,
            },
        },
    });

    console.log("Operational signer added successfully");
    ```

    <Note>
      If the wallet's admin (recovery) signer is an `api-key` type, the approval is handled automatically — you can call `addDelegatedSigner` without `experimental_prepareOnly` and skip the approval steps.
    </Note>

    See the [SDK reference](/sdk-reference/wallets/v0/typescript/classes/Wallet#adddelegatedsigner) for all parameters and return types.
  </Tab>

  <Tab title="React Native">
    ```typescript theme={null}
    import { useWallet } from '@crossmint/client-sdk-react-native-ui';

    const { wallet } = useWallet();

    const externalSigner = {
        type: "external-wallet",
        address: "0x1234567890123456789012345678901234567890"
    }

    await wallet.addDelegatedSigner({
        signer: externalSigner,
    });
    ```

    See the [React Native SDK reference](/sdk-reference/wallets/v0/react-native/hooks#wallet-methods) for more details.
  </Tab>

  <Tab title="REST">
    Operational signers must be approved by the wallet's recovery signer (called `adminSigner` in the current API).
    The SDK handles this automatically, but with the REST API you must [approve the transaction](/api-reference/wallets/approve-transaction) (if using Solana, Stellar)
    or [signature](/api-reference/wallets/approve-signature) (if using EVM) to complete it.

    <Steps>
      <Step title="Create the operational signer">
        Call the [create delegated signer](/api-reference/wallets/register-delegated-key) endpoint.

        <CodeGroup>
          ```bash cURL theme={null}
          curl --request POST \
              --url https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:evm/signers \
              --header 'Content-Type: application/json' \
              --header 'X-API-KEY: <x-api-key>' \
              --data '{
                  "chain": "base",
                  "signer": "external-wallet:0x1234567890123456789012345678901234567890"
              }'
          ```

          ```js Node.js theme={null}
          const url = 'https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:evm/signers';

          const payload = {
              chain: "base",
              signer: "external-wallet:0x1234567890123456789012345678901234567890"
          };

          const options = {
              method: 'POST',
              headers: {
                  'X-API-KEY': '<x-api-key>',
                  'Content-Type': 'application/json'
              },
              body: JSON.stringify(payload)
          };

          try {
              const response = await fetch(url, options);
              const data = await response.json();
              console.log(data);
          } catch (error) {
              console.error(error);
          }
          ```

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

          url = "https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:evm/signers"

          payload = {
              "chain": "base",
              "signer": "external-wallet:0x1234567890123456789012345678901234567890"
          }
          headers = {
              "X-API-KEY": "<x-api-key>",
              "Content-Type": "application/json"
          }

          response = requests.post(url, json=payload, headers=headers)

          print(response.json())
          ```
        </CodeGroup>

        See the [API reference](/api-reference/wallets/register-delegated-key) for more details.
      </Step>

      <Step title="Sign the approval returned in the response">
        <Note>
          If you are using an `api-key` as the recovery signer (admin signer) you can skip the following steps.
        </Note>

        Sign the approval message field returned in the response inside `transaction.approvals` (for EVM) or `signature.approvals` (for Solana and Stellar)             using the recovery signer (admin signer).
      </Step>

      <Step title="Approve the transaction or signature to register the operational signer">
        <Tabs>
          <Tab title="EVM">
            Call the [approve signature](/api-reference/wallets/approve-signature) endpoint using the signature from the previous step and the signature id returned in the call from Step 1.

            <CodeGroup>
              ```bash cURL theme={null}
              curl --request POST \
                  --url https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:evm/signatures/b984491a-5785-43c0-8811-45d46fe6e520/approvals \
                  --header 'Content-Type: application/json' \
                  --header 'X-API-KEY: <x-api-key>' \
                  --data '{
                      "approvals": [{
                          "signer": "email:user@example.com",
                          "signature": "0x1234567890abcdef..."
                      }]
                  }'
              ```

              ```js Node.js theme={null}
              const url = 'https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:evm/signatures/b984491a-5785-43c0-8811-45d46fe6e520/approvals';

              const payload = {
                  approvals: [{
                      signer: "email:user@example.com",
                      signature: "0x1234567890abcdef..."
                  }]
              };

              const options = {
                  method: 'POST',
                  headers: {
                      'X-API-KEY': '<x-api-key>',
                      'Content-Type': 'application/json'
                  },
                  body: JSON.stringify(payload)
              };

              try {
                  const response = await fetch(url, options);
                  const data = await response.json();
                  console.log(data);
              } catch (error) {
                  console.error(error);
              }
              ```

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

              url = "https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:evm/signatures/b984491a-5785-43c0-8811-45d46fe6e520/approvals"

              payload = {
                  "approvals": [{
                      "signer": "email:user@example.com",
                      "signature": "0x1234567890abcdef..."
                  }]
              }
              headers = {
                  "X-API-KEY": "<x-api-key>",
                  "Content-Type": "application/json"
              }

              response = requests.post(url, json=payload, headers=headers)

              print(response.json())
              ```
            </CodeGroup>

            See the [API reference](/api-reference/wallets/approve-signature) for more details.
          </Tab>

          <Tab title="Solana and Stellar">
            Call the [approve transaction](/api-reference/wallets/approve-transaction) endpoint using the signature from the previous step and the transaction id returned in the call from Step 1.

            <CodeGroup>
              ```bash cURL theme={null}
              curl --request POST \
                  --url https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:solana/transactions/b984491a-5785-43c0-8811-45d46fe6e520/approvals \
                  --header 'Content-Type: application/json' \
                  --header 'X-API-KEY: <x-api-key>' \
                  --data '{
                      "approvals": [{
                          "signer": "email:user@example.com",
                          "signature": "5qY6wXw6zTn7..."
                      }]
                  }'
              ```

              ```js Node.js theme={null}
              const url = 'https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:solana/transactions/b984491a-5785-43c0-8811-45d46fe6e520/approvals';

              const payload = {
                  approvals: [{
                      signer: "email:user@example.com",
                      signature: "5qY6wXw6zTn7..."
                  }]
              };

              const options = {
                  method: 'POST',
                  headers: {
                      'X-API-KEY': '<x-api-key>',
                      'Content-Type': 'application/json'
                  },
                  body: JSON.stringify(payload)
              };

              try {
                  const response = await fetch(url, options);
                  const data = await response.json();
                  console.log(data);
              } catch (error) {
                  console.error(error);
              }
              ```

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

              url = "https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:solana/transactions/b984491a-5785-43c0-8811-45d46fe6e520/approvals"

              payload = {
                  "approvals": [{
                      "signer": "email:user@example.com",
                      "signature": "5qY6wXw6zTn7..."
                  }]
              }
              headers = {
                  "X-API-KEY": "<x-api-key>",
                  "Content-Type": "application/json"
              }

              response = requests.post(url, json=payload, headers=headers)

              print(response.json())
              ```
            </CodeGroup>

            See the [API reference](/api-reference/wallets/approve-transaction) for more details.
          </Tab>
        </Tabs>
      </Step>
    </Steps>
  </Tab>
</Tabs>

## Listing all operational signers

<Tabs>
  <Tab title="React">
    ```typescript theme={null}
    import { useWallet } from '@crossmint/client-sdk-react-ui';

    const { wallet } = useWallet();

    const signers = await wallet.delegatedSigners();
    ```

    See the [React SDK reference](/sdk-reference/wallets/v0/react/hooks#wallet-methods) for more details.
  </Tab>

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

    const crossmint = createCrossmint({
        apiKey: "<your-server-api-key>",
    });

    const crossmintWallets = CrossmintWallets.from(crossmint);

    const wallet = await crossmintWallets.getWallet(
        "<wallet-address>",
        { chain: "base-sepolia", signer: { type: "external-wallet" } }
    );

    const signers = await wallet.delegatedSigners();
    ```

    See the [SDK reference](/sdk-reference/wallets/v0/typescript/classes/Wallet#delegatedsigners) for all parameters and return types.
  </Tab>

  <Tab title="React Native">
    ```typescript React Native theme={null}
    import { useWallet } from '@crossmint/client-sdk-react-native-ui';

    const { wallet } = useWallet();

    const signers = await wallet.delegatedSigners();
    ```

    See the [React Native SDK reference](/sdk-reference/wallets/v0/react-native/hooks#wallet-methods) for more details.
  </Tab>

  <Tab title="REST">
    <CodeGroup>
      ```bash cURL theme={null}
      curl --request GET \
          --url https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:evm \
          --header 'X-API-KEY: <x-api-key>'
      ```

      ```js Node.js theme={null}
      const url = 'https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:evm';

      const options = {
          method: 'GET',
          headers: {
              'X-API-KEY': '<x-api-key>'
          }
      };

      try {
          const response = await fetch(url, options);
          const data = await response.json();
          console.log(data);
      } catch (error) {
          console.error(error);
      }
      ```

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

      url = "https://staging.crossmint.com/api/2025-06-09/wallets/email:user@example.com:evm"

      headers = {"X-API-KEY": "<x-api-key>"}

      response = requests.get(url, headers=headers)

      print(response.json())
      ```
    </CodeGroup>

    See the [API reference](/api-reference/wallets/get-wallet-by-locator) for more details.
  </Tab>
</Tabs>
