Skip to main content
This guide covers every breaking change in the Wallets SDK V1 release. It is organized by audience — client-side (React / React Native, Swift, Kotlin), server-side (Node.js), and REST API — so you can jump to the section that applies to you.
V1 is a major release with breaking changes. Read through the relevant sections before upgrading your packages.

Terminology changes

V1 renames several concepts. Use this table as a find-and-replace checklist across your codebase.

Client-side migration (React / React Native)

1. Update packages

Update all @crossmint packages to V1 versions:

2. Update createOnLogin in your provider

The signer field is now recovery, and delegatedSigners is now signers.
Device signers are now the default operational signer. If you do not specify signers, a device signer is created automatically.

3. Replace getOrCreateWallet with getWallet + createWallet

getOrCreateWallet has been removed. Use getWallet to retrieve an existing wallet. If it throws WalletNotAvailableError, call createWallet.

4. Replace customAuth with setJwt

If you use a third-party auth provider (BYOA), replace experimental_setCustomAuth with setJwt.
See the Bring Your Own Auth guide for complete setup instructions.

5. Remove experimental_ prefixes

All experimental_ prefixes have been removed from wallet methods and options.

6. Replace useWalletEmailSigner with useWalletOtpSigner

The useWalletEmailSigner hook has been replaced by useWalletOtpSigner, which works for both email and phone OTP flows.

7. Replace addDelegatedSigner with addSigner

The method name and signature have changed. addSigner now accepts signer config objects in addition to locator strings.

8. Remove Farcaster and Dynamic login references

Farcaster sign-in and Dynamic wallet login have been removed entirely. If you used either, migrate to an alternative auth method.
  • Remove "farcaster" from loginMethods in CrossmintAuthProvider.
  • Remove "web3" from loginMethods.
  • Remove any FarcasterSignIn, Web3AuthFlow, or DynamicWalletProvider imports.

9. Understand device signers

Device signers are a new signer type backed by the device’s hardware security module (Secure Enclave on mobile, IndexedDB on web). They are the default operational signer — no OTP is required for day-to-day signing. Key points:
  • No code change is needed if you want the default device signer behavior.
  • Call wallet.needsRecovery() to check if the device signer needs to be re-established (e.g. after the user switches devices).
  • Call wallet.recover() to trigger recovery using the recovery signer.

10. Use useSigner() for non-device signers

If you need to sign with a non-device signer (e.g. passkey, external wallet, server), call wallet.useSigner() first.
useSigner() only accepts signer config objects — locator strings (e.g. "external-wallet:0x...") are no longer accepted.

11. Update external wallet signer to use onSign

V1 replaces chain-specific signing props (provider, viemAccount, onSignTransaction, onSignStellarTransaction) with a single unified onSign callback. When using an external-wallet signer (via useSigner), both address and onSign are required.
Registration vs. usage: When registering an external-wallet signer (in createWallet({ signers: [...] }) or addSigner()), only address is needed — no onSign. The onSign callback is only required when actively signing via useSigner().

Client-side migration (Swift)

1. Update the SDK version

In Xcode, go to your package dependency for crossmint-swift-sdk and update the version requirement:

2. Replace getOrCreateWallet with getWallet + createWallet

getOrCreateWallet has been removed. Use getWallet to retrieve an existing wallet. If it returns nil, call createWallet. The signer parameter is now named recovery.

3. Update OTP authentication

The single otpAuthentication() method has been replaced with two explicit steps: sendEmailOtp and confirmEmailOtp.

4. Understand device signers

Device signers are a new signer type backed by the device’s hardware security module (Secure Enclave). They are the default operational signer — no OTP is required for day-to-day signing. Key points:
  • No code change is needed if you want the default device signer behavior.
  • Opt in explicitly via WalletOptions(deviceSigner: true) if you need to control it.
  • Call wallet.needsRecovery() to check if the device signer needs to be re-established (e.g. after the user reinstalls the app or switches devices).
  • Call wallet.recover() to trigger recovery using the recovery signer.

5. Add and manage signers

Signer management is available on Wallet.

6. Update ApiKeySigner initialization

ApiKeySigner no longer provides a default ApiKeySignerData — you must pass one explicitly.

7. Replace the deprecated Signers enum

The Signers enum is deprecated. Use EVMSigners or SolanaSigners for type-safe chain compatibility.

Client-side migration (Kotlin)

1. Update the SDK version

Update the version in your libs.versions.toml or build.gradle.kts:

2. Replace getOrCreateWallet with getWallet + createWallet

getOrCreateWallet has been removed. Use getWallet to retrieve an existing wallet. If it returns a failure, call createWallet. The signer parameter is now named recovery.

3. Understand device signers

Device signers are a new signer type backed by the device’s hardware security module (Android Keystore). They are the default operational signer — no OTP is required for day-to-day signing. Key points:
  • No code change is needed if you want the default device signer behavior.
  • Call wallet.needsRecovery() to check if the device signer needs to be re-established (e.g. after the user reinstalls the app or switches devices).
  • Call wallet.recover() to trigger recovery using the recovery signer.

4. Add and manage signers

Signer management is a first-class API on Wallet.

5. Use SignerSelection in send and approve

send() and approve() now accept an optional signer: SignerSelection parameter. It defaults to SignerSelection.Admin (the recovery signer), so existing call sites without the parameter continue to work. Pass SignerSelection.Delegated(...) to sign with an operational signer.

6. Check balances and list transfers

balances(), fund(), and listTransfers() are available directly on Wallet.

Server-side migration (Node.js)

owner field behavior:
  • Client-side: owner must NOT be provided — it is automatically derived from the JWT. The client-side types (ClientSideWalletArgsFor, ClientSideWalletCreateArgs) omit it entirely.
  • Server-side with email/phone signers: owner is required — must be manually set.
  • Server-side with any other signer (device, passkey, API key, external wallet, server signer): owner is optional.

1. Update packages

2. Replace getOrCreateWallet with createWallet / getWallet

3. Update signer configuration

The old signer field (admin signer) is now recovery, and delegatedSigners is now signers.

4. Migrate from API key signer to server signer

If you were using the API key as a signer for server-side operations, migrate to the new server signer. Server signers use deterministic key derivation from a secret you control.
Store your server signer secret securely. The same secret always derives the same key, so losing it means losing signing access. Crossmint never has access to your secret.

5. Remove experimental_ prefixes

Same as client-side — remove all experimental_ prefixes from method names and option fields.

REST API migration

The REST API changes in V1 are additive — there are no breaking changes to existing endpoints. The main addition is server signer support.

Switch to the 2025-06-09 API version

Server signers require the 2025-06-09 API version. Update your base URL:

Create a wallet with a server signer

Previously, server-managed signing used the external-wallet type. V1 introduces a dedicated server signer type.
The REST API accepts address (not secret) for server signers. Derive the address from your secret in your backend before passing it to the API.

Submit approvals with a server signer

Use the server:<address> locator format when submitting approvals.

REST ↔ SDK signer type mapping

Use this table to map between REST API signer types and SDK signer config objects.

Checklist

Use this checklist to verify your migration is complete:
  • Updated all @crossmint packages to V1 versions
  • Replaced getOrCreateWallet with createWallet / getWallet
  • (Android) Updated SDK to 1.0.1
  • (Android/iOS) Replaced getOrCreateWallet with createWallet / getWallet, renamed signerrecovery
  • (iOS) Replaced otpAuthentication with sendEmailOtp + confirmEmailOtp
  • (iOS) Updated ApiKeySigner initialization — no longer has a default parameter
  • (iOS) Replaced deprecated Signers enum with EVMSigners / SolanaSigners
  • Updated createOnLogin: signerrecovery, delegatedSignerssigners
  • Replaced experimental_setCustomAuth with setJwt (if using BYOA)
  • Removed all experimental_ prefixes from methods and options
  • Replaced useWalletEmailSigner with useWalletOtpSigner
  • Replaced addDelegatedSigner with addSigner
  • Removed Farcaster / Dynamic login references (if applicable)
  • Updated REST API calls to use server signer type (if applicable)
  • Searched codebase for old terms: adminSigner, getOrCreateWallet, delegatedSigner, experimental_

Next steps

Troubleshooting

Handle WalletNotAvailableError and other common errors

Add a signer

Register operational signers on your wallet