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

# Swift

> Create user wallets from your iOS app in under 5 minutes

<Note>
  **This page has been updated for Wallets SDK V1.** If you are using the previous version,
  see the [previous version of this page](/wallets/v0/quickstarts/swift) or the [V1 migration guide](/wallets/guides/migrate-to-v1).
</Note>

This quickstart integrates the Crossmint Swift SDK into an iOS app to create a non-custodial wallet for a user, fund it with testnet USDC on Base Sepolia, and send USDC to another wallet.

<CardGroup cols={2}>
  <Snippet file="before-you-start.mdx" />

  <Card title="iOS Demo App" icon="github" iconType="duotone" href="https://github.com/Crossmint/crossmint-swift-sdk/tree/main/Examples/SmartWalletsDemo">
    See a full working example with a repository to clone.
  </Card>
</CardGroup>

<Steps>
  <Step title="Install the SDK">
    Add the Crossmint Swift SDK to your project using Swift Package Manager.

    In Xcode, go to **File > Add Package Dependencies** and enter the repository URL:

    ```text theme={null}
    https://github.com/Crossmint/crossmint-swift-sdk
    ```

    Select the `CrossmintClientSDK` product to add to your target.

    ### Requirements

    * iOS 15.0+
    * Xcode 16.0+
    * Swift 5.9+
  </Step>

  <Step title="Configure your API key">
    The Crossmint SDK requires a client API key for authentication.
    [Get your client API key](/introduction/platform/api-keys/client-side) using the Crossmint Console.

    Create a file to store your configuration:

    ```swift CrossmintConfig.swift theme={null}
    import CrossmintAuth
    import CrossmintClient


    let crossmintApiKey = "<YOUR_API_KEY>"
    var crossmintAuthManager: CrossmintAuthManager = {
        do {
            return try CrossmintAuthManager(apiKey: crossmintApiKey)
        } catch {
            fatalError("Invalid Crossmint configuration: \(error)")
        }
    }()
    ```

    <Note>
      The environment (staging vs production) is automatically determined by your API key. Staging keys start with `ck_staging_`, production keys with `ck_production_`.
    </Note>
  </Step>

  <Step title="Initialize the Crossmint SDK">
    Initialize the SDK in your app's entry point and add the non-custodial signer view modifier. This example uses [Crossmint Auth](/authentication/introduction) but you can use [any authentication provider of your choice](/wallets/guides/bring-your-own-auth).

    ```swift YourApp.swift theme={null}
    import SwiftUI
    import CrossmintClient

    @main
    struct YourApp: App {
        var body: some Scene {
            WindowGroup {
                ContentView()
                    .crossmintNonCustodialSigner(
                        CrossmintSDK.shared(
                            apiKey: crossmintApiKey,
                            authManager: crossmintAuthManager
                        )
                    )
            }
        }
    }
    ```

    The `.crossmintNonCustodialSigner()` modifier is required for transaction signing. It embeds a hidden web view that securely manages the signing process.

    ### Access SDK instances

    Inside your views, access SDK functionality using `CrossmintSDK.shared`:

    ```swift theme={null}
    import CrossmintClient

    let sdk = CrossmintSDK.shared
    let authManager = sdk.authManager
    let wallets = sdk.crossmintWallets
    ```
  </Step>

  <Step title="Authenticate users">
    Actions within the SDK are user-based, so first you need to authenticate a user.
    Choose your authentication method:

    <Tabs>
      <Tab title="Crossmint Auth (OTP)">
        Use Crossmint's built-in OTP authentication for easy, email-based login.

        <Steps>
          <Step title="Send OTP to user's email">
            ```swift theme={null}
            import CrossmintAuth

            let email = "user@example.com"

            do {
                try await crossmintAuthManager.sendEmailOtp(email: email)
                // OTP sent — show an input field for the code
            } catch let error as AuthManagerError {
                // Handle error: error.errorMessage
            }
            ```
          </Step>

          <Step title="Verify the OTP sent to the user's email">
            ```swift theme={null}
            import CrossmintAuth

            let email = "user@example.com"
            let otpCode = "123456" // Code entered by user

            do {
                let status = try await crossmintAuthManager.confirmEmailOtp(
                    email: email,
                    code: otpCode
                )

                if case .authenticationStatus(.authenticated) = status {
                    // User is authenticated, proceed to create wallet
                }
            } catch let error as AuthManagerError {
                // Handle error: error.errorMessage
            }
            ```
          </Step>
        </Steps>

        <Note>
          See the [iOS Demo App](https://github.com/Crossmint/crossmint-swift-sdk/tree/main/Examples/SmartWalletsDemo) repository for a complete UI implementation example with SwiftUI views.
        </Note>
      </Tab>

      <Tab title="Third-Party Auth (Prod)">
        If you have an existing auth provider (Auth0, Firebase, Supabase, etc.), authenticate users with your provider and pass the JWT to Crossmint.

        ```swift theme={null}
        import CrossmintClient

        // After the user authenticates with your provider, set their JWT
        let authManager = CrossmintSDK.shared.authManager
        await authManager.setJWT(yourProviderJWT)
        // User is now authenticated with Crossmint
        ```

        <Note>
          Configure JWT authentication in the [Crossmint Console](https://console.crossmint.com) under API Keys > JWT Authentication before using third-party auth.
        </Note>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Create a wallet">
    After authentication, create the user's wallet. This example uses Base Sepolia (Base testnet) but you can choose any [supported chain](/introduction/supported-chains).

    ```swift theme={null}
    import CrossmintClient
    import CrossmintAuth

    let sdk = CrossmintSDK.shared

    do {
        guard let email = crossmintAuthManager.email else {
            // User not authenticated — return to the auth step
            return
        }

        let wallet = try await sdk.crossmintWallets.createWallet(
            chain: EVMChain.baseSepolia,
            recovery: EVMSigners.email(email)
        )

        // Wallet is ready to use!
        print("Wallet address: \(wallet.address)")
    } catch let error as WalletError {
        // Handle error: error.errorMessage
    }
    ```

    <Note>
      Use `createWallet` for new users. For returning users, call `getWallet(chain: EVMChain.baseSepolia)` to fetch their existing wallet without creating a new one.
    </Note>
  </Step>

  <Step title="Check wallet balance">
    Before sending tokens, check the wallet balance:

    ```swift theme={null}
    import CrossmintClient

    do {
        let balance = try await wallet.balances()

        // Native token (ETH on Base Sepolia)
        print("ETH: \(balance.nativeToken.amount)")

        // USDC balance
        print("USDC: \(balance.usdc.amount)")

        // All other tokens in this wallet
        for token in balance.tokens {
            print("\(token.name): \(token.amount)")
        }
    } catch let error as WalletError {
        // Handle error: error.errorMessage
    }
    ```
  </Step>

  <Step title="Fund the wallet">
    Before sending USDC, you need to get some into the wallet.

    **Option 1: Use the staging fund method (staging only)**

    ```swift theme={null}
    do {
        try await wallet.fund(token: .usdxm, amount: 10)
    } catch {
        // Handle error
    }
    ```

    **Option 2: Use the USDC Faucet**

    Get the wallet address and use the [USDC Faucet](https://faucet.circle.com/):

    ```swift theme={null}
    let walletAddress = wallet.address
    print("Fund this address: \(walletAddress)")
    ```

    Navigate to the faucet, select **Base Sepolia**, and enter the wallet address.

    <img src="https://mintcdn.com/crossmint/eYDj8xN_FdfDDRqk/images/wallets/circle-usdc-faucet.png?fit=max&auto=format&n=eYDj8xN_FdfDDRqk&q=85&s=5e7b583883acb530b97680bb34acf72f" alt="Circle faucet - Base Sepolia selected" width="1136" height="1088" data-path="images/wallets/circle-usdc-faucet.png" />
  </Step>

  <Step title="Send USDC">
    Send USDC to another wallet using the `wallet.send` function:

    ```swift theme={null}
    import CrossmintClient

    let recipientAddress = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb2"

    do {
        let summary = try await wallet.send(
            recipientAddress,
            "base-sepolia:usdc",
            0.01
        )
        print("Transaction hash: \(summary.txId)")
    } catch let error as TransactionError {
        switch error {
        case .userCancelled:
            // User cancelled the transaction
            break
        default:
            // Handle error: error.errorMessage
            break
        }
    }
    ```

    <Note>
      The Swift SDK handles transaction approval automatically inside `send()`. Unlike the Kotlin SDK, no explicit `approve()` call is needed.
    </Note>

    The first time a wallet sends a transaction on a device, an OTP verification is required. The SDK automatically handles this by presenting an OTP input view.

    To handle the OTP flow, observe the `isOTPRequired` publisher in your view:

    ```swift theme={null}
    import SwiftUI
    import CrossmintClient

    struct ContentView: View {
        @State private var showOTPView = false

        var body: some View {
            YourMainView()
                .onReceive(CrossmintSDK.shared.isOTPRequired) { required in
                    showOTPView = required
                }
                .sheet(isPresented: $showOTPView) {
                    EmptyView() // Replace with your OTP input UI, then call CrossmintSDK.shared.submit(otp: enteredCode)
                }
        }
    }
    ```

    Following transactions sent from the same device do not need OTP verification.

    And that is it! You just created a non-custodial wallet for your user and made a USDC transaction on Base Sepolia.
  </Step>
</Steps>

## Launching in Production

For production, the steps are almost identical, but some changes are required:

1. Create a developer account on the [production console](https://www.crossmint.com/console)
2. Create a production client API key on the [API Keys](https://www.crossmint.com/console/projects/apiKeys) page with the API scopes `users.create`, `users.read`, `wallets.read`, `wallets.create`, `wallets:transactions.create`, `wallets:transactions.sign`, `wallets:balance.read`, `wallets.fund`
3. Update your configuration with the production API key
4. **Use your own authentication provider**: For production applications, Crossmint recommends using [third-party authentication](/wallets/guides/bring-your-own-auth) with providers like Auth0, Firebase, or Supabase, rather than Crossmint Auth (OTP). Configure JWT authentication in the [Crossmint Console](https://www.crossmint.com/console/projects/apiKeys) under API Keys > JWT Authentication

## Learn More

<CardGroup cols={3}>
  <Card title="Check Balances" icon="money-bill-transfer" iconType="duotone" href="/wallets/guides/check-balances">
    Check the balance of a wallet.
  </Card>

  <Card title="Transfer Tokens" icon="coins" iconType="duotone" color="#1A5785" href="/wallets/guides/transfer-tokens">
    Send tokens between wallets.
  </Card>

  <Card title="Operational Signers" icon="key" iconType="duotone" color="#2156B9" href="/wallets/guides/signers/add-signers">
    Register operational signers on a wallet.
  </Card>
</CardGroup>

## Other Links

<CardGroup cols={2}>
  <Card title="Swift SDK Reference" icon="https://mintcdn.com/crossmint/GBIHIdhwMt6rU_EY/images/icons/swift.svg?fit=max&auto=format&n=GBIHIdhwMt6rU_EY&q=85&s=91137deeec19366731790dd77c0982bc" href="/sdk-reference/wallets/swift/classes/wallet" width="800" height="800" data-path="images/icons/swift.svg">
    Deep dive into Swift SDK reference docs.
  </Card>

  <Card title="Talk to an expert" icon="message" iconType="duotone" color="#ADD8E6" href="https://www.crossmint.com/contact/sales">
    Contact the Crossmint sales team for support.
  </Card>
</CardGroup>
