The short version

Tatum Smart Wallets give each of your users a multi-chain wallet without you ever holding a full private key. Signing uses MPC: one share lives with you (or the user), the other stays sealed in Tatum’s enclave. Both are required. Neither side can move funds alone.

In practice you install @tatumio/wallet-sdk, create a client per user, call generateWallet(), encrypt the shares, back them up, then send with sendAssets(). Same Tatum API key you already use for the RPC Gateway and Data API. Gas sponsorship is there if you want users to act before they hold native tokens.

This page is the forwardable walkthrough. Deep API detail lives in the Smart Wallets docs.

What are Tatum Smart Wallets?

Most wallet products force a choice: browser extension, seed phrase UX, or keys parked on your servers. Smart Wallets sit in a different spot. They are Tatum’s MPC wallet service for apps that create wallets for many end users (fintech, consumer apps, trading, gaming, agents, banking-style flows).

Each wallet is split into two shares:

  • Client share: returned once by generateWallet(). You encrypt it and store it.
  • Tatum share: sealed in an AWS Nitro Enclave. It never shows up in the SDK.

Normal signing never rebuilds the private key. The two parties just produce a signature together. That is why you can run wallet ops from a backend without treating a raw key like a database column.

Balances and history for those addresses still come from the usual stack: hit a node through the Gateway, or pull portfolios with the Data API. Smart Wallets handle the key and signing side.

UI cards for Smart Wallet capabilities: wallet management, transactions and signing, gas sponsorship, backup and recovery. Tatum wordmark on the navy header.

Core capabilities

Tap a card for the short version of each piece

Tatum

How MPC signing works (2-of-2)

Tatum uses a fixed 2-of-2 model. There is no 2-of-3 or 3-of-5 knob. That keeps the story simple: your share plus Tatum’s share, or no signature.

Share Who holds it What it does
Client share Your app or end user Shown once from generateWallet(). Encrypt it. Tatum cannot recover it for you.
Tatum share AWS Nitro Enclave Never leaves the enclave. Tatum cannot rebuild the full key on its own.

One generateWallet() call covers two curves: SECP256K1 for EVM, Bitcoin, and Tron; ED25519 for Solana and Stellar. You pick the share by curve, not by chain name.

If you want a longer take on custody models, we already wrote about custodial vs non-custodial vs hybrid and wallet as a service.

Before you start

  1. Grab an API key from the Tatum dashboard.
  2. Make sure Smart Wallets is enabled on the account. In beta, custodian endpoints sometimes need a manual flip even when RPC already works. If you see wallets.custodian.api.key.missing, email support@tatum.io from the address on the account.
  3. Node.js 18+, then:
npm install @tatumio/wallet-sdk
export TATUM_API_KEY="your-api-key"

No second API key. After activation, the same key covers Smart Wallets, Gateway RPC, and Data API. Sepolia and Base Sepolia are fine for dry runs. Operations still burn credits, so keep an eye on the balance in the dashboard.

Step by step: create a wallet and send

Your backend is the custodian. Each end user is a client. Generate, sign, backup, and recover all go through the client-scoped SDK. Keep the permanent API key and clientApiKey on the server. Browser and mobile only get short-lived session tokens if you need them.

Six-step wallet lifecycle UI: create client, init client, generate wallet, confirm stored, show address, backup. Progress bar and Tatum wordmark on the navy header.

Interactive onboarding

Walk the wallet lifecycle

Tatum

Working TypeScript example

Run this from a backend service. After the send lands, you can watch the address with Notifications or refresh balances through the Data API.

import { TatumWalletsSdk, WalletChain, WALLET_CHAINS } from "@tatumio/wallet-sdk";

const apiKey = process.env.TATUM_API_KEY;
if (!apiKey) throw new Error("Set TATUM_API_KEY");

const wallets = new TatumWalletsSdk({
  apiKey,
  baseUrl: "https://api.tatum.io",
});

async function onboardAndSend() {
  const newClient = await wallets.custodian.createClient({
    body: { isAccountAbstracted: false },
  });

  const client = wallets.initClient({
    token: newClient.clientApiKey!,
  });

  // Encrypt and store these shares in production
  const shares = await client.generateWallet();

  const details = await client.getClientDetails();
  const signingSharePairIds = details.wallets!.flatMap((w) =>
    (w.signingSharePairs ?? []).map((sp) => sp.id!)
  );
  await client.updateSigningSharePairs({
    body: { signingSharePairIds, status: "STORED_CLIENT" },
  });

  const evmAddress = details.metadata?.namespaces?.["eip155"]?.address;
  console.log("EVM address:", evmAddress);

  const chain = WalletChain.ETHEREUM_SEPOLIA;
  const curve = WALLET_CHAINS[chain].curve;

  const result = await client.sendAssets({
    body: {
      share: shares[curve].share,
      chain,
      to: "0xRecipientAddress",
      token: "NATIVE",
      amount: "0.01",
    },
  });

  console.log("Tx hash:", result.transactionHash);
}

onboardAndSend().catch(console.error);

In production: encrypt shares, create the backup in the same onboarding session, attach the tx hash to your activity feed, and put auth plus policy checks in front of every sendAssets or sign call. If you screen destinations, pair that with malicious address checks before you sign.

Picking the right send or sign call

Most teams live in sendAssets(). The other methods show up when you need inspection, message signing, or a raw digest. Use the rows below instead of guessing from the docs index.

Method picker Tatum

Click a row. The recommended call shows up underneath.

Simple transfer Native coin or token to an address
Inspect first Custom flows, simulation, approval gates
Sign a message Login, permits, typed data
Raw digest Custom protocols without broadcast
Use sendAssets(). It builds, signs, and broadcasts in one shot for native coins and tokens (ETH, MATIC, SOL, ERC-20, SPL, and friends).

ERC-20 and SPL transfers

Pass the contract or mint address as token instead of "NATIVE". For fee context on EVM, you can still lean on fee estimation in the product UI even when sponsorship covers the gas.

// ERC-20 USDC on Ethereum
await client.sendAssets({
  body: {
    share: shares.SECP256K1.share,
    chain: WalletChain.ETHEREUM_MAINNET,
    to: "0xRecipient",
    token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    amount: "100",
  },
});

// SPL USDC on Solana
await client.sendAssets({
  body: {
    share: shares.ED25519.share,
    chain: WalletChain.SOLANA_MAINNET,
    to: "SolanaRecipient",
    token: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    amount: "100",
  },
});

Gas sponsorship

Turn on sponsorGas: true and Tatum’s relayer pays gas on EVM chains. The user still signs. They just do not need native tokens in the wallet first. That is the difference between “download MetaMask and buy ETH” and “tap send inside your app.”

await client.sendAssets({
  body: {
    share: shares.SECP256K1.share,
    chain: WalletChain.POLYGON_MAINNET,
    to: "0xRecipient",
    token: "0xUSDCContractAddress",
    amount: "10",
    sponsorGas: true,
  },
});

Good fit for first-time onboarding and token-only balances. For very chatty flows, ask support about pre-signatures to cut MPC latency.

Supported chains

Filter by mainnet, testnet, or curve. At runtime, pass the share for WALLET_CHAINS[chain].curve. Some chains need an explicit rpcUrl; others resolve through Tatum RPC automatically via your Gateway key.

Filterable supported chains table with Ethereum, Polygon, Base, and Solana rows, curve badges, and Tatum wordmark on the navy header.

Supported networks

Filter by network or curve

Tatum
Chain WalletChain Curve Type

Full matrix: Supported Chains. Chain-specific build guides (for example Polygon or Ethereum) still apply once you have an address to fund.

Backup, recovery, and key eject

Backup shares are not signing shares. Day-to-day signing still uses the active pair. Recovery builds a new signing pair from the backups. If the client signing share and the client backup are both gone, that wallet is not coming back.

Backup Recovery
When Right after generateWallet() When signing shares are lost
SDK call backupWallet() recoverWallet()
Input Original generate response Decrypted backup shares
Output Encrypted backup shares to store New signing shares to store
const backup = await client.backupWallet({
  body: { generateResponse: JSON.stringify(shares) },
});

// Encrypt backup.SECP256K1.share and backup.ED25519.share, then store.
// Optional: store ciphertext with Portal via storeEncryptedBackupShare().

await client.updateBackupSharePairs({
  body: {
    backupSharePairIds: [backup.SECP256K1.id, backup.ED25519.id],
    status: "STORED_CLIENT_BACKUP_SHARE",
  },
});

Key eject rebuilds a normal blockchain private key so someone can leave Tatum’s signing path. Call enableEject() first. You need the client backup plus Tatum’s custodian backup inside the ejectableUntil window. The result imports into a regular external wallet.

Where each secret lives

This is the bit teams usually under-document. Click a row for the storage note. Treat every one of these as a secret, not a log field.

Interactive-style table of Smart Wallet secrets: client signing share, Tatum signing share, backup share, API key, session token. First row expanded. Tatum wordmark on the navy header.
Where each secret lives Click a row for the storage note
Tatum

Returned once from generateWallet(). Encrypt before storage. Passed into every sendAssets / sign call. If this and the client backup are both lost, the wallet is unrecoverable.

Never exposed through the SDK. Lives in a hardware-backed enclave. Needed for day-to-day MPC signing alongside the client share.

From backupWallet(). Cannot sign directly. Used only for recovery (and key eject). Encrypt with a key the user or your ops policy controls.

Powers custodian calls, Gateway RPC, and Data API. Environment variable or secrets manager. Never ship it to a browser bundle.

Permanent clientApiKey stays server-side. Use session tokens when the frontend must call client-scoped methods. Do not reuse a session token for custodian endpoints.

Common errors

Status Usually means What to try
401 Bad or missing API key Check apiKey on TatumWalletsSdk
403 Token used in the wrong place Do not hit custodian endpoints with a session token
404 Unknown client or wallet Confirm IDs and that staging IDs are not hitting production
422 Wrong share, chain, or funds Match curve to chain, use WalletChain, or enable sponsorGas

Catch WalletsApiError for HTTP failures and plain TypeError when the network never answers. Longer patterns: Error Handling.

Security checklist

  • Keep the Tatum API key and permanent clientApiKey on the backend.
  • Encrypt signing and backup shares before they touch disk (AES-256-GCM or KMS).
  • Require real auth before send, recover, or eject.
  • Run limits, destination checks, and approvals before signing.
  • Never log shares, backup material, or session tokens.
  • If you plan to leave Tatum someday, practice key eject before you need it under pressure.

Banks and regulated stacks: Smart Wallets for Banks. Consumer wallet apps: Smart Wallets for Wallet App. Broader secure flow patterns: Building Secure User Wallet Flows.

Smart Wallets FAQ

Answers stay closed until you open a question.

Tatum’s MPC wallet service for end-user wallets. You create and manage them with the Wallet SDK and /v4/wallets API without handling raw private keys. Product page: tatum.io/wallets.

No. Tatum never holds the client share, and its own share stays in a hardware-backed enclave. It joins the MPC protocol. It cannot rebuild the full key alone.

No. After Smart Wallets is on for your account, use the same Tatum API key with @tatumio/wallet-sdk that you use for Gateway and Data API.

No hard caps on wallets, signing ops, or transactions. Ops burn Tatum credits, so keep enough balance for the volume you run.

Standard MPC signing needs both shares, so signing pauses without Tatum. Key eject lets you rebuild a full private key and keep going on your own.

Next steps

  1. Get an API key and ask for Smart Wallets access if it is not on yet.
  2. Install @tatumio/wallet-sdk and run the onboarding flow on a testnet.
  3. Back up in the same session as generateWallet().
  4. Put sendAssets / sponsorGas behind your auth and policy layer.
  5. Keep the docs and this page handy for the next person who asks how Smart Wallets work.

Package: @tatumio/wallet-sdk · Source: tatumio/wallet-sdk