Skip to main content
The Flutter SDK uses ChangeNotifier-based controllers instead of React hooks. Controllers can be used directly (headless) or accessed through the widget tree via providers.

CrossmintClient

The top-level facade for the Crossmint SDK. Provides access to auth, wallets, and all sub-clients.

Properties

config
CrossmintClientConfig
The configuration this client was built with.
auth
CrossmintAuthClient
Authentication sub-client — email OTP, OAuth, wallet sign-in, session persistence, JWT refresh.
wallets
CrossmintWalletsClient
Wallet sub-client — create, list, and read Crossmint-hosted wallets (EVM, Solana, Stellar) and their signers.
credentials
CrossmintCredentialsClient
Verifiable credentials sub-client — issue, query, and verify credentials.
orders
CrossmintOrdersClient
Orders sub-client — checkout orders and mint/purchase flows.
tokens
CrossmintTokensClient
Tokens sub-client — metadata and balances for tokens held by wallets.
users
CrossmintUsersClient
Users sub-client — user profile lookups and updates.
appId
String?
The effective app ID — explicit [CrossmintClientConfig.appId] if set, otherwise the value auto-resolved from platform metadata during [initialize]. May be null until [initialize] has completed.
isInitialized
bool
Whether [initialize] has completed successfully.
isDisposed
bool
Whether [dispose] has been called. Once disposed, the client cannot be reused — construct a new one.
hiddenSignerBridgeController
HiddenSignerBridgeRuntimeController
The shared hidden signer bridge controller, lazily constructed on first access. Powers non-custodial email/phone signing inside a hidden WebView.
authStorage
CrossmintAuthStorage
The auth storage adapter resolved during construction — either the one passed via [CrossmintClientConfig.authStorage] or the default flutter_secure_storage-backed implementation.
transport
CrossmintTransport
The HTTP transport resolved during construction. Shared by every sub-client; injects the live JWT via a closure so token refresh works without rebuilding dependencies.

Methods

createWalletController(config)
CrossmintWalletController
Creates a [CrossmintWalletController] bound to this client.
createHiddenSignerBridge(config)
HiddenSignerBridgeRuntimeController
Builds a new [HiddenSignerBridgeRuntimeController] instance — used internally by [hiddenSignerBridgeController]. Override the bridge config to point at a custom signer URL (e.g. for testing).
createExportSignerBridge(config)
CrossmintExportSignerBridgeRuntimeController
Builds a new [CrossmintExportSignerBridgeRuntimeController] instance. Used internally by [exportSignerBridgeController].
createEvmNonCustodialSigner(bridge, signerType, signerLocator, address, onAuthRequired)
CrossmintEvmNonCustodialSigner
Builds a non-custodial EVM signer bound to an existing [HiddenSignerBridge]. Produces secp256k1 signatures inside the WebView without exposing keys to Dart.
createSolanaNonCustodialSigner(bridge, signerType, signerLocator, address, onAuthRequired)
CrossmintSolanaNonCustodialSigner
Builds a non-custodial Solana signer bound to an existing [HiddenSignerBridge]. Produces ed25519 signatures inside the WebView.
createStellarNonCustodialSigner(bridge, signerType, signerLocator, address, onAuthRequired)
CrossmintStellarNonCustodialSigner
Builds a non-custodial Stellar signer bound to an existing [HiddenSignerBridge]. Produces ed25519 signatures inside the WebView.
createEvmWallet(wallet, recoverySigner, signer, additionalSigners, deviceSignerKeyStorage, onAuthRequired)
CrossmintEvmWallet
Wraps a server-issued [CrossmintWallet] in a runtime [CrossmintEvmWallet].
createSolanaWallet(wallet, recoverySigner, signer, additionalSigners, deviceSignerKeyStorage, onAuthRequired)
CrossmintSolanaWallet
Wraps a server-issued [CrossmintWallet] in a runtime [CrossmintSolanaWallet].
createStellarWallet(wallet, recoverySigner, signer, additionalSigners, deviceSignerKeyStorage, onAuthRequired)
CrossmintStellarWallet
Wraps a server-issued [CrossmintWallet] in a runtime [CrossmintStellarWallet].
createDeviceWalletSigner(signerLocator, address, storage)
CrossmintDeviceWalletSigner
Builds a hardware-backed device signer for an existing server signer.
createEvmExternalWalletSigner(address, signerLocator, onSign)
CrossmintEvmExternalWalletSigner
Builds an external-wallet EVM signer that delegates to a user-supplied [CrossmintExternalWalletSignCallback]. Use for wallets owned by the user (e.g. MetaMask, Rainbow) where the SDK only needs to request signatures.
createSolanaExternalWalletSigner(address, signerLocator, onSign)
CrossmintSolanaExternalWalletSigner
Builds an external-wallet Solana signer that delegates to a user-supplied [CrossmintExternalWalletSignCallback].
createStellarExternalWalletSigner(address, signerLocator, onSign)
CrossmintStellarExternalWalletSigner
Builds an external-wallet Stellar signer that delegates to a user-supplied [CrossmintExternalWalletSignCallback].
createPasskeyApprovalSigner(credentialId, signerLocator, onSign)
CrossmintPasskeyApprovalSigner
Builds a passkey approval signer. The caller provides onSign — a callback that performs the WebAuthn / platform-native passkey assertion and returns a [CrossmintPasskeySignResult]. Native platform passkey support is pending (Stage 2); today every passkey signer requires an explicit callback or CrossmintSignerException(code: passkeyCallbackMissing) is thrown during signing.
dispose()
Future<void>
Releases the signer bridges and auth client, then marks the client as disposed. Safe to call multiple times. After disposal, construct a new [CrossmintClient] rather than reusing this one.
initialize()
Future<void>
Validates configuration and prepares the client for use.

Usage

import 'package:crossmint_flutter/crossmint_client.dart';

final client = CrossmintClient(
  config: CrossmintClientConfig(
    apiKey: 'YOUR_CLIENT_API_KEY',
    appScheme: 'myapp',
  ),
);

await client.initialize();
await client.auth.restoreSession();

CrossmintAuthClient

Manages authentication state and login flows. Exposes state via ValueListenable and Stream for reactive UI updates.

Properties

state
CrossmintAuthState
The current auth state snapshot.
stateListenable
ValueListenable<CrossmintAuthState>
Reactive handle on [state] — suitable for [ValueListenableBuilder].
states
Stream<CrossmintAuthState>
Stream of auth-state changes. Emits on every state mutation.

Methods

restoreSession()
Future<void>
Reads any persisted session from [CrossmintAuthStorage] and applies it to the client. Safe to call once per app launch — prefer using the result of CrossmintClient.initialize which calls this internally.
loginWithOAuth(provider)
Future<void>
Opens the Crossmint-hosted OAuth flow for [provider] (Google, Twitter, etc.). The response comes back through [CrossmintAuthCallbackRouter] — make sure it is started before calling this.
sendEmailOtp(email)
Future<CrossmintEmailOtpChallenge>
Requests the Crossmint API to send an email OTP to [email]. Returns a challenge that [confirmEmailOtp] completes.
confirmEmailOtp(email, emailId, token)
Future<bool>
Submits an email OTP challenge — pass the emailId from the challenge and the token the user entered. Returns true on success.
completeOAuth(callbackUri)
Future<bool>
Completes an OAuth flow from a deep-link callback URI. Normally invoked by [CrossmintAuthCallbackRouter]; call directly only for custom routing.
completeOAuthWithOneTimeSecret(oneTimeSecret)
Future<bool>
Completes an OAuth flow from a one-time secret (SSR / server-mediated callbacks). Returns true on success.
signInWithWallet(address, type)
Future<CrossmintWalletAuthChallenge>
Starts wallet-based authentication. Returns a challenge that the wallet must sign. [type] is 'evm' or 'solana'.
authenticateWallet(address, type, signature)
Future<bool>
Completes wallet-based authentication with the signed challenge.
getSession()
Future<CrossmintAuthSession?>
Returns the current session (JWT + metadata), or null if not signed in. Does not hit the network — reads from in-memory state.
getUser(forceRefresh)
Future<CrossmintAuthenticatedUser?>
Returns the authenticated user’s profile. Caches the result; pass forceRefresh: true to bypass the cache and refetch.
logout()
Future<void>
Signs the user out — clears persisted storage, cached session/user, and POSTs to the Crossmint (or custom) logout endpoint.
setJwt(jwt)
Future<void>
Sets a custom JWT for “Bring Your Own Auth” (BYOA) flows.

Usage

import 'package:crossmint_flutter/crossmint_flutter_auth.dart';

client.auth.stateListenable.addListener(() {
  print('Auth state: ${client.auth.state}');
});

final challenge = await client.auth.sendEmailOtp('YOUR_USER_EMAIL');
await client.auth.confirmEmailOtp(
  email: 'YOUR_USER_EMAIL',
  emailId: challenge.id,
  token: 'YOUR_OTP_CODE',
);

await client.auth.loginWithOAuth(CrossmintOAuthProvider.google);

await client.auth.logout();

CrossmintWalletController

Manages wallet lifecycle — creation, loading, signing, and OTP flows. Extends ChangeNotifier for reactive UI updates.

Properties

client
CrossmintClient
The underlying client — exposed for code that needs direct access to sub-clients (auth, orders, credentials, etc.).
config
CrossmintWalletControllerConfig
The configuration this controller was built with.
otp
CrossmintWalletOtpController
OTP controller for non-custodial email/phone signer challenges.
state
CrossmintWalletStateView
Read-only observation surface for the underlying wallet state. Advanced consumers can subscribe to wallet / status changes directly via this [Listenable] while still routing all mutations through the controller’s public API (getWallet, createWallet, refresh, clear, …).
currentWallet
CrossmintWallet?
The currently-loaded wallet, or null if none is loaded.
status
CrossmintWalletStatus
Current wallet lifecycle status.
onAuthRequired
CrossmintWalletAuthRequiredCallback
The auth-required callback the controller wires into every signer it builds. Exposed so apps building signers manually can share the same OTP-handling path.
pendingOtpChallenge
CrossmintOtpChallenge?
Shortcut to [CrossmintWalletOtpController.pendingChallenge].
otpChallengeListenable
ValueListenable<CrossmintOtpChallenge?>
Shortcut to [CrossmintWalletOtpController.challengeListenable].
requireCurrentWallet
CrossmintWallet
Returns the currently-loaded wallet or throws [CrossmintWalletException] when none is loaded.

Methods

getWallet(request)
Future<CrossmintWallet?>
Looks up an existing wallet and stores the result in controller state. Returns null when no wallet matches. Listeners fire on state changes.
loadWallet(request)
Future<CrossmintWallet?>
Deprecated: use [getWallet] instead.
createWallet(request)
Future<CrossmintWallet>
Creates a new wallet and stores it in controller state. Validates passkey signers up-front via [crossmintValidatePasskeySigners] and fires [CrossmintWalletLifecycleCallbacks.onWalletCreationStart] if set.
ensureLoaded()
Future<CrossmintWallet?>
Ensures a wallet is loaded, creating one if configured to do so.
refresh()
Future<CrossmintWallet?>
Re-fetches the currently-loaded wallet from the API. Returns null when nothing is loaded.
clear()
Future<void>
Drops the loaded wallet and any pending OTP challenge. Call during sign-out.
sendOtp()
Future<void>
Shortcut to [CrossmintWalletOtpController.sendOtp].
verifyOtp(otpCode)
Future<void>
Shortcut to [CrossmintWalletOtpController.verifyOtp].
rejectOtp()
void
Shortcut to [CrossmintWalletOtpController.reject].
createEvmWallet(signer, additionalSigners)
CrossmintEvmWallet
Wraps the currently-loaded wallet as a runtime [CrossmintEvmWallet]. Throws [CrossmintWalletException] if no wallet is loaded.
createSolanaWallet(signer, additionalSigners)
CrossmintSolanaWallet
Wraps the currently-loaded wallet as a runtime [CrossmintSolanaWallet]. On Solana, device signer support depends on the wallet type and is validated server-side. A default device signer is not auto-injected for Solana; it is registered reactively and falls back to the recovery signer when the server rejects it.
createStellarWallet(signer, additionalSigners)
CrossmintStellarWallet
Wraps the currently-loaded wallet as a runtime [CrossmintStellarWallet].
createEvmWalletWithDeviceSigner(signerLocator, address, storage)
CrossmintEvmWallet
Builds a runtime EVM wallet backed by a hardware-backed device signer. Use for low-friction, day-to-day signing with keys in Secure Enclave / Android Keystore.
createEvmWalletWithNonCustodialSigner(signerType, signerLocator, address, bridge)
CrossmintEvmWallet
Builds a runtime EVM wallet backed by a non-custodial email/phone signer. Requires [CrossmintWalletHost] (or CrossmintWalletProvider) mounted in the widget tree.
createSolanaWalletWithNonCustodialSigner(signerType, signerLocator, address, bridge)
CrossmintSolanaWallet
Builds a runtime Solana wallet backed by a non-custodial email/phone signer. Requires a mounted wallet host.
createStellarWalletWithNonCustodialSigner(signerType, signerLocator, address, bridge)
CrossmintStellarWallet
Builds a runtime Stellar wallet backed by a non-custodial email/phone signer. Requires a mounted wallet host.
createStellarWalletWithDeviceSigner(signerLocator, address, storage)
CrossmintStellarWallet
Builds a runtime Stellar wallet backed by a hardware device signer.
createEvmWalletWithExternalWalletSigner(address, signerLocator, onSign)
CrossmintEvmWallet
Builds a runtime EVM wallet backed by a user-owned external wallet (e.g. MetaMask). The caller supplies [onSign] to perform signatures.
createSolanaWalletWithExternalWalletSigner(address, signerLocator, onSign)
CrossmintSolanaWallet
Builds a runtime Solana wallet backed by a user-owned external wallet.
createStellarWalletWithExternalWalletSigner(address, signerLocator, onSign)
CrossmintStellarWallet
Builds a runtime Stellar wallet backed by a user-owned external wallet.
createEvmWalletWithPasskeySigner(id, onSign)
CrossmintEvmWallet
Builds a runtime EVM wallet backed by a passkey signer.
createSolanaWalletWithPasskeySigner(id, onSign)
CrossmintSolanaWallet
Builds a runtime Solana wallet backed by a passkey signer. See [createEvmWalletWithPasskeySigner] for passkey selection semantics.
createStellarWalletWithPasskeySigner(id, onSign)
CrossmintStellarWallet
Builds a runtime Stellar wallet backed by a passkey signer. See [createEvmWalletWithPasskeySigner] for passkey selection semantics.
dispose()
void
The controller also provides chain-specific convenience factories that build the signer for you: createEvmWalletWithDeviceSigner, createEvmWalletWithPasskeySigner, createEvmWalletWithExternalWalletSigner, createEvmWalletWithNonCustodialSigner, and their Solana / Stellar counterparts.

Usage

import 'package:crossmint_flutter/crossmint_flutter_controllers.dart';

final controller = client.createWalletController(
  CrossmintWalletControllerConfig(
    createOnLogin: CrossmintCreateOnLoginConfig(
      chain: 'base-sepolia',
      recovery: const CrossmintEmailSignerConfig(),
    ),
  ),
);

// Listen to status changes
controller.addListener(() {
  print('Status: ${controller.status}');
  final wallet = controller.currentWallet;
  if (wallet != null) {
    print('Address: ${wallet.address}');
  }
});

// Manual OTP handling
controller.otp.challengeListenable.addListener(() {
  final challenge = controller.otp.challengeListenable.value;
  if (challenge != null) {
    // Show your own OTP prompt UI
    // Then call: controller.otp.verifyOtp('123456');
  }
});

CrossmintWallets

Stateless convenience facade for wallet operations. Mirrors the CrossmintWallets entry point used by the TS, Kotlin, and Swift SDKs. For reactive state management (e.g. listening to wallet changes in a widget tree), use CrossmintWalletController instead. Unlike the controller, the facade does not auto-resolve signer configs. Callers must provide fully-resolved configs (e.g. include the email address in CrossmintEmailSignerConfig, or pre-create a device signer via createDeviceSigner()).

Constructor

CrossmintWallets.from()
CrossmintWallets
Creates a CrossmintWallets facade backed by client.

Methods

getWallet(chain, alias, plugins, recoverySigner)
Future<CrossmintRuntimeWalletBase>
Retrieves an existing wallet and returns a typed runtime wallet.
createWallet(chain, recovery, signers, owner, alias, plugins)
Future<CrossmintRuntimeWalletBase>
Creates a new wallet and returns a typed runtime wallet.
createDeviceSigner(storage, address)
Future<CrossmintDeviceSignerDescriptor>
Creates a device signer descriptor.
createPasskeySigner(name, config)
Future<CrossmintPasskeySignerConfig>
Creates a passkey signer configuration.

Usage

import 'package:crossmint_flutter/crossmint_flutter_wallets.dart';

final wallets = CrossmintWallets.from(
  client,
  onAuthRequired: (challenge) {
    // Show your OTP prompt UI, then call challenge.verify(code)
  },
);

// Get an existing wallet
final wallet = await wallets.getWallet(chain: 'base-sepolia');
print('Address: ${wallet.address}');

// Create a new wallet
final newWallet = await wallets.createWallet(
  chain: 'base-sepolia',
  recovery: CrossmintEmailSignerConfig(email: 'YOUR_USER_EMAIL'),
);

// Send tokens
final tx = await newWallet.sendToken('RECIPIENT_WALLET_ADDRESS', 'usdc', '10');

Wallet Methods

The runtime wallet instances returned by the controller provide methods for token transfers, balances, signing, and more.

Properties

PropertyTypeDescription
wallet.clientCrossmintClientTop-level Crossmint client shared by all wallet operations.
wallet.walletCrossmintWalletServer-issued wallet snapshot backing this runtime instance.
wallet.deviceSignerKeyStorageDeviceSignerKeyStorage?Storage backend for hardware-backed device signer keys.
wallet.onAuthRequiredCrossmintSignerAuthRequiredCallback?Callback invoked when a signer operation requires user authentication.
wallet.defaultChainStringChain identifier used when the wallet snapshot has no explicit chain.
wallet.chainStringBlockchain this wallet operates on (falls back to [defaultChain]).
wallet.addressStringOn-chain address of the wallet.
wallet.ownerString?Owner identifier associated with the wallet, if any.
wallet.recoveryCrossmintSignerConfig?Recovery (admin) signer config parsed from the wallet’s backend state.
wallet.locatorStringUnique wallet locator used for API calls.
wallet.signerCrossmintWalletApprovalSigner?Currently active approval signer, or null if none is selected.
wallet.additionalSignersList<CrossmintWalletApprovalSigner>Secondary signers available alongside the primary [signer].
wallet.needsRecoveryboolWhether the wallet needs recovery (signer registration) before the next transaction.
wallet.canExportPrivateKeyboolWhether the active signer supports private-key export.

Methods

MethodDescription
wallet.useSigner(signer)Sets the active signer for this wallet. Accepts a signer config object; the locator is inferred internally. Works for device, non-custodial, external-wallet, and passkey signers.
wallet.balances(tokens)Returns the wallet balances — always includes USDC and the native token. Pass additional [tokens] to request extra token balances.
wallet.transactions()Lists transaction summaries for this wallet.
wallet.transaction(transactionId)Retrieves details for a specific transaction by ID.
wallet.approve(request)Approves a pending transaction or signature request.
wallet.nfts(page, perPage)Returns the wallet’s NFTs (paginated).
wallet.fund(request)Initiates a funding (on-ramp) request for this wallet.
wallet.transfers(page, perPage, tokens, status)Reads transfer history for this wallet (unstable API).
wallet.send(request)Sends a token transfer and waits for confirmation.
wallet.sendToken(to, token, amount)Convenience wrapper around [send] for simple token transfers.
wallet.signers()Lists all signers registered on this wallet with their current status.
wallet.removeSigner(signerLocator)Removes a signer from the wallet by its locator.
wallet.signerIsRegistered(signerLocator)Checks whether a signer with the given locator is registered.
wallet.isSignerApproved(signerLocator)Checks whether a registered signer is approved and usable.
wallet.addSigner(signer)Registers a new signer on the wallet and approves the registration.
wallet.preAuthIfNeeded()Awaits any in-flight recovery; if _needsRecovery is set and no recovery is in-flight, starts one and awaits it. Concurrent callers coalesce onto the same future so a single recovery runs per wallet.
wallet.recover()Runs device-signer recovery: resumes any pending operation or registers a new device signer using the recovery signer. Returns early if the device signer is already approved on-chain.
wallet.exportPrivateKey(bridge)Exports the wallet’s private key via the export signer bridge.
wallet.approveTransactionAndWait(transactionId)Approves a pending transaction and polls until it reaches a terminal state.
wallet.transactionApprovalPayload(transaction, pendingApproval, signer)Extracts the signable payload from a pending transaction approval.
wallet.completeApprovedTransaction(transaction)Polls a transaction until it reaches a terminal state and attaches explorer links.
wallet.waitForTransaction(transactionId)Polls a transaction by ID until it succeeds or fails.
wallet.walletSnapshotForSigners()Fetches a fresh wallet snapshot to inspect registered signers.
wallet.requireActiveSigner(operation)Returns the active signer or throws if none is selected.
Chain-specific methods:
  • CrossmintEvmWalletsendTransaction(), signMessage(), signTypedData()
  • CrossmintSolanaWalletsendTransaction()
  • CrossmintStellarWalletsendTransaction()

Usage

controller.currentWallet holds the loaded domain model. Signing, balance, and transaction methods live on the runtime wallet returned by controller.createEvmWallet() (or createSolanaWallet / createStellarWallet).
if (controller.currentWallet == null) return;

final wallet = controller.createEvmWallet();

final balances = await wallet.balances(tokens: <String>['usdc']);
print('USDC: ${balances.usdc.amount}');
print('Native: ${balances.nativeToken.amount}');

final tx = await wallet.sendToken('RECIPIENT_WALLET_ADDRESS', 'usdc', '10');
print('Transaction: ${tx.id}');

final signature = await wallet.signMessage('Hello, Web3!');
print('Signature: $signature');