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

# Kotlin Quickstart

> Install the Dynamic Kotlin SDK on Android with AARs, initialize it in Compose, and sign users in with the built-in UI.

<Tip>
  **📱 Complete Example App**: For a fully functional Android app demonstrating all SDK
  features, check out our [Android SDK Example App](https://github.com/dynamic-labs/android-sdk-and-sample-app/tree/main/ExampleApp/DynamicSDKExample). It
  includes authentication flows (email/SMS OTP, social login, passkeys), wallet management, EVM/Solana transactions,
  MFA, and passkey examples with Jetpack Compose.
</Tip>

<Tabs>
  <Tab title="Agent-friendly">
    <Tip>
      Add the Dynamic docs MCP to your AI editor first — your agent can then query the docs directly. Instructions are on the [Welcome page](/docs/overview/introduction/welcome).
    </Tip>

    Copy this prompt into your LLM (e.g. Claude, ChatGPT, Cursor) to implement Dynamic in your Android app with Kotlin.

    <div data-llm-quickstart>
      ````markdown theme={"system"}
      # Kotlin SDK Quickstart

      ## Purpose and Usage

      This document provides structured quickstart information for the Dynamic Kotlin SDK (Android). It is designed to be consumed by LLMs to generate accurate installation commands and code examples based on user requirements.

      > **Important scope note:** The Dynamic Kotlin SDK is for **Android native apps** using Jetpack Compose. It provides embedded wallets, authentication (email OTP, SMS OTP, social login, passkeys), and multi-chain support (EVM + Solana). It uses AAR files — there is no Maven Central publication yet.

      ---

      ## How to use this document

      Start by asking the user which path they want:

      > "Would you like a **Quick start** (EVM only, Jetpack Compose, zero configuration — recommended if you're just getting started) or a **Custom setup** (choose your chains and configuration)?"

      - If the user chooses **Quick start**: follow the Quick Start Path section exactly. Do not ask any configuration questions — execute the happy path as written.
      - If the user chooses **Custom setup**: follow the Custom Setup Path section and ask all configuration questions before proceeding.

      ---

      ## Quick Start Path

      > Use this path when the user chooses Quick start. Execute every step in order. Do not skip steps. Do not ask configuration questions.

      **Stack:** Kotlin + Jetpack Compose + EVM only

      ### Step 1 — Prerequisites

      Tell the user:
      - Android SDK 28+ (Android 9.0+) is required
      - Kotlin 2.1.0+ is required
      - Gradle 8.x+ is required
      - Java 17 is required
      - A Dynamic environment ID is required — get it at https://app.dynamic.xyz/dashboard/overview

      Ask the user for their environment ID before proceeding.

      ### Step 2 — Download AAR files

      Download the latest AAR files from https://github.com/dynamic-labs/android-sdk-and-sample-app:

      - `dynamic-sdk-android.aar` (required)

      Place it in `app/libs/`.

      ### Step 3 — Add dependencies

      Add to `build.gradle.kts`:

      ```kotlin
      dependencies {
          // Dynamic SDK AAR
          implementation(files("libs/dynamic-sdk-android.aar"))

          // Required transitive dependencies
          implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
          implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
          implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
          implementation("androidx.webkit:webkit:1.8.0")
          implementation("com.squareup.okhttp3:okhttp:4.12.0")
          implementation("androidx.browser:browser:1.7.0")
          implementation("androidx.datastore:datastore-preferences:1.1.1")
          implementation("com.google.crypto.tink:tink-android:1.15.0")
          implementation("androidx.credentials:credentials:1.2.2")
          implementation("androidx.credentials:credentials-play-services-auth:1.2.2")
          implementation("com.google.android.gms:play-services-auth:20.7.0")
          implementation(platform("androidx.compose:compose-bom:2024.09.00"))
          implementation("androidx.compose.ui:ui")
          implementation("androidx.compose.foundation:foundation")
          implementation("androidx.compose.runtime:runtime")
          implementation("androidx.lifecycle:lifecycle-runtime-compose:2.6.2")
      }
      ```

      ### Step 4 — Configure AndroidManifest.xml

      ```xml
      <manifest xmlns:android="http://schemas.android.com/apk/res/android">
          <uses-permission android:name="android.permission.INTERNET" />
          <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

          <application android:usesCleartextTraffic="true" ...>
              <activity
                  android:name=".MainActivity"
                  android:exported="true"
                  android:launchMode="singleTask">
                  <intent-filter>
                      <action android:name="android.intent.action.MAIN" />
                      <category android:name="android.intent.category.LAUNCHER" />
                  </intent-filter>
              </activity>

              <!-- OAuth Callback Activity (Required) -->
              <activity
                  android:name="com.dynamic.sdk.android.Auth.AuthCallbackActivity"
                  android:exported="true"
                  android:launchMode="singleTop"
                  android:noHistory="true"
                  android:theme="@android:style/Theme.Translucent.NoTitleBar">
                  <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="yourappscheme" />
                  </intent-filter>
              </activity>
          </application>
      </manifest>
      ```

      > The `android:scheme` must match the `redirectUrl` in `ClientProps`. For example, if `redirectUrl = "myapp://"`, use `android:scheme="myapp"`.

      ### Step 5 — Initialize the SDK

      ```kotlin
      import android.os.Bundle
      import androidx.activity.ComponentActivity
      import androidx.activity.compose.setContent
      import androidx.compose.foundation.layout.*
      import androidx.compose.material3.*
      import androidx.compose.ui.Modifier
      import com.dynamic.sdk.android.DynamicSDK
      import com.dynamic.sdk.android.UI.DynamicUI
      import com.dynamic.sdk.android.core.ClientProps
      import com.dynamic.sdk.android.core.LoggerLevel

      class MainActivity : ComponentActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)

              val props = ClientProps(
                  environmentId = "your-environment-id",
                  appLogoUrl = "https://your-app.com/logo.png",
                  appName = "Your App Name",
                  redirectUrl = "yourappscheme://",
                  appOrigin = "https://your-app.com",
                  logLevel = LoggerLevel.DEBUG
              )
              DynamicSDK.initialize(props, applicationContext, this)

              setContent {
                  MaterialTheme {
                      Surface(
                          modifier = Modifier.fillMaxSize(),
                          color = MaterialTheme.colorScheme.background
                      ) {
                          Box(modifier = Modifier.fillMaxSize()) {
                              AppContent()
                              DynamicUI() // Required overlay for auth flows
                          }
                      }
                  }
              }
          }
      }
      ```

      ### Step 6 — Show the auth UI

      ```kotlin
      import androidx.compose.material3.*
      import androidx.compose.runtime.*
      import com.dynamic.sdk.android.DynamicSDK

      @Composable
      fun LoginScreen() {
          val sdk = DynamicSDK.getInstance()
          Button(onClick = { sdk.ui.showAuth() }) {
              Text("Sign In")
          }
      }
      ```

      ### Step 7 — Listen for auth state changes

      ```kotlin
      import androidx.lifecycle.ViewModel
      import androidx.lifecycle.viewModelScope
      import com.dynamic.sdk.android.DynamicSDK
      import com.dynamic.sdk.android.Models.UserProfile
      import kotlinx.coroutines.flow.MutableStateFlow
      import kotlinx.coroutines.flow.StateFlow
      import kotlinx.coroutines.launch

      class AuthViewModel : ViewModel() {
          private val sdk = DynamicSDK.getInstance()

          private val _user = MutableStateFlow<UserProfile?>(null)
          val user: StateFlow<UserProfile?> = _user

          private val _isAuthenticated = MutableStateFlow(false)
          val isAuthenticated: StateFlow<Boolean> = _isAuthenticated

          init {
              _isAuthenticated.value = sdk.auth.isAuthenticated()
              _user.value = sdk.auth.authenticatedUser

              viewModelScope.launch {
                  sdk.auth.authenticatedUserChanges.collect { user ->
                      _user.value = user
                      _isAuthenticated.value = user != null
                  }
              }
          }
      }
      ```

      ### Step 8 — Enable features in dashboard

      Tell the user:
      1. Go to https://app.dynamic.xyz/dashboard/overview
      2. Go to **Authentication** and enable Email OTP
      3. Go to **Wallets** and enable embedded wallets
      4. Go to **Chains** and enable an EVM testnet (e.g. Base Sepolia)

      ---

      ## Custom Setup Path

      > Use this path when the user chooses Custom setup. Ask ALL questions below before generating any code.

      **Questions to ask the user:**
      1. Which chains do you need? (EVM only / EVM + Solana)
      2. What is your app's URL scheme for OAuth callbacks? (e.g. `myapp://`)
      3. What authentication methods do you want? (Email OTP, SMS OTP, Social login, Passkeys)
      4. Do you need WalletConnect support for connecting to dApps?

      ### Configuration differences

      **Solana support:** Add these extra dependencies:

      ```kotlin
      implementation(files("libs/solana-web3.aar"))
      implementation("org.sol4k:sol4k:0.6.0")
      ```

      **WalletConnect support:** Add `reownProjectId` to `ClientProps`:

      ```kotlin
      val props = ClientProps(
          environmentId = "your-environment-id",
          appLogoUrl = "https://your-app.com/logo.png",
          appName = "Your App Name",
          redirectUrl = "yourappscheme://",
          appOrigin = "https://your-app.com",
          reownProjectId = "your-reown-project-id"
      )
      ```

      ### SDK Access (after initialization)

      ```kotlin
      val sdk = DynamicSDK.getInstance()

      // Auth
      sdk.ui.showAuth()
      sdk.auth.isAuthenticated()
      sdk.auth.authenticatedUser

      // Wallets
      sdk.wallets.userWallets
      sdk.wallets.primaryWallet

      // User profile
      sdk.ui.showUserProfile()

      // Logout
      sdk.auth.logout() // suspend function — call from a coroutine
      ```

      ### Wallet display example

      ```kotlin
      import com.dynamic.sdk.android.Models.BaseWallet
      import kotlinx.coroutines.flow.MutableStateFlow

      class HomeViewModel : ViewModel() {
          private val sdk = DynamicSDK.getInstance()
          private val _wallets = MutableStateFlow<List<BaseWallet>>(emptyList())
          val wallets: StateFlow<List<BaseWallet>> = _wallets

          init {
              _wallets.value = sdk.wallets.userWallets
              viewModelScope.launch {
                  sdk.wallets.userWalletsChanges.collect { newWallets ->
                      _wallets.value = newWallets
                  }
              }
          }
      }
      ```

      ---

      ## Critical Reference

      | Correct | Incorrect | Notes |
      |---|---|---|
      | Place AAR in `app/libs/` | Reference a Maven coordinate | SDK is not on Maven Central |
      | Call `DynamicSDK.initialize()` in `onCreate()` | Call `getInstance()` before `initialize()` | Throws if not initialized |
      | Include `DynamicUI()` in root Compose layout | Omit `DynamicUI()` | Auth overlay won't appear |
      | Match `android:scheme` to `redirectUrl` | Use different values | OAuth callbacks break |
      | Use `viewModelScope.launch` for Flow collection | Collect on the main thread without lifecycle scope | Leaks coroutines |
      | Whitelist deep link in Dynamic dashboard | Skip dashboard config | OAuth returns fail silently |

      ---

      ## Troubleshooting — Common Issues

      ### 1 — "Could not resolve: dynamic-sdk-android.aar"
      Ensure the AAR file is in `app/libs/`. Clean the build (Build → Clean Project). Restart Android Studio.

      ### 2 — SDK not initialized
      `DynamicSDK.initialize()` must be called in `MainActivity.onCreate()` before any views call `DynamicSDK.getInstance()`.

      ### 3 — OAuth callbacks not working
      Verify the URL scheme in `AndroidManifest.xml` matches `redirectUrl` in `ClientProps`. Whitelist the deep link URL in the Dynamic dashboard under **Security → Whitelist Mobile Deeplink**.

      ### 4 — Wallets not appearing after login
      Wallets are created asynchronously. Use `sdk.wallets.userWalletsChanges` Flow to listen for updates. Check that embedded wallets are enabled in the dashboard.

      ### 5 — DynamicUI overlay not showing
      Ensure `DynamicUI()` is in your root Compose layout inside a `Box` or similar container that supports overlays.

      If the issue persists, check https://docs.dynamic.xyz/overview/troubleshooting/general.

      ---

      ## Beyond This Quickstart

      This prompt covers initial setup only. For deeper guides (authentication flows, wallet operations, session management, transactions, etc.), fetch the full documentation index:

      **https://www.dynamic.xyz/docs/llms.txt**

      This file contains every page in the Dynamic documentation organized by SDK. Search for the "Kotlin SDK" section to discover all available pages and their URLs. Use it as your navigation source for any question beyond what this quickstart covers.

      Alternatively, if the Dynamic MCP server is available in your environment, query it directly for any documentation page.
      ````
    </div>
  </Tab>

  <Tab title="Step-by-step">
    <Accordion title="Prerequisites">
      Before you begin, make sure you have:

      * **Android SDK 28+** (Android 9.0+)
      * **Kotlin 2.1.0+**
      * **Gradle 8.x+**
      * **Java 17**
      * **Dynamic Account** — Environment ID from [Dynamic Dashboard](https://app.dynamic.xyz/dashboard/overview)
    </Accordion>

    ## Install the SDK

    This guide uses AAR-based setup (there is no interactive embed on this page).

    ### Step 1: Download AAR files

    Download the latest AAR files from the [Dynamic Android SDK repository](https://github.com/dynamic-labs/android-sdk-and-sample-app):

    * `dynamic-sdk-android.aar` (required)
    * `solana-web3.aar` (optional - only if you need Solana support)

    Place them in your project's `app/libs` directory.

    ### Step 2: Add dependencies

    Add the Dynamic SDK and all required dependencies to your `build.gradle.kts`:

    ```kotlin build.gradle.kts theme={"system"}
    dependencies {
        // ==========================================
        // Dynamic SDK AAR Files
        // ==========================================

        // Core SDK (required)
        implementation(files("libs/dynamic-sdk-android.aar"))

        // Solana SDK (optional - remove if not needed)
        implementation(files("libs/solana-web3.aar"))
        implementation("org.sol4k:sol4k:0.6.0")  // Required by Dynamic Solana SDK

        // ==========================================
        // Required transitive dependencies
        // ==========================================

        // Kotlin Coroutines
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")

        // JSON serialization
        implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")

        // Android WebView
        implementation("androidx.webkit:webkit:1.8.0")

        // HTTP client
        implementation("com.squareup.okhttp3:okhttp:4.12.0")

        // Custom Tabs for authentication
        implementation("androidx.browser:browser:1.7.0")

        // Secure storage - DataStore + Tink
        implementation("androidx.datastore:datastore-preferences:1.1.1")
        implementation("com.google.crypto.tink:tink-android:1.15.0")

        // Passkeys support
        implementation("androidx.credentials:credentials:1.2.2")
        implementation("androidx.credentials:credentials-play-services-auth:1.2.2")
        implementation("com.google.android.gms:play-services-auth:20.7.0")

        // Jetpack Compose (required for DynamicUI)
        implementation(platform("androidx.compose:compose-bom:2024.09.00"))
        implementation("androidx.compose.ui:ui")
        implementation("androidx.compose.foundation:foundation")
        implementation("androidx.compose.runtime:runtime")
        implementation("androidx.lifecycle:lifecycle-runtime-compose:2.6.2")
    }
    ```

    <Note>
      If you don't need Solana support, you can skip the `solana-web3.aar` and `sol4k` dependencies.
    </Note>

    ## Configure AndroidManifest.xml

    Add the required permissions and activities to your `AndroidManifest.xml`:

    ```xml AndroidManifest.xml theme={"system"}
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

        <application
            android:usesCleartextTraffic="true"
            ...>

            <activity
                android:name=".MainActivity"
                android:exported="true"
                android:launchMode="singleTask">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>

            <!-- OAuth Callback Activity (Required) -->
            <activity
                android:name="com.dynamic.sdk.android.Auth.AuthCallbackActivity"
                android:exported="true"
                android:launchMode="singleTop"
                android:noHistory="true"
                android:theme="@android:style/Theme.Translucent.NoTitleBar">
                <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="yourappscheme" />
                </intent-filter>
            </activity>
        </application>
    </manifest>
    ```

    <Warning>
      Make sure the `android:scheme` in your manifest matches the `redirectUrl` in your `ClientProps`. For example, if `redirectUrl = "myapp://"`, then use `android:scheme="myapp"`.
    </Warning>

    ## Initialize the SDK

    Initialize the Dynamic SDK in your MainActivity:

    ```kotlin MainActivity.kt theme={"system"}
    import android.os.Bundle
    import androidx.activity.ComponentActivity
    import androidx.activity.compose.setContent
    import androidx.compose.foundation.layout.*
    import androidx.compose.material3.*
    import androidx.compose.ui.Modifier
    import com.dynamic.sdk.android.DynamicSDK
    import com.dynamic.sdk.android.UI.DynamicUI
    import com.dynamic.sdk.android.core.ClientProps
    import com.dynamic.sdk.android.core.LoggerLevel

    class MainActivity : ComponentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)

            // Initialize Dynamic SDK
            val props = ClientProps(
                environmentId = "your-environment-id",
                appLogoUrl = "https://your-app.com/logo.png",
                appName = "Your App Name",
                redirectUrl = "yourappscheme://",
                appOrigin = "https://your-app.com",
                logLevel = LoggerLevel.DEBUG
            )
            DynamicSDK.initialize(props, applicationContext, this)

            setContent {
                MaterialTheme {
                    Surface(
                        modifier = Modifier.fillMaxSize(),
                        color = MaterialTheme.colorScheme.background
                    ) {
                        Box(modifier = Modifier.fillMaxSize()) {
                            // Main app content
                            AppContent()

                            // Dynamic SDK WebView overlay (required for auth flows)
                            DynamicUI()
                        }
                    }
                }
            }
        }
    }
    ```

    ### Configuration Options

    The `ClientProps` supports various configuration options:

    | Property         | Description                                                                                              | Required |
    | ---------------- | -------------------------------------------------------------------------------------------------------- | -------- |
    | `environmentId`  | Your Dynamic environment ID from the dashboard                                                           | Yes      |
    | `appName`        | Your app's display name                                                                                  | Yes      |
    | `appLogoUrl`     | URL to your app's logo (shown in auth UI)                                                                | Yes      |
    | `redirectUrl`    | Deep link URL scheme for OAuth callbacks                                                                 | Yes      |
    | `appOrigin`      | Your app's origin URL                                                                                    | Yes      |
    | `reownProjectId` | Reown (WalletConnect) project ID for [connecting to dApps](/docs/kotlin/wallets/global-wallets/walletconnect) | No       |
    | `logLevel`       | Logging level (`.DEBUG`, `.INFO`, `.WARN`, `.ERROR`)                                                     | No       |

    ### Access the SDK

    After initialization, access the SDK singleton anywhere in your app:

    ```kotlin theme={"system"}
    val sdk = DynamicSDK.getInstance()

    // Show auth modal
    sdk.ui.showAuth()

    // Check auth state
    val isAuthenticated = sdk.auth.isAuthenticated()

    // Get wallets
    val wallets = sdk.wallets.userWallets

    // Get primary wallet
    val primaryWallet = sdk.wallets.primaryWallet
    ```

    ## Basic Usage

    ### Using Built-in Authentication UI

    The easiest way to add authentication is using the built-in UI:

    ```kotlin theme={"system"}
    import androidx.compose.foundation.layout.*
    import androidx.compose.material3.*
    import androidx.compose.runtime.*
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.unit.dp
    import com.dynamic.sdk.android.DynamicSDK

    @Composable
    fun LoginScreen() {
        val sdk = DynamicSDK.getInstance()

        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(16.dp),
            verticalArrangement = Arrangement.Center
        ) {
            Button(
                onClick = { sdk.ui.showAuth() },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text("Sign In")
            }
        }
    }
    ```

    ### Listening for Authentication State

    Use Kotlin Flow to react to authentication changes:

    ```kotlin theme={"system"}
    import androidx.compose.foundation.layout.*
    import androidx.compose.material3.*
    import androidx.compose.runtime.*
    import androidx.compose.ui.Modifier
    import androidx.lifecycle.ViewModel
    import androidx.lifecycle.viewModelScope
    import com.dynamic.sdk.android.DynamicSDK
    import com.dynamic.sdk.android.Models.UserProfile
    import kotlinx.coroutines.flow.MutableStateFlow
    import kotlinx.coroutines.flow.StateFlow
    import kotlinx.coroutines.launch

    class AuthViewModel : ViewModel() {
        private val sdk = DynamicSDK.getInstance()

        private val _user = MutableStateFlow<UserProfile?>(null)
        val user: StateFlow<UserProfile?> = _user

        private val _isAuthenticated = MutableStateFlow(false)
        val isAuthenticated: StateFlow<Boolean> = _isAuthenticated

        init {
            // Check initial auth state
            _isAuthenticated.value = sdk.auth.isAuthenticated()
            _user.value = sdk.auth.authenticatedUser

            // Listen for auth state changes
            viewModelScope.launch {
                sdk.auth.authenticatedUserChanges.collect { user ->
                    _user.value = user
                    _isAuthenticated.value = user != null
                }
            }
        }
    }

    @Composable
    fun AppContent(viewModel: AuthViewModel) {
        val isAuthenticated by viewModel.isAuthenticated.collectAsState()

        if (isAuthenticated) {
            HomeScreen()
        } else {
            LoginScreen()
        }
    }
    ```

    ### Complete Example with Wallets

    ```kotlin theme={"system"}
    import androidx.compose.foundation.layout.*
    import androidx.compose.foundation.lazy.LazyColumn
    import androidx.compose.foundation.lazy.items
    import androidx.compose.material3.*
    import androidx.compose.runtime.*
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.unit.dp
    import androidx.lifecycle.ViewModel
    import androidx.lifecycle.viewModelScope
    import com.dynamic.sdk.android.DynamicSDK
    import com.dynamic.sdk.android.Models.BaseWallet
    import kotlinx.coroutines.flow.MutableStateFlow
    import kotlinx.coroutines.flow.StateFlow
    import kotlinx.coroutines.launch

    class HomeViewModel : ViewModel() {
        private val sdk = DynamicSDK.getInstance()

        private val _wallets = MutableStateFlow<List<BaseWallet>>(emptyList())
        val wallets: StateFlow<List<BaseWallet>> = _wallets

        init {
            // Get current wallets
            _wallets.value = sdk.wallets.userWallets

            // Listen for wallet changes
            viewModelScope.launch {
                sdk.wallets.userWalletsChanges.collect { newWallets ->
                    _wallets.value = newWallets
                }
            }
        }

        fun showUserProfile() {
            sdk.ui.showUserProfile()
        }

        fun logout() {
            viewModelScope.launch {
                sdk.auth.logout()
            }
        }
    }

    @Composable
    fun HomeScreen(viewModel: HomeViewModel) {
        val wallets by viewModel.wallets.collectAsState()

        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(16.dp)
        ) {
            Text(
                text = "Welcome!",
                style = MaterialTheme.typography.headlineMedium
            )

            Spacer(modifier = Modifier.height(16.dp))

            if (wallets.isEmpty()) {
                CircularProgressIndicator()
                Text("Creating wallets...")
            } else {
                LazyColumn {
                    items(wallets) { wallet ->
                        WalletCard(wallet)
                    }
                }
            }

            Spacer(modifier = Modifier.height(16.dp))

            Button(
                onClick = { viewModel.showUserProfile() },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text("Show Profile")
            }

            Button(
                onClick = { viewModel.logout() },
                modifier = Modifier.fillMaxWidth(),
                colors = ButtonDefaults.buttonColors(
                    containerColor = MaterialTheme.colorScheme.error
                )
            ) {
                Text("Logout")
            }
        }
    }

    @Composable
    fun WalletCard(wallet: BaseWallet) {
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .padding(vertical = 8.dp)
        ) {
            Column(modifier = Modifier.padding(16.dp)) {
                Text(
                    text = wallet.chain.uppercase(),
                    style = MaterialTheme.typography.labelMedium,
                    color = MaterialTheme.colorScheme.primary
                )
                Text(
                    text = wallet.address,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
    ```

    ## Enable Features in Dashboard

    Before you can use authentication and wallet features, enable them in your Dynamic dashboard:

    1. Go to your [Dynamic Dashboard](https://app.dynamic.xyz/dashboard/overview)
    2. Select your project
    3. Go to **Authentication** and enable the methods you want to use:
       * Email OTP
       * SMS OTP
       * Social providers (Google, Apple, Farcaster, etc.)
       * Passkeys
    4. Go to **Wallets** and enable embedded wallets
    5. Go to **Chains** and enable the networks you want to support (EVM and/or Solana)

    <Tip>
      For testing, we recommend starting with Email OTP authentication and an EVM
      testnet like Base Sepolia. This gives you a complete setup without requiring
      real phone numbers or mainnet transactions.
    </Tip>

    ## Troubleshooting

    ### Common Issues

    * **Could not resolve: dynamic-sdk-android.aar**
      * Make sure you've placed the AAR file in your `app/libs` directory
      * Try cleaning the build (Build → Clean Project)
      * Restart Android Studio

    * **SDK not initialized**
      * Ensure `DynamicSDK.initialize()` is called in your `MainActivity.onCreate()` before any views access the SDK
      * Don't call `DynamicSDK.getInstance()` before initialization

    * **Authentication callbacks not working**
      * Verify your URL scheme is configured in `AndroidManifest.xml`
      * Ensure the `redirectUrl` matches your URL scheme
      * Whitelist your deep link URL in the Dynamic dashboard under **Security → Whitelist Mobile Deeplink**

    * **Wallets not appearing after login**
      * Wallets are created asynchronously after authentication
      * Use `sdk.wallets.userWalletsChanges` Flow to listen for wallet updates
      * Check that embedded wallets are enabled in your dashboard

    * **DynamicUI overlay not showing**
      * Make sure `DynamicUI()` composable is included in your app's root layout
      * Verify it's placed inside a `Box` or similar container that allows overlays

    ## Next Steps

    <Warning>
      **Step-up authentication** and **device registration** are required
      before accepting the `2026_04_01` API version. You must implement
      both manually in your headless integration.
      See the [upgrade guide](/docs/overview/migrations/api/2026_04_01).
    </Warning>

    Your SDK is configured. You can go deeper here:

    1. **[Authentication Guide](/docs/kotlin/headless-authentication)** - Learn how to implement user authentication with email, SMS, and passkeys
    2. **[Social Authentication](/docs/kotlin/social-authentication)** - Add social login options like Google, Apple, and Farcaster
    3. **[Session Management](/docs/kotlin/session-management)** - Manage authentication state with Kotlin Flow
    4. **[Wallet Operations](/docs/kotlin/wallets/general/token-balances)** - Work with balances and sign messages
    5. **[EVM Operations](/docs/kotlin/wallets/evm/send-eth)** - Perform EVM transactions
    6. **[Solana Operations](/docs/kotlin/wallets/solana/connection)** - Send Solana transactions
    7. **[Connect to dApps](/docs/kotlin/wallets/global-wallets/walletconnect)** - Use WalletConnect to connect your embedded wallet to any dApp
    8. **[Step-up authentication](/docs/kotlin/step-up-auth)** — required before accepting the `2026_04_01` API version
    9. **[Device registration](/docs/kotlin/device-registration)** — required before accepting the `2026_04_01` API version

    <Info>
      Building without DynamicUI()? See the [Authentication screens](/docs/kotlin/headless-authentication) for a full list of screens your app needs to handle.
    </Info>
  </Tab>
</Tabs>
