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

# Flutter SDK

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

This page covers the **SNA-only** integration of the OTPless Headless SDK in Flutter. 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 |
| ------------------- | ------- |
| Android Minimum SDK | 21      |
| iOS                 | 13.0+   |

## Step 1: Add SDK dependency

Add the dependency to your `pubspec.yaml`:

```yaml pubspec.yaml theme={null}
dependencies:
  otpless_headless_flutter: ^<latest_version>
```

Then fetch it:

```bash theme={null}
flutter pub get
```

<Note>
  Check the latest version of the [SDK on pub.dev](https://pub.dev/packages/otpless_headless_flutter).
</Note>

## Step 2: Smart Authentication (SNA) setup

<Warning>
  Make sure **Silent Network Authentication** is enabled on the [OTPLESS dashboard](https://otpless.com/dashboard/customer/channels). For an SNA-only configuration, SNA must be the only channel enabled.
</Warning>

<Tabs>
  <Tab title="Android">
    1. Add the network security config inside `android/app/src/main/AndroidManifest.xml`, in your `<application>` tag:

    ```xml AndroidManifest.xml theme={null}
    android:networkSecurityConfig="@xml/otpless_network_security_config"
    ```

    2. If your `MainActivity` extends `FlutterActivity`, change it to extend `FlutterFragmentActivity` for lifecycle awareness:

    ```kotlin MainActivity.kt theme={null}
    import io.flutter.embedding.android.FlutterFragmentActivity

    class MainActivity : FlutterFragmentActivity() {
    }
    ```
  </Tab>

  <Tab title="iOS">
    Add the following block to your `ios/Runner/Info.plist`.

    * If the `NSAppTransportSecurity` key is **not** already present, add the entire block below.
    * If it **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>
    ```
  </Tab>
</Tabs>

## Step 3: Initialize the SDK

Create an `Otpless` instance, initialize it with your App ID, and register the response callback:

```dart theme={null}
import 'package:otpless_headless_flutter/otpless_flutter.dart';

final _otplessHeadlessPlugin = Otpless();

@override
void initState() {
    super.initState();
    _otplessHeadlessPlugin.initialize("YOUR_APP_ID");
    _otplessHeadlessPlugin.setResponseCallback(onOtplessResponse);
}
```

<Note>
  Replace `YOUR_APP_ID` with your actual App ID from the [OTPLESS dashboard](https://dashboard.otpless.com/login).
</Note>

## Step 4: Start SNA with the requestId

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

```dart theme={null}
final Map<String, dynamic> args = {
    "requestId": "REQUEST_ID_FROM_API"
};

_otplessHeadlessPlugin.start(onOtplessResponse, args);
```

<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 5: Handle callbacks

```dart theme={null}
void onOtplessResponse(dynamic response) {
    _otplessHeadlessPlugin.commitResponse(response);

    final responseType = response["responseType"];
    switch (responseType) {
        case "SDK_READY":
            // SDK initialized successfully — enable your continue button
            // or proceed with user authentication.
            break;
        case "FAILED":
            // SDK initialization failed
            if (response["statusCode"] == 5003) {
                // Please try to initialize the SDK again.
            }
            break;
        case "INITIATE":
            // Authentication has been initiated
            if (response["statusCode"] != 200) {
                handleInitiateError(response);
            } else if (response["response"]?["authType"] == "SILENT_AUTH") {
                // SNA is being attempted — show a loading state.
            }
            break;
        case "VERIFY":
            // Verification failed for the attempted authType.
            if (response["response"]?["authType"] == "SILENT_AUTH" && response["statusCode"] == 9106) {
                // SNA verification failed — treated as AUTH_TERMINATED.
            }
            break;
        case "ONETAP":
            // Final success response — returns token / idToken
            break;
        case "AUTH_TERMINATED":
            // SNA-only configuration: auth could not complete.
            // Emitted when pre-checks fail, or when SNA was attempted
            // and then failed. Treat as a terminal failure and rely on
            // the Status Check API for the exact error.
            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 you initialize the SDK (Step 3).

| 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()` (Step 4).

| Callback          | State                  | Meaning                                                                                                   |
| ----------------- | ---------------------- | --------------------------------------------------------------------------------------------------------- |
| `INITIATE`        | Non-terminal           | SNA is being attempted after pre-checks pass. `authType` is `SILENT_AUTH`.                                |
| `VERIFY`          | Non-terminal           | Verification failed for the attempted `authType` (e.g. `statusCode 9106` for `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. |

<Warning>
  In the SNA-only configuration `AUTH_TERMINATED` is a terminal failure with no fallback. Always treat the [Status Check API](/sna/status-check-api) result as authoritative. See [Handling the AUTH\_TERMINATED callback](/knowledge-base/sna/auth-terminated-callback).
</Warning>

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