Requirements

  • The compileSdk version should be 35.
  • The minimum SDK version supported by the SDK is 21.
  • The kotlin version should be 1.9.0 and above.
  • The gradle version should be 8.3.1 and above.

This is the new Headless authentication SDK that is significantly faster and more robust than the previous version. This upgrade enhances performance, reliability, and security, ensuring a seamless authentication experience, along with a seamless integration process. We strongly recommend migrating to the new SDK for improved efficiency and better support. To migrate from the old SDK, remove the previous SDK dependency and integration and follow the below mentioned steps.

Step 1: Add SDK Dependency

First, let’s add the OTPLESS SDK to your project. Update your app’s build.gradle file by adding the following dependency:

  implementation ("io.github.otpless-tech:otpless-headless-sdk:latest_version")

Please check the latest version of the SDK here. Make sure to synchronize your Gradle project to fetch the dependency.

Step 2: Update AndroidManifest.xml

Add this intent filter to your LoginActivity in AndroidManifest.xml:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.DEFAULT" />
    <data
        android:scheme="otpless.your_appid_in_lowercase"
        android:host="otpless" />
</intent-filter>

Replace YOUR_APP_ID with your actual App ID provided in your OTPLESS dashboard.

🔍 Example: If your App ID is “AcmeApp123”, scheme becomes otpless.acmeapp123

Additionally, ensure your activity is set to singleTop launch mode and that the exported attribute is true:

android:launchMode="singleTop"
android:exported="true"

Silent Network Authentication (SNA) Setup

  • Make sure that Silent Network Authentication is enabled on the OTPLESS dashboard.
  • Once you have successfully integrated OTPLESS Android SDK in your application, you only have to add the following line in your app’s AndroidManifest file in the <application> tag:
android:networkSecurityConfig="@xml/otpless_network_security_config"

Step 3: Add SDK Initialization

Import OtplessSDK in your LoginActivity.ktfile:

import com.otpless.v2.android.sdk.main.OtplessSDK;

initialize the SDK in your LoginActivity or LoginFragment depending upon your application architecture. In case of:

  • LoginActivity - Initialise the SDK in the onCreate() function
  • LoginFragment - Initialise the SDK in the onViewCreated() function.
OtplessSDK.initialize(appId = "YOUR_APPID", activity = activity)
OtplessSDK.setResponseCallback(this::onOtplessResponse)

Replace YOUR_APP_ID with your actual App ID provided in your OTPLESS dashboard.

Step 4: Handle Callback

Now, let’s implement a callback method to handle the response from the OTPLESS SDK:

private fun onOtplessResponse(response: OtplessResponse) {
    OtplessSDK.commit(response)
    when (response.responseType) {
        ResponseTypes.INITIATE -> {
            // notify that authentication has been initiated
             if (response.statusCode != 200) {
                handleInitiateError(response);
            }
        }
        ResponseTypes.VERIFY -> {
            // notify that verification has failed.
            handleVerifyError(response)
        }
        ResponseTypes.ONETAP -> {
            // final response with token
            val token = response.response?.optJSONObject("data")?.optString("token")
            if (!token.isNullOrBlank()) {
                // Process token and proceed.
            }
        }
        ResponseTypes.OTP_AUTO_READ -> {
            val otp = response.response?.optString("otp")
            if (!otp.isNullOrBlank()) {
                // Autofill the OTP in your TextField/EditText
            }
        }
        ResponseTypes.FALLBACK_TRIGGERED -> {
        // A fallback occurs when an OTP delivery attempt on one channel fails,  
        // and the system automatically retries via the subsequent channel selected on Otpless Dashboard.  
        // For example, if a merchant opts for SmartAuth with primary channal as WhatsApp and secondary channel as SMS,
        // in that case, if OTP delivery on WhatsApp fails, the system will automatically retry via SMS.
        // The response will contain the deliveryChannel to which the OTP has been sent.

        if (response.response != null) {
                val newDeliveryChannel = response.response.optString("deliveryChannel"); // This is the deliveryChannel to which the OTP has been sent
            }
        }
        ResponseTypes.SDK_READY -> {
            // SDK has been initialized successfully, you may enable your continue button or proceed with user authentication.
        }
        ResponseTypes.FAILED -> {
            // Notify that the initialization failed
            if (response.statusCode == 5003) {
                // SDK initialization failed, please try to initialize the SDK again
            }
        }
    }
}

Handle Initiate Error Response:

    private fun handleInitiateError(response: OtplessResponse) {
        val errorCode = response.response?.get("errorCode") as? String
        val errorMessage = response.response?.get("errorMessage") as? String

        when (errorCode) {
            "7101" -> {
                // Handle request error: Invalid parameters values or missing parameters
                println("OTPless Error: $errorMessage")
            }

            "7102" -> {
                // Handle request error: Invalid phone number
                println("OTPless Error: $errorMessage")
            }

            "7103" -> {
                // Handle request error: Invalid phone number delivery channel
                println("OTPless Error: $errorMessage")
            }

            "7104" -> {
                // Handle request error: Invalid email
                println("OTPless Error: $errorMessage")
            }

            "7105" -> {
                // Handle request error: Invalid email channel
                println("OTPless Error: $errorMessage")
            }

            "7106" -> {
                // Handle request error: Invalid phone number or email
                println("OTPless Error: $errorMessage")
            }

            "7113" -> {
                // Handle request error: Invalid expiry
                println("OTPless Error: $errorMessage")
            }

            "7116" -> {
                // Handle request error: OTP Length is invalid (4 or 6 only allowed)
                println("OTPless Error: $errorMessage")
            }

            "7121" -> {
                // Handle request error: Invalid app hash
                println("OTPless Error: $errorMessage")
            }

            "4000" -> {
                // Handle invalid request values
                println("OTPless Error: $errorMessage")
            }

            "4001" -> {
                // Handle unsupported 2FA request
                println("OTPless Error: $errorMessage")
            }

            "4003" -> {
                // Handle incorrect request channel
                println("OTPless Error: $errorMessage")
            }

            "401", "7025" -> {
                // Handle unauthorized request or country not enabled
                println("OTPless Error: $errorMessage")
            }

            "7020", "7022", "7023", "7024" -> {
                // Handle rate limiting errors (Too many requests)
                println("OTPless Error: $errorMessage")
            }

            "9002", "9003", "9004", "9005", "9006", "9007", "9008", "9009" -> {
                // Handle passkey authentication errors
                println("OTPless Error: $errorMessage")
            }

            "500" -> {
                // Handle unknown passkey error
                println("OTPless Error: $errorMessage")
            }

            "9100", "9104", "9103" -> {
                // Handle network connectivity errors
                println("OTPless Error: $errorMessage")
            }
        }
    }

Handle Verify Response

fun handleVerifyResponse(response: OtplessResponse) {
        val errorCode = response.response?.get("errorCode") as? String
        val errorMessage = response.response?.get("errorMessage") as? String

        when (errorCode) {
            "7112" -> {
                // Handle request error: Empty OTP
                println("OTPless Error: $errorMessage")
            }

            "7115" -> {
                // Handle request error: OTP is already verified
                println("OTPless Error: $errorMessage")
            }

            "7118" -> {
                // Handle request error: Incorrect OTP
                println("OTPless Error: $errorMessage")
            }

            "7303" -> {
                // Handle request error: OTP expired
                println("OTPless Error: $errorMessage")
            }

            "4000" -> {
                // Handle invalid request
                println("OTPless Error: $errorMessage")
            }

            "9100" -> {
                // Handle network error: Socket timeout exception
                println("OTPless Error: $errorMessage")
            }

            "9104" -> {
                // Handle network error: IO Exception occurred
                println("OTPless Error: $errorMessage")
            }

            "9103" -> {
                // Handle network error: Unknown Host Exception
                println("OTPless Error: $errorMessage")
            }

            else -> {
                // Handle unknown error
                println("OTPless Error: $errorMessage")
            }
        }
    }

Override onNewIntent()

override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    lifecycleScope.launch {
        OtplessSDK.onNewIntent(intent)
    }
}

Error Codes

Checkout error codes here

Step 5: Initiate Authentication

Well done! You have completed the foundational setup of the SDK. Now, let’s move to the next step and understand how to initiate and verify different authentication modes.

Choose the authentication mode you want to integrate from the options below:

Phone Authentication 📱
Phone authentication allows users to verify their identity using their phone number. Merchants can choose from various authentication methods:

  • Silent Authentication (SNA) – Automatically verifies the user without requiring OTP or MAGICLINK.
  • OTP on Desired Channel – Sends a one-time password (OTP) via SMS, WhatsApp, or another preferred channel.
  • Magic Link – Sends a link that users can click to authenticate.
  • SNA + OTP – Uses silent authentication first and falls back to OTP if needed.
  • OTP + Magic Link – Sends both an OTP and a magic link, allowing users to authenticate via either method.
final OtplessRequest otplessRequest = new OtplessRequest();
otplessRequest.setPhoneNumber("PHONE_NUMBER", "COUNTRY_CODE");
OtplessSDK.INSTANCE.startAsync(otplessRequest, this::onOtplessResponse);

Verify OTP

To verify the OTP entered by the user, use the verify method with the necessary parameters. Verifying OTP is required only in case of OTP authentication. No need to verify OTP in case of MAGICLINK.

final OtplessRequest otplessRequest = new OtplessRequest();
otplessRequest.setPhoneNumber("PHONE_NUMBER", "COUNTRY_CODE");
otplessRequest.setOtp("XXXXXX");
OtplessSDK.INSTANCE.startAsync(otplessRequest, this::onOtplessResponse);