Skip to main content
This page has been updated for Wallets SDK V1. If you are using the previous version, see the previous version of this page or the V1 migration guide.

Latest Node.js SDK version - npm

Typescript SDK (@crossmint/wallets-sdk) for creating and managing Crossmint Wallets on EVM, Solana, and Stellar chains.

Prerequisites

Get a Crossmint API key from the developer console. Ensure your key has the Wallet API scopes enabled.
  • Client-side (browser): Use a client API key
  • Server-side (Node.js): Use a server API key

Installation

npm install @crossmint/wallets-sdk
# or
pnpm add @crossmint/wallets-sdk
# or
yarn add @crossmint/wallets-sdk

Quick Start

Server-side (Node.js)

import { createCrossmint, CrossmintWallets } from "@crossmint/wallets-sdk";

const crossmint = createCrossmint({ apiKey: "<YOUR_SERVER_API_KEY>" });
const wallets = CrossmintWallets.from(crossmint);

// Create a wallet with a server signer
const wallet = await wallets.createWallet({
  chain: "base-sepolia",
  recovery: { type: "server", secret: "<RECOVERY_SECRET>" },
});

console.log(wallet.address);

// Send tokens
const tx = await wallet.send("0xRecipientAddress", "usdc", "10");
console.log(tx.explorerLink);

Client-side (Headless)

For client-side usage without React, you can use the SDK directly with JWT authentication:
import { createCrossmint, CrossmintWallets } from "@crossmint/wallets-sdk";

const crossmint = createCrossmint({ apiKey: "<YOUR_CLIENT_API_KEY>" });
crossmint.setJwt("<USER_JWT>");

const wallets = CrossmintWallets.from(crossmint);

const wallet = await wallets.getWallet({ chain: "base-sepolia" });
console.log(wallet.address);
For React apps, use @crossmint/client-sdk-react-ui which provides CrossmintWalletProvider, hooks, and built-in UI for OTP and passkey flows.

Core Concepts

Signers

Wallets SDK uses a two-tier signer model:
  • Recovery signer — High-security, used for wallet recovery and adding new signers. Supports email OTP, phone OTP, external wallet, or server key.
  • Operational signer — Low-friction, used for day-to-day signing. The default is the device signer, which uses hardware-backed keys (no OTP needed). Also supports passkey, server key, and external wallet.
When no operational signer is available, the recovery signer automatically serves as a fallback for signing.

Wallet Lifecycle

// Create a new wallet
const wallet = await wallets.createWallet({
  chain: "base-sepolia",
  recovery: { type: "email", email: "user@example.com" },
  signers: [{ type: "device" }], // optional — device is the default
});

// Retrieve an existing wallet (client-side)
const wallet = await wallets.getWallet({ chain: "base-sepolia" });

// Retrieve an existing wallet (server-side)
const wallet = await wallets.getWallet("0xWalletAddress", {
  chain: "base-sepolia",
});

Usage

Balances

const balances = await wallet.balances();

console.log(balances.nativeToken.amount);
console.log(balances.usdc.amount);

Send Tokens

const tx = await wallet.send("0xRecipient", "usdc", "100");
console.log(tx.explorerLink);

Transfers

const transfers = await wallet.transfers({
  tokens: "usdc",
  status: "successful",
});

NFTs

const nfts = await wallet.nfts({ perPage: 10, page: 1 });

Chain-Specific Transactions

import { EVMWallet, SolanaWallet, StellarWallet } from "@crossmint/wallets-sdk";

// EVM — smart contract interaction
const evmWallet = EVMWallet.from(wallet);
const tx = await evmWallet.sendTransaction({
  to: "0xContractAddress",
  abi: contractAbi,
  functionName: "mint",
  args: [1],
  value: 0n,
});

// EVM — sign a message
const sig = await evmWallet.signMessage({ message: "Hello" });

// EVM — viem public client
const client = evmWallet.getViemClient();

// Solana
const solWallet = SolanaWallet.from(wallet);
const solTx = await solWallet.sendTransaction({
  serializedTransaction: "<base64-encoded-transaction>",
});

// Stellar
const stellarWallet = StellarWallet.from(wallet);
const stellarTx = await stellarWallet.sendTransaction({
  contractId: "C...",
  method: "transfer",
  args: { to: "G...", amount: "1000000" },
});

Signer Management

// Add a new signer
await wallet.addSigner({ type: "server", secret: "<SECRET>" });

// List signers
const signers = await wallet.signers();
console.log(signers); // [{ type: "device", locator: "device:...", status: "success" }, ...]

// Set the active signer
await wallet.useSigner({ type: "server", secret: "<SECRET>" });

// Recovery flow (new device)
if (wallet.needsRecovery()) {
  await wallet.recover(); // uses recovery signer to register a new device signer
}

Transaction Approval (Prepare-Only Mode)

For flows that require multi-step approval:
// Create a transaction without auto-approving
const pendingTx = await wallet.send("0xRecipient", "usdc", "10", {
  prepareOnly: true,
});
console.log(pendingTx.transactionId);

// Approve later
const result = await wallet.approve({
  transactionId: pendingTx.transactionId,
});

Signer Types

TypeUse CasePlatforms
deviceDefault day-to-day signer. Hardware-backed, no OTP.Browser, React Native
serverServer-side automated operations (AI agents, backends).Node.js
emailOTP-based recovery signer.All
phoneOTP-based recovery signer.All
passkeyWebAuthn/FIDO2 biometric signer.Browser (EVM only)
external-walletBring-your-own key (MetaMask, KMS, etc).All

React / React Native

For React applications, use @crossmint/client-sdk-react-ui which provides wallet providers, hooks (useWallet, useWalletOtpSigner), and built-in UI for OTP and passkey flows. For React Native, see @crossmint/client-sdk-react-native-ui.

Documentation

License

Apache-2.0

Signers

Learn about signer types and how to choose the right ones.