Step-by-step instructions for integrating the Para Flutter SDK into your mobile app.
This guide walks you through the setup of Para in a Flutter application. You’ll learn how to install the SDK, configure iOS/Android for passkey-based logins, implement user authentication flows, and generate wallets.
If you haven’t already created your Flutter app, follow
the official Flutter docs to set up a new project.
Important: You must register your TeamId and BundleId with Para via the Developer Portal to use associated domains. This is required by Apple for passkey security. Allow up to 24 hours for domain propagation.
To enable passkeys on iOS, you need to set up associated domains in your Xcode project:
Open your Flutter project’s iOS folder in Xcode
Select your target and go to “Signing & Capabilities”
Important: You must register your TeamId and BundleId with Para via the Developer Portal to use associated domains. This is required by Apple for passkey security. Allow up to 24 hours for domain propagation.
For Android setup, you need to provide your app’s SHA-256 certificate fingerprint to Para.
Quick Testing Option: You can use com.getpara.example.flutter as your package name for immediate testing. This package name is pre-registered and works with the SHA-256 certificate from the default debug.keystore, making it testable in debug mode for newly scaffolded Flutter apps.
For newer versions of Flutter, you need to add the following configuration block to your android/build.gradle file to resolve a namespace issue with the passkey dependency:
For debug builds: keytool -list -v -keystore ~/.android/debug.keystore
For release builds: keytool -list -v -keystore <your_keystore_path>
For production apps, you’ll need to: 1. Upgrade your plan in the Developer Portal 2. Register your actual package name 3. Provide your app’s SHA-256 fingerprint 4. Wait up to 24 hours for the Digital Asset Links to propagate
To ensure passkey functionality works correctly:
Enable biometric or device unlock settings (fingerprint, face unlock, or PIN)
Sign in to a Google account on the device (required for Google Play Services passkey management)
To use Para’s features, you’ll need to initialize a Para client instance that can be accessed throughout your app. This
client handles all interactions with Para’s services, including authentication, wallet management, and transaction
signing.
Create a file (e.g., lib/services/para_client.dart) to initialize your Para client:
Copy
Ask AI
import 'package:para/para.dart';// Initialize a global Para client instancefinal para = Para( environment: Environment.beta, // Use Environment.prod for production apiKey: 'YOUR_PARA_API_KEY', deepLinkScheme: 'yourapp://callback', // Required for OAuth/WebAuth);
You can access para from anywhere in your app by importing the file where you initialized it. This singleton pattern
ensures consistent state management across your application.
Para offers two hosted environments: Environment.BETA (alias Environment.DEVELOPMENT) for testing, and
Environment.PROD (alias Environment.PRODUCTION) for live use. Select the environment that matches your current
development phase.
The Para SDK v2 provides a unified authentication flow that automatically handles both new and existing users. Here’s how to implement authentication in your Flutter application.
Beta Testing Credentials In the BETA Environment, you can use any email ending in @test.getpara.com (like
dev@test.getpara.com) or US phone numbers (+1) in the format (area code)-555-xxxx (like (425)-555-1234). Any OTP
code will work for verification with these test credentials. These credentials are for beta testing only. You can
delete test users anytime in the beta developer console to free up user slots.
Phone authentication follows the same pattern as email:
Copy
Ask AI
Future<void> authenticateWithPhone(String phoneNumber, String countryCode) async { // Format phone number properly final formattedPhone = para.formatPhoneNumber(phoneNumber, countryCode); // Step 1: Initiate auth flow final authState = await para.signUpOrLogIn( auth: Auth.phone(formattedPhone) ); // Step 2: Handle based on auth stage switch (authState.stage) { case AuthStage.verify: // New user - SMS verification code sent print('SMS code sent to $formattedPhone'); // Show UI to collect verification code break; case AuthStage.login: // Existing user - proceed to login await handlePhoneLogin(authState); break; case AuthStage.signup: // Should not happen directly break; }}Future<void> verifyPhone(String verificationCode) async { // Verify the SMS code final verifiedState = await para.verifyNewAccount( verificationCode: verificationCode ); // After verification, proceed to signup if (verifiedState.stage == AuthStage.signup) { await handlePhoneSignup(verifiedState); }}Future<void> handlePhoneLogin(AuthState authState) async { // Login with passkey - no webAuthSession needed final walletFuture = para.loginWithPasskey( phone: authState.auth.phoneNumber, ); final wallet = await walletFuture.future; // User is now logged in final wallets = await para.fetchWallets();}Future<void> handlePhoneSignup(AuthState authState) async { // For simplified flow, use the auth extension final wallet = await para.handleSignup( authState: authState, method: SignupMethod.passkey, ); print('Wallet created: ${wallet.address}');}
Phone numbers should include the country code (e.g., +1234567890). Use para.formatPhoneNumber() to ensure proper formatting.
Para supports multiple OAuth providers for social login:
Copy
Ask AI
Future<void> loginWithGoogle() async { final webAuthSession = WebAuthenticationSession( prefersEphemeralWebBrowserSession: false, ); // Use unified OAuth flow for v2 final authState = await para.verifyOAuth( provider: OAuthMethod.google, deeplinkUrl: 'yourapp://callback', ); // OAuth handles both new and existing users automatically final isActive = await para.isSessionActive(); if (isActive) { // User is now authenticated final wallets = await para.fetchWallets(); print('OAuth successful, ${wallets.length} wallets available'); }}
Check if a user is logged in and manage their session:
Copy
Ask AI
// Check if session is activeFuture<void> checkSession() async { final isActive = await para.isSessionActive().future; if (isActive) { // User is logged in final wallets = await para.fetchWallets().future; final authDetails = await para.getCurrentUserAuthDetails().future; }}// Export session for backupFuture<void> exportUserSession() async { final sessionData = await para.exportSession().future; // Store sessionData securely}// LogoutFuture<void> logoutUser() async { await para.logout().future;}
Once authenticated, you can access and manage wallets:
Copy
Ask AI
// Get all walletsFuture<void> getUserWallets() async { final wallets = await para.fetchWallets(); for (final wallet in wallets) { print('Type: ${wallet.type}'); // WalletType.evm, .solana, or .cosmos print('Address: ${wallet.address}'); print('Scheme: ${wallet.scheme}'); // WalletScheme.mpc }}// Get specific wallet by filteringFuture<Wallet?> getSpecificWallet(String walletId) async { final walletsFuture = para.fetchWallets(); final wallets = await walletsFuture.future; try { return wallets.firstWhere((w) => w.id == walletId); } catch (e) { return null; // Not found }}// Check if using external walletFuture<void> checkExternalWallet() async { final isExternal = await para.isUsingExternalWallet(); if (isExternal) { print('User is using an external wallet'); }}
Many Para operations return a ParaFuture that can be cancelled:
Copy
Ask AI
// Example with signingfinal signatureFuture = para.signMessage( walletId: wallet.id, messageBase64: base64Encode(utf8.encode('Hello!')),);// Cancel if neededawait para.cancelOperationById(signatureFuture.requestId);// Or await the resulttry { final signature = await signatureFuture.future; print('Signature: ${signature.signature}');} catch (e) { // Handle cancellation or error}
If you encounter issues during the integration or usage of the Para SDK in your Flutter application, here are some common
problems and their solutions:
If you’re having trouble initializing the Para SDK:
Ensure you’re providing the required deepLinkScheme parameter
Verify that you’re using the correct API key and environment
Check that all necessary dependencies are installed properly
Look for any Dart errors in your Flutter debug console
Verify that your Flutter version is compatible with the Para SDK
If passkey creation, retrieval, or usage isn’t working:
Verify that you’ve set up associated domains correctly in your iOS project
For Android, check that you’ve configured your build.gradle file with the namespace fix
Make sure you’ve provided the correct SHA-256 fingerprint to the Para team for Android
Ensure that biometric authentication is enabled on the test device
For Android, confirm the test device has a Google account signed in
Check that WebAuthenticationSession is properly configured
If you’re experiencing authentication issues:
Double-check that your API key is correct and properly set in your Para client initialization
Verify you’re using the correct environment (beta or prod) that matches your API key
Ensure your account has the necessary permissions for the operations you’re attempting
Check that your deep link scheme matches what’s configured in your app
Verify the authentication flow is being followed correctly (verify → signup/login)
If you’re migrating from V1 to V2:
Replace checkIfUserExists() + createUser() with signUpOrLogIn()
Replace verifyEmail() with verifyNewAccount()
Replace login() with loginWithPasskey()
Remove calls to init() - it no longer exists
Add the required deepLinkScheme parameter to the constructor
Update wallet creation to use SignupMethod.passkey or .password