The Para Swift SDK enables you to integrate secure wallet features including creation, passkey-based authentication, and transaction signing into your iOS 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.
Don’t have an API key yet? Request access to the Developer Portal to create API keys, manage billing, teams, and more.

Install the SDK

1

Add the Para Swift SDK Package

  1. In your Xcode project, go to File > Add Packages or (in your target) Frameworks, Libraries, and Embedded Content and click +.
  2. Enter https://github.com/getpara/swift-sdk
  3. Select Branch and enter 2.0.0-alpha
  4. Add the package to your app target and click Add Package.
2

Configure Associated Domains for Passkeys

To enable passkeys on iOS, you need to configure Associated Domains:
  1. In Xcode, go to Signing & Capabilities for your app target
  2. Click + Capability and add Associated Domains
  3. Add the following entries:
    webcredentials:app.usecapsule.com
    webcredentials:app.beta.usecapsule.com
    
  4. Register your Team ID + Bundle ID with Para via the Developer Portal
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.

Configure URL Scheme

Before initializing Para, you need to configure your app’s URL scheme for deep linking. This is required for the appScheme parameter and enables OAuth authentication flows.
1

Add URL Scheme in Xcode

  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., paraswift, yourapp)
    • Role: Select Editor

Initialize Para

To use Para’s features, you’ll need to initialize a Para manager that can be accessed throughout your app. This manager handles all interactions with Para’s services, including authentication, wallet management, and transaction signing. Below is an example of initializing the SDK in a SwiftUI application:
App.swift
import SwiftUI
import ParaSwift

@main
struct ExampleApp: App {
    @StateObject private var paraManager: ParaManager

    init() {
        // Initialize Para manager
        _paraManager = StateObject(wrappedValue: ParaManager(
            environment: .beta, // Use .prod for production
            apiKey: "YOUR_API_KEY_HERE", // Get from: https://developer.getpara.com
            appScheme: "yourapp" // Your app's URL scheme for deep linking
        ))
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(paraManager)
        }
    }
}
The appScheme parameter must match the URL scheme you configured in your Info.plist. This enables deep linking for external wallet integrations like MetaMask and OAuth authentication flows.

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

Build Your Authentication Flow

The recommended approach is to create a single authentication view that handles all authentication methods together. This provides users with all authentication options in one place.
Para supports authentication with both email addresses and phone numbers.
1

Handle Email/Phone Submission

Initiate authentication with email or phone:
AuthenticationView.swift
// Initialize authentication controllers
@Environment(\.authorizationController) private var authorizationController
@Environment(\.webAuthenticationSession) private var webAuthenticationSession

// Determine if input is email or phone
let auth: Auth
if userInput.contains("@") {
    auth = .email(userInput)
} else {
    auth = .phone(userInput) // Include country code
}

// SDK call: Initiate authentication
let authState = try await paraManager.initiateAuthFlow(auth: auth)

// Handle the result based on stage
switch authState.stage {
case .verify:
    // New user - needs verification (see OTP handling step below)
case .login:
    // Existing user - complete login
    try await paraManager.handleLogin(
        authState: authState,
        authorizationController: authorizationController,
        webAuthenticationSession: webAuthenticationSession
    )
case .signup:
    // Handle signup after verification
}
2

Handle OTP Verification

For new users who need verification, handle the OTP flow:
AuthenticationView.swift
// After user enters the verification code
let verificationCode = "123456" // Get from user input

do {
    // Submit verification code
    let verifiedState = try await paraManager.handleVerificationCode(
        verificationCode: verificationCode
    )
    
    // Complete signup with passkey
    try await paraManager.handleSignup(
        authState: verifiedState,
        method: .passkey,
        authorizationController: authorizationController,
        webAuthenticationSession: webAuthenticationSession
    )
    
    // User is now signed up and authenticated
} catch {
    // Handle error
}

Handle Returning Users

After initial setup, users can log in using their email or phone with the same authentication flow:
LoginView.swift
// Login with email
let authState = try await paraManager.initiateAuthFlow(auth: .email(userEmail))

// Since the user exists, authState.stage will be .login
if authState.stage == .login {
    try await paraManager.handleLogin(
        authState: authState,
        authorizationController: authorizationController,
        webAuthenticationSession: webAuthenticationSession
    )
    // User is now logged in
}
Alternatively, you can use direct passkey login if you know the user has set up passkeys:
LoginView.swift
// Direct passkey login (will show all available passkeys if email/phone not provided)
try await paraManager.loginWithPasskey(
    authorizationController: authorizationController,
    email: userEmail, // Optional - helps filter passkeys
    phone: nil
)
This will prompt the user for Face ID or Touch ID verification before granting access to their wallets.

Check Authentication Status

You can check if a user is already authenticated:
ContentView.swift
let isLoggedIn = await paraManager.isFullyLoggedIn()

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:
SettingsView.swift
try await paraManager.logout()

Create and Manage Wallets

After successful authentication, you can perform wallet operations:
WalletView.swift
// Get all user wallets
try await paraManager.fetchWallets() // Ensure we have the latest wallets

if paraManager.wallets.isEmpty {
    // No wallets, perhaps create one
    try await paraManager.createWallet(type: .evm, skipDistributable: false)
    // paraManager.wallets is updated internally
    guard let firstWallet = paraManager.wallets.first else {
        print("Failed to create or find a wallet.")
        return
    }
    
    // Sign a simple message (SDK handles Base64 encoding internally)
    let signature = try await paraManager.signMessage(
        walletId: firstWallet.id,
        message: "Hello, Para!"
    )
    print("Signature: \(signature)")
    
} else {
    // Use existing wallet
    guard let firstWallet = paraManager.wallets.first else { return }
    
    // Sign a simple message (SDK handles Base64 encoding internally)
    let signature = try await paraManager.signMessage(
        walletId: firstWallet.id,
        message: "Hello, Para!"
    )
    print("Signature: \(signature)")
}
For detailed transaction signing with specific blockchains (EVM, Solana, Cosmos), please refer to the respective blockchain integration guides.

Example

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

Swift SDK Example App

Next Steps

After integrating Para into your Swift app, you can explore other features and integrations to enhance your Para experience.