iOS SDK (v2.0+)

The AeroSync iOS SDK is a native SwiftUI SDK for secure bank account linking. Built with SwiftUI and WKWebView, it lets users connect their bank accounts through fast, tokenized connections — with full OAuth and MFA support. Your users' banking credentials are never shared with or stored by your application.

📘

Looking for the old (v1.2.1) API?

This page documents SDK v2.2.1. If your app still depends on an older aerosync-ios-sdk install (installed via "Branch: main" rather than a version tag), see the iOS SDK (Legacy v1.2.1) page for that API reference, or jump to Migrating from v1.x below to upgrade.

Create a User

The Aerosync+Aeronetwork SDKs require a user identifier, aeroPassUserUuid, to be passed to the widget on launch. Follow the guide here to create a new user and access the user's aeroPassUserUuid.

Features

  • Full bank linking experience — complete OAuth and credential-based flows via AerosyncSDK
  • OAuth support — external browser opens automatically; returns cleanly to your app via deep link
  • MFA support — multi-factor authentication flows with job and connection ID handling
  • Multi-Account Linking: Return multiple linked accounts from a single flow (v2.2.0+)
  • Swipe navigation — swipe right/left to go back and forward within the widget
  • Theming — light and dark mode support
  • Swift Package Manager — no CocoaPods required

Requirements

RequirementMinimum
iOS14.0+
Xcode12.0+
Swift5.3+

Installation

Swift Package Manager

In Xcode: File → Add Package Dependencies, then enter:

https://github.com/Aeropay-inc/aerosync-ios-sdk

Select version 2.2.1 or later, then click Add Package.

Or via Package.swift:

dependencies: [
    .package(url: "https://github.com/Aeropay-inc/aerosync-ios-sdk", from: "2.2.1")
]

Import

import aerosync_ios_sdk

Setup

1. Register a URL scheme

OAuth bank flows redirect back to your app using a custom URL scheme. Add it to your app's Info.plist:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>yourapp</string>
        </array>
    </dict>
</array>
📘

Choose a unique scheme such as yourapp or com.yourcompany.yourapp. The full deeplink passed to the SDK would then be yourapp://connect.

2. Handle the deep link callback

In your SwiftUI App, add an onOpenURL modifier so returning from OAuth completes correctly:

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { url in
                    // The SDK resolves the OAuth return automatically.
                    // Add any additional routing logic here if needed.
                }
        }
    }
}

Using SceneDelegate instead?

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url else { return }
    // Handle url
}

Quick Start

The minimum setup to get the bank linking widget running:

import SwiftUI
import aerosync_ios_sdk

struct BankLinkView: View {
    var body: some View {
        NavigationView {
            AerosyncSDK(
                token: "your-token-here",
                env: "sandbox",
                deeplink: "yourapp://connect",
                aeroPassUserUuid: "user-uuid-123",
                onEvent: { _ in },
                onSuccess: { data in print(data) },
                onClose: { _ in },
                onLoad: { _ in },
                onError: { _ in }
            )
        }
    }
}
📘

To generate a token, see the AeroSync integration guide.

Usage

Standard bank linking

import SwiftUI
import aerosync_ios_sdk

struct BankLinkView: View {
    @Environment(\.presentationMode) var presentationMode

    var body: some View {
        NavigationView {
            AerosyncSDK(
                token: "your-token-here",
                env: "sandbox",                    // "sandbox" or "production"
                deeplink: "yourapp://connect",
                aeroPassUserUuid: "user-uuid-123", // Required
                configurationId: "your-config-id", // Optional
                theme: "light",                    // "light" or "dark"
                manualLinkOnly: false,
                handleMFA: false,
                onEvent: { data in
                    // Widget events and page navigation signals
                },
                onSuccess: { data in
                    // Bank connection completed — parse data for credentials
                    print("Success: \(data)")
                },
                onClose: { _ in
                    presentationMode.wrappedValue.dismiss()
                },
                onLoad: { _ in
                    // Widget finished loading
                },
                onError: { error in
                    print("Error: \(error)")
                }
            )
            .navigationTitle("Link Your Bank")
        }
    }
}

MFA flow

Use this when re-authenticating an existing bank connection that requires multi-factor verification:

AerosyncSDK(
    token: "your-token-here",
    env: "sandbox",
    deeplink: "yourapp://connect",
    aeroPassUserUuid: "user-uuid-123",
    handleMFA: true,
    jobId: "your-job-id",           // Required when handleMFA is true
    connectionId: "your-conn-id",   // Required when handleMFA is true
    onEvent: { _ in },
    onSuccess: { data in
        // MFA completed successfully
    },
    onClose: { _ in },
    onLoad: { _ in },
    onError: { error in
        print("MFA error: \(error)")
    }
)

Presenting as a sheet

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

    var body: some View {
        Button("Link Bank Account") {
            showWidget = true
        }
        .sheet(isPresented: $showWidget) {
            NavigationView {
                AerosyncSDK(
                    token: "your-token-here",
                    env: "sandbox",
                    deeplink: "yourapp://connect",
                    aeroPassUserUuid: "user-uuid-123",
                    onEvent: { _ in },
                    onSuccess: { data in
                        showWidget = false
                    },
                    onClose: { _ in
                        showWidget = false
                    },
                    onLoad: { _ in },
                    onError: { _ in }
                )
                .navigationTitle("Link Your Bank")
                .navigationBarTitleDisplayMode(.inline)
            }
        }
    }
}

API Reference

To generate a token, see the AeroSync integration guide.

AerosyncSDK parameters

ParameterTypeRequiredDefaultDescription
tokenStringYes—Authentication token for the session
envStringYes—"sandbox" or "production"
deeplinkStringYes—Full URL scheme for the OAuth callback (e.g. "yourapp://connect")
aeroPassUserUuidStringYes—AeroPass user UUID — see Create a User
configurationIdString?NonilConfiguration ID for widget customization
themeStringNo"light""light" or "dark"
manualLinkOnlyBoolNofalseRestrict to manual (non-OAuth) credential linking only
handleMFABoolNofalseEnable MFA re-authentication flow
jobIdString?NonilRequired when handleMFA is true
connectionIdString?NonilRequired when handleMFA is true

Callbacks

CallbackSignatureDescription
onSuccess(String) -> VoidBank connection completed — receives a JSON string (single account, or multiple accounts when the merchant's configuration has multi-account linking enabled; see Success Response)
onClose(Any) -> VoidUser dismissed the widget
onEvent(Any) -> VoidWidget page events and navigation signals
onError(Any) -> VoidAn error occurred during the flow
onLoad(Any) -> VoidWidget finished loading

Success Response Format

The onSuccess callback receives a JSON string:

{
  "type": "pageSuccess",
  "payload": {
    "connectionId": "33e1121dde934c5cb5b964b325e28728",
    "aeroPassUserUuid": "b120bcb5-2f39-48d3-a654-1c437c1ec175",
    "clientName": "Aeropay"
  }
}
FieldDescription
connectionIdUnique identifier for the bank connection
aeroPassUserUuidAeroPass UUID for the authenticated user
clientNameYour registered client name on the AeroSync platform

Multi-Account Linking (v2.2.0+)

If your AeroSync configuration has multi-account linking enabled, the same onSuccess event instead carries a list of linked accounts:

{
  "type": "pageSuccess",
  "payload": {
    "accounts": [
      { "connectionId": "33e1121dde934c5cb5b964b325e28728", "accountType": "checking", "accountNumberDisplay": "••••1234" },
      { "connectionId": "84f2232eef045d6dc6a075436f39839", "accountType": "savings", "accountNumberDisplay": "••••5678" }
    ],
    "clientName": "Aeropay",
    "aeroPassUserUuid": "b120bcb5-2f39-48d3-a654-1c437c1ec175"
  }
}
FieldDescription
accountsList of linked accounts (multi-account only) — each has connectionId, accountType, accountNumberDisplay

Multi-account linking is opt-in and configured server-side on your AeroSync configuration — no extra widget parameters are required to receive it. onSuccess keeps its existing (String) -> Void signature either way, so adopting the typed models below is optional and non-breaking.

Parsing with the typed models:

onSuccess: { message in
    guard let result = AerosyncSuccessPayload.parse(from: message) else { return }
    switch result {
    case .multiAccount(let payload):
        for account in payload.accounts {
            print("\(account.accountType): \(account.accountNumberDisplay)")
        }
    case .singleAccount(let payload):
        print("Connected: \(payload.connectionId)")
    }
}

Manual parsing (if you'd rather not use the typed models):

onSuccess: { data in
    guard let jsonData = data.data(using: .utf8),
          let json = try? JSONSerialization.jsonObject(with: jsonData) as? [String: Any],
          let payload = json["payload"] as? [String: Any] else { return }

    if let accounts = payload["accounts"] as? [[String: Any]] {
        // Multi-account: each entry has connectionId, accountType, accountNumberDisplay
    } else {
        let connectionId = payload["connectionId"] as? String
        // Use this to authenticate with the AeroSync API
    }
}
📘

Naming note

The typed models use the Aerosync prefix (AerosyncSuccessPayload, AerosyncSingleAccountSuccessPayload, AerosyncMultiAccountSuccessPayload, AerosyncLinkedAccount) — not AeroSync. This differs slightly from the Flutter and React Native SDKs' equivalent types, so don't cross-copy the casing between platforms.


What's New Across 2.x

  • v2.1.0 — removed AerosyncEmbeddedView (to be re-introduced in a future release) and removed all debug print statements from production code paths
  • v2.2.0 — added the typed multi-account success models described above
  • v2.2.1 — fixed the sandbox environment host (https://sandbox.aerosync.com → https://sandbox-sync.aero.inc) — if you allowlist AeroSync domains in a firewall or CSP policy, update it to the new host

Migrating from 1.x

SDK 2.x introduced several breaking changes. If you're upgrading from an app installed via "Branch: main" (pre-2.0), update your integration as follows:

1.x2.xNotes
Install via Xcode "Branch: main"Install via version tag (from: "2.2.1")Pin to a real release instead of tracking main
consumerIdconfigurationIdParameter renamed
userId (MFA)connectionId (MFA)MFA parameter renamed — used together with jobId and handleMFA: true
—aeroPassUserUuidNew required parameter — must be added to every AerosyncSDK usage. See Create a User to generate one.
env values: staging, production (and dev per some 1.x releases)env values: sandbox, production onlydev/staging no longer supported — any other value force-crashes
—manualLinkOnlyNew parameter to restrict to manual (non-OAuth) linking only
Success payload: {ClientName, user_id, user_password, FILoginAcctId}Success payload: {connectionId, clientName, aeroPassUserUuid} (or {accounts: [...], clientName, aeroPassUserUuid} for multi-account)Field names and shape changed
AerosyncEmbeddedView(removed in 2.1.0)Will be re-introduced in a future release

See the iOS SDK (Legacy v1.2.1) page for the full old API reference while you migrate.


Troubleshooting

Widget not loading

  • Verify your token is valid and has not expired
  • Confirm the env value is either "sandbox" or "production" — any other value will crash with a force-unwrap

OAuth browser never opens

  • Confirm javaScriptCanOpenWindowsAutomatically is not blocked by any custom WKWebViewConfiguration layer in your app — the SDK sets this to true internally, so ensure no parent configuration overrides it

App does not return after OAuth

  • Verify the URL scheme in Info.plist matches the scheme in your deeplink parameter exactly (e.g. if deeplink is yourapp://connect, the scheme must be yourapp)
  • Confirm your App or SceneDelegate has the onOpenURL / openURLContexts handler wired up

onSuccess never fires

  • Check that your bank linking flow fully completes — partial flows (user closes early) trigger onClose, not onSuccess
  • Inspect raw events in onEvent to trace the widget state

Build errors after upgrading

  • Run File → Packages → Update to Latest Package Versions in Xcode
  • Ensure the deployment target is iOS 14.0+
  • Clean the build folder: Product → Clean Build Folder (⇧⌘K)

License

This SDK is proprietary software. Please refer to your license agreement for usage terms.


Did this page help you?