> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Setup

> Step-by-step guide for integrating the Para Flutter SDK into your mobile application

export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
  const [isHovered, setIsHovered] = useState(false);
  const handleClick = e => {
    e.preventDefault();
    if (newTab) {
      window.open(href, '_blank', 'noopener,noreferrer');
    } else {
      window.location.href = href;
    }
  };
  return <div className={`not-prose relative my-2 p-[1px] rounded-xl transition-all duration-300 ${isHovered ? 'bg-gradient-to-r from-[#FF4E00] to-[#874AE3]' : 'bg-gray-200'}`} onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
      <a href={href} onClick={handleClick} className={`not-prose flex ${horizontal ? 'flex-row' : 'flex-col'} font-normal h-full bg-white overflow-hidden w-full cursor-pointer rounded-[11px] no-underline`}>
        {imgUrl && <div className={`relative overflow-hidden flex-shrink-0 ${horizontal ? 'w-[30%] rounded-l-[11px]' : 'w-full'}`} onClick={e => e.stopPropagation()}>
            <img src={imgUrl} alt={title} className="w-full h-full object-cover pointer-events-none select-none" draggable="false" />
            <div className="absolute inset-0 pointer-events-none" />
          </div>}
        <div className={`flex-grow px-6 py-5 ${horizontal ? 'w-[70%]' : 'w-full'} flex flex-col ${horizontal && imgUrl ? 'justify-center' : 'justify-start'}`}>
          {title && <h2 className="font-semibold text-base text-gray-800 m-0">{title}</h2>}
          {description && <div className={`font-normal text-gray-500 re leading-6 ${horizontal || !imgUrl ? 'mt-0' : 'mt-1'}`}>
              <p className="m-0 text-xs">{description}</p>
            </div>}
        </div>
      </a>
    </div>;
};

export const DemoCallout = ({variant = "card", title = "Interactive Demo", description = "Try the live demo to explore authentication flows and customize your modal before integrating."}) => {
  if (variant === "subtle") {
    return <div className="not-prose my-4 px-4 py-3 rounded-xl border border-orange-200 bg-orange-50/50">
        <div className="flex items-center justify-between gap-4">
          <p className="text-sm text-gray-700 m-0">
            {description}
          </p>
          <a href="https://demo.getpara.com/" target="_blank" rel="noopener noreferrer" className="not-prose flex-shrink-0 inline-flex items-center gap-2 px-3 py-1.5 text-xs font-semibold text-orange-600 bg-white border border-orange-200 rounded-lg hover:bg-orange-50 transition-colors no-underline">
            Try Demo
            <svg width="12" height="12" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
              <path d="M40 472L472 40M472 40H83.2M472 40V428.8" stroke="currentColor" strokeWidth="66.6667" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </a>
        </div>
      </div>;
  }
  return <a href="https://demo.getpara.com/" target="_blank" rel="noopener noreferrer" className="not-prose block my-4 p-5 rounded-xl bg-gradient-to-r from-orange-600 via-pink-600 to-purple-600 hover:opacity-95 transition-opacity no-underline">
      <div className="flex items-center justify-between gap-4">
        <div>
          <h3 className="text-base font-semibold text-white m-0">{title}</h3>
          <p className="text-xs text-white/80 mt-1 m-0">{description}</p>
        </div>
        <div className="flex-shrink-0 w-8 h-8 rounded-full bg-white/20 flex items-center justify-center">
          <svg width="14" height="14" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path d="M40 472L472 40M472 40H83.2M472 40V428.8" stroke="white" strokeWidth="66.6667" strokeLinecap="round" strokeLinejoin="round" />
          </svg>
        </div>
      </div>
    </a>;
};

export const Link = ({href, label, newTab = false}) => {
  const [isHovered, setIsHovered] = useState(false);
  return <a href={href} target={newTab ? '_blank' : '_self'} rel={newTab ? 'noopener noreferrer' : undefined} className="not-prose inline-block relative text-black font-semibold cursor-pointer border-b-0 no-underline" onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
      {label}
      <span className={`absolute left-0 bottom-0 w-full rounded-sm bg-gradient-to-r from-orange-600 to-purple-600 transition-all duration-300 ${isHovered ? 'h-0.5' : 'h-px'}`} />
    </a>;
};

The Para Flutter SDK enables you to integrate secure wallet features including creation, passkey-based authentication, and transaction signing into your mobile applications. This guide covers all necessary steps from installation to implementing authentication flows.

## Prerequisites

To use Para, you need an API key. This key authenticates your requests to Para services and is essential for
integration.

<Warning>
  Don't have an API key yet? Request access to the <Link label="Developer Portal" href="https://developer.getpara.com" /> to create API keys, manage billing, teams, and more.
</Warning>

<DemoCallout variant="subtle" />

## Install the SDK

Start by installing the Para SDK:

```bash theme={null}
flutter pub add para
```

## Configure URL Scheme

Configure your app's URL scheme for OAuth authentication flows. This enables OAuth providers to redirect back to your app after authentication.

<Tabs>
  <Tab title="iOS">
    1. In Xcode, select your project in the navigator
    2. Select your app target
    3. Go to the **Info** tab
    4. Scroll down to **URL Types** and click **+** to add a new URL type
    5. Fill in the fields:
       * **URL Schemes**: Enter your scheme name (e.g., `yourapp`, `myflutterapp`)
       * **Role**: Select **Editor**
       * **Identifier**: Use your bundle identifier or a descriptive name

    <Warning>
      Make sure your URL scheme is unique to avoid conflicts with other apps. Use a scheme related to your app's bundle ID (e.g., `com.mycompany.myapp`) for uniqueness.
    </Warning>
  </Tab>

  <Tab title="Android">
    Configure URL scheme handling in your `android/app/src/main/AndroidManifest.xml` file:

    1. Locate your MainActivity in the AndroidManifest.xml
    2. Update your MainActivity with the complete configuration below:

    ```xml theme={null}
    <activity
        android:name=".MainActivity"
        android:exported="true"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme"
        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
        android:hardwareAccelerated="true"
        android:windowSoftInputMode="adjustResize">

        <!-- Standard launcher intent -->
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>

        <!-- Custom scheme deep links -->
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="yourapp" />
        </intent-filter>

    </activity>

    <!-- Required for OAuth authentication flows -->
    <activity
        android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
        android:exported="true">
        <intent-filter android:label="flutter_web_auth_2">
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="yourapp" />
        </intent-filter>
    </activity>
    ```

    <Warning>
      **Android 12+ Requirement:** The `android:exported="true"` attribute is mandatory for apps targeting Android 12 (API 31) and higher when the activity has intent filters.
    </Warning>

    <Note>
      Replace `yourapp` with your actual app scheme. This scheme must match the `appScheme` parameter used in Para initialization. The `android:launchMode="singleTop"` prevents multiple instances of your app from being created when deep links are opened.
    </Note>
  </Tab>
</Tabs>

## Optional: Configure Passkeys

Enable passkeys only if you’ve turned them on in the Para Developer Portal. Configure both iOS and Android platforms:

<Tabs>
  <Tab title="iOS">
    To enable passkeys on iOS, you need to configure Associated Domains:

    1. Open your Flutter project's iOS folder in Xcode
    2. In Xcode, go to **Signing & Capabilities** for your app target
    3. Click **+ Capability** and add **Associated Domains**
    4. Add the following entries:
       ```
       webcredentials:app.usecapsule.com
       webcredentials:app.beta.usecapsule.com
       ```
    5. Register your Team ID + Bundle ID with Para via the <Link label="Developer Portal" href="https://developer.getpara.com" />

    <Warning>
      Without properly registering your Team ID and Bundle ID with Para, passkey authentication flows will fail. Contact Para support if you encounter issues with passkey registration.
    </Warning>

    <Note>
      Prepping for review? See <Link label="iOS App Store Submission" href="/v3/general/ios-app-store-submission" /> for Sign in with Apple and reviewer guidance.
    </Note>
  </Tab>

  <Tab title="Android">
    ### Get SHA-256 Fingerprint

    To get your SHA-256 fingerprint:

    * For debug builds: `keytool -list -v -keystore ~/.android/debug.keystore`
    * For release builds: `keytool -list -v -keystore <your_keystore_path>`

    Register your package name and SHA-256 fingerprint with Para via the <Link label="Developer Portal" href="https://developer.getpara.com" />

    <Warning>
      Without properly registering your package name and SHA-256 fingerprint with Para, passkey authentication flows will fail. Contact Para support if you encounter issues with passkey registration.
    </Warning>

    <Info>**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.</Info>

    ### Fix Namespace Issue

    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:

    ```gradle theme={null}
    subprojects {
        afterEvaluate { project ->
            if (project.hasProperty('android')) {
                project.android {
                    if (namespace == null) {
                        namespace project.group
                    }
                }
            }
        }
    }
    ```

    ### Device Requirements

    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)
  </Tab>
</Tabs>

## Initialize Para

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:

```dart lib/services/para_client.dart theme={null}
import 'package:para/para.dart';

// Para Configuration
final config = ParaConfig(
  apiKey: 'YOUR_PARA_API_KEY', // Get from: https://developer.getpara.com
  environment: Environment.beta, // Use Environment.prod for production
);

// Initialize Para client instance
final para = Para.fromConfig(
  config: config,
  appScheme: 'yourapp', // Your app's scheme (without ://)
);
```

<Tip>
  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.
</Tip>

## Authenticate Users

Para provides a unified authentication experience that supports email, phone, and social login methods. The SDK automatically determines whether a user is new or existing and guides you through the appropriate flow.

<Note>
  **Beta Testing Credentials** In the `BETA` Environment, you can use any email ending in `@test.getpara.com` (like
  [dev@test.getpara.com](mailto: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.
</Note>

Create a single `FlutterWebAuthSession` and reuse it whenever you call `handleLogin` or `handleSignup`.

```dart lib/views/authentication_view.dart theme={null}
final webAuthSession = FlutterWebAuthSession(
  callbackUrlScheme: 'yourapp',
);
```

### Build Your Authentication Flow

Para’s One-Click Login is the default path. As soon as you receive an `AuthState`, check for `loginUrl` and complete the inline flow before falling back to other methods. The pattern below mirrors the example app while keeping the logic compact.

<Tabs>
  <Tab title="Email/Phone Authentication">
    Para supports authentication with both email addresses and phone numbers.

    <Steps>
      <Step title="Handle Email/Phone Submission">
        Initiate authentication with email or phone:

        ```dart lib/views/authentication_view.dart theme={null}
        // Determine if input is email or phone
        final Auth auth;
        if (userInput.contains('@')) {
          auth = Auth.email(userInput);
        } else {
          auth = Auth.phone(userInput); // Include country code
        }

        // SDK call: Initiate authentication
        final authState = await para.initiateAuthFlow(auth: auth);

        // One-Click login or signup
        if (authState.loginUrl?.isNotEmpty == true) {
          await para.presentAuthUrl(
            url: authState.loginUrl!,
            webAuthenticationSession: webAuthSession,
          );

          final nextStage = authState.effectiveNextStage;
          if (nextStage == AuthStage.signup) {
            await para.waitForSignup();
          } else {
            await para.waitForLogin();
          }

          await para.touchSession();
          await para.fetchWallets();
          return;
        }

        // Handle the result based on stage (only needed for passkey/password flows)
        switch (authState.stage) {
          case AuthStage.verify:
            // New user - show verification UI (see optional passkey/password section)
            break;
        case AuthStage.login:
          // Existing user - fall back to passkey/password flows
          await para.handleLogin(
            authState: authState,
            webAuthenticationSession: webAuthSession,
          );
          break;
        case AuthStage.signup:
          // Complete signup with passkey/password if you enable them
          break;
        }
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Social Login">
    Social login is integrated directly into the unified authentication view. Users can authenticate with Google, Apple, or Discord.

    <Steps>
      <Step title="Handle Social Login">
        Implement the social login handler:

        ```dart lib/views/authentication_view.dart theme={null}
        Future<void> handleSocialLogin(OAuthMethod provider) async {
          try {
            final authState = await para.verifyOAuth(
              provider: provider,
              appScheme: 'yourapp',
            );

            if (authState.loginUrl?.isNotEmpty == true) {
              await para.presentAuthUrl(
                url: authState.loginUrl!,
                webAuthenticationSession: webAuthSession,
              );

              final nextStage = authState.effectiveNextStage;
              if (nextStage == AuthStage.signup) {
                await para.waitForSignup();
              } else {
                await para.waitForLogin();
              }
              await para.touchSession();
              await para.fetchWallets();
              return;
            }

            if (authState.stage == AuthStage.login) {
              try {
                await para.touchSession();
              } catch (_) {
                // Session refresh is best-effort
              }
              await para.fetchWallets();
              // Navigate to main app
              return;
            }
          } catch (e) {
            // Handle error
            print('OAuth login failed: ${e.toString()}');
          }
        }
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

### Optional: Passkey/Password Signup

If you enable passkeys or passwords in the Para dashboard, you’ll need to handle the verification stage and call `handleSignup`.

```dart lib/views/authentication_view.dart theme={null}
final verifiedState = await para.verifyOtp(otp: userCode);

// Reuse the One-Click block shown above here, then fall back to handleSignup.
await para.handleSignup(
  authState: verifiedState,
  signupMethod: SignupMethod.passkey, // or SignupMethod.password
  webAuthenticationSession: webAuthSession,
);
```

## Returning Users

Existing users follow the same One-Click-first flow. If you’ve enabled passkey or password methods, fall back to `handleLogin`
after the One-Click block. You can also call `loginWithPasskey` directly when you know a user has registered one.

## Check Authentication Status

You can check if a user is already authenticated:

```dart lib/views/content_view.dart theme={null}
final isLoggedIn = await para.isSessionActive().future;

if (isLoggedIn) {
  // User is authenticated, proceed to main app flow
} else {
  // Show login/signup UI
}
```

## Sign Out Users

To sign out a user and clear their session:

```dart lib/views/settings_view.dart theme={null}
await para.logout().future;
```

## Create and Manage Wallets

After successful authentication, you can perform wallet operations:

```dart lib/views/wallet_view.dart theme={null}
// Get all user wallets
await para.fetchWallets(); // Ensure we have the latest wallets

final wallets = await para.fetchWallets().future;

if (wallets.isEmpty) {
  // No wallets, perhaps create one
  final wallet = await para.createWallet(
    type: WalletType.evm,
    skipDistribute: false,
  ).future;

  print('Created wallet: ${wallet.address}');

  // Sign a simple message (SDK handles Base64 encoding internally)
final signature = await para.signMessage(
  walletId: wallet.id,
  messageBase64: base64Encode(utf8.encode('Hello, Para!')),
);
print('Signature: ${(signature as SuccessfulSignatureResult).signedTransaction}');

} else {
  // Use existing wallet
  final firstWallet = wallets.first;

  // Sign a simple message (SDK handles Base64 encoding internally)
final signature = await para.signMessage(
  walletId: firstWallet.id,
  messageBase64: base64Encode(utf8.encode('Hello, Para!')),
);
print('Signature: ${(signature as SuccessfulSignatureResult).signedTransaction}');
}
```

<Note>
  For transaction signing by chain, use the EVM, Solana, Cosmos, and Stellar guides.
</Note>

## Example

For a complete implementation example, check out our Flutter SDK example app:

<Card horizontal title="Flutter SDK Example App" imgUrl="/images/v3/framework-flutter.png" href="https://github.com/getpara/examples-hub/tree/3.0.0/mobile/with-flutter" description="See an end-to-end example of Para Flutter SDK integration." />

## Next Steps

After setup, use these guides for wallet signing flows.

<CardGroup cols={3}>
  <Card title="EVM Integration" imgUrl="/images/v3/network-evm.png" href="/v3/flutter/guides/evm" description="Sign EVM transactions with Para SDK" />

  <Card title="Solana Integration" imgUrl="/images/v3/network-solana.png" href="/v3/flutter/guides/solana" description="Sign Solana transactions with Para SDK" />

  <Card title="Cosmos Integration" imgUrl="/images/v3/network-cosmos.png" href="/v3/flutter/guides/cosmos" description="Sign Cosmos transactions with Para SDK" />

  <Card title="Stellar Integration" imgUrl="/images/v3/network-stellar.png" href="/v3/flutter/guides/stellar" description="Sign Stellar transactions with Para SDK" />
</CardGroup>
