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

# iOS SDK

> Integrate the OTPless Headless SDK on iOS for the SNA-only flow — add the dependency, configure SNA in Info.plist, start with a requestId, and handle callbacks.

This page covers the **SNA-only** integration of the OTPless Headless SDK on iOS. The SDK accepts the `requestId` generated by the [Create API](/sna/create-api), performs the silent network handshake, and reports progress through callbacks. Your backend confirms the final result via the [Status Check API](/sna/status-check-api).

## Requirements

| Requirement | Version |
| ----------- | ------- |
| iOS         | 13.0+   |
| Xcode       | 12.0+   |
| Swift       | 5.5+    |

## Step 1: Add SDK dependency

The SDK can be installed via **CocoaPods** or **Swift Package Manager**. Find the latest version of the [SDK here](https://cocoapods.org/pods/OtplessBM).

<CodeGroup>
  ```ruby CocoaPods theme={null}
  # Add to your Podfile's dependencies section
  pod 'OtplessBM/Core', 'latest_version'
  ```

  ```text Swift Package Manager theme={null}
  1. In Xcode, click File > Swift Packages > Add Package Dependency.
  2. Enter the repository URL:
     https://github.com/otpless-tech/otpless-headless-iOS-sdk.git
  3. Select the dependency rule as "exact version" and use the latest version.
  ```
</CodeGroup>

For CocoaPods, run the following in your root folder to fetch the dependency:

```bash theme={null}
pod repo update
pod install
```

## Step 2: Configure Info.plist for SNA

Add the following block to your `Info.plist` **only if you are using the SNA feature**.

* If the `NSAppTransportSecurity` key is **not** already present, add the entire block below.
* If the `NSAppTransportSecurity` key **is** already present, add the listed domains one by one under `NSExceptionDomains`.

```xml Info.plist theme={null}
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>api-csp.airtel.in</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
        <key>v4-api-csp.airtel.in</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
        <key>in-vil.ipification.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
        <key>partnerapi.jio.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>
```

<Warning>
  Make sure **Silent Network Authentication** is enabled on the [OTPLESS dashboard](https://dashboard.otpless.com/login). For an SNA-only configuration, SNA must be the only channel enabled. Learn more about [Silent Network Authentication](/knowledge-base/sna/sna-101).
</Warning>

## Step 3: Start SNA with the requestId

Pass the `requestId` returned by the [Create API](/sna/create-api) to `start()`:

```swift theme={null}
otplessTask?.cancel() // Cancel any ongoing tasks to prevent request duplication

let request = OtplessRequest()
otplessRequest.set(fromBackend: "REQUEST_ID_FROM_API")

otplessTask = Task(priority: .userInitiated) {
    await Otpless.shared.start(withRequest: request)
}
```

<Note>
  Start polling the [Status Check API](/sna/status-check-api) from your backend immediately after calling `start()`. The SDK callback and the server status run in parallel.
</Note>

## Step 4: Handle callbacks

```swift theme={null}
func onResponse(_ response: OtplessBM.OtplessResponse) {
    Otpless.shared.commitOtplessResponse(response)

    switch response.responseType {
    case .SDK_READY:
        // SDK initialized successfully — enable your continue button
        // or proceed with user authentication.
        print("SDK has been initialized successfully.")

    case .FAILED:
        // SDK initialization failed
        if response.statusCode == 5003 {
            print("SDK initialization failed, please try to initialize the SDK again")
        }

    case .INITIATE:
        // Authentication has been initiated
        if response.statusCode == 200 {
            let authType = response.response?["authType"] as? String
            if authType == "SILENT_AUTH" {
                // SNA is being attempted — show a loading state.
            }
        } else {
            handleInitiateError(response)
        }

    case .ONETAP:
        // Final success response with token / idToken
        if response.statusCode == 200 {
            if let data = response.response?["data"] as? [String: Any] {
                if let idToken = data["idToken"] as? String, !idToken.isEmpty {
                    // Process idToken and verify it on your backend.
                }
                if let token = data["token"] as? String, !token.isEmpty {
                    // Process token and verify it on your backend.
                }
            } else {
                print("Token not received")
            }
        } else {
            print("Token verification failed")
        }

    case .AUTH_TERMINATED:
        // SNA-only configuration: auth could not complete.
        // Emitted when pre-checks fail, or when SNA was attempted
        // and then failed/expired. Treat as a terminal failure and
        // rely on the Status Check API for the final outcome.
        break
    }
}
```

## Callback reference

The SDK works in two steps — initialization and `start()` — and each step has its own set of callbacks.

#### Step 1: Initialization callbacks

Emitted when the SDK initializes.

| Callback    | Meaning                                            |
| ----------- | -------------------------------------------------- |
| `SDK_READY` | SDK initialization completed.                      |
| `FAILED`    | SDK failed to initialize (e.g. `statusCode 5003`). |

#### Step 2: Start callbacks

Emitted after you invoke `start()` to begin authentication.

| Callback          | State                  | Meaning                                                                                                           |
| ----------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `INITIATE`        | Non-terminal           | SNA is being attempted after pre-checks pass. `authType` is `SILENT_AUTH`.                                        |
| `ONETAP`          | **Success — terminal** | SNA completed successfully (Silent Mobile Verification). Returns `token` / `idToken`.                             |
| `AUTH_TERMINATED` | **Failed — terminal**  | Emitted in two cases: (1) pre-checks failed → terminated directly; (2) SNA was initiated and then failed/expired. |

<Note>
  For the `errorCode` / `statusCode` values surfaced in SDK callbacks, see [SDK Error Codes](/sna/sdk-error-codes).
</Note>

## Next step

<Card title="Status Check API" icon="circle-check" href="/sna/status-check-api">
  Confirm the authoritative auth status from your server.
</Card>
