diff --git a/demo-app-threeds/.gitignore b/demo-app-threeds/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/demo-app-threeds/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/demo-app-threeds/build.gradle b/demo-app-threeds/build.gradle
new file mode 100644
index 00000000..cb3ffce2
--- /dev/null
+++ b/demo-app-threeds/build.gradle
@@ -0,0 +1,41 @@
+plugins {
+ id 'com.android.application'
+ id 'org.jetbrains.kotlin.android'
+}
+
+android {
+ namespace 'io.hyperswitch.demo_app_threeds'
+ compileSdk 36
+
+ defaultConfig {
+ applicationId "io.hyperswitch.demo_app_threeds"
+ minSdk 24
+ targetSdk 36
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+}
+
+dependencies {
+ implementation (project(":hyperswitch-sdk-android-threeDS-trident"))
+ implementation (project(":hyperswitch-sdk-android-authentication"))
+
+ implementation("com.squareup.okhttp3:okhttp:4.12.0")
+
+
+ implementation libs.fuel
+ implementation libs.kotlin.coroutines
+ implementation libs.androidx.preference
+ implementation 'org.slf4j:slf4j-nop:2.0.17'
+ androidTestImplementation('com.wix:detox:+')
+}
\ No newline at end of file
diff --git a/demo-app-threeds/proguard-rules.pro b/demo-app-threeds/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/demo-app-threeds/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/demo-app-threeds/src/androidTest/java/io/hyperswitch/demo_app_threeds/ExampleInstrumentedTest.kt b/demo-app-threeds/src/androidTest/java/io/hyperswitch/demo_app_threeds/ExampleInstrumentedTest.kt
new file mode 100644
index 00000000..72b74d32
--- /dev/null
+++ b/demo-app-threeds/src/androidTest/java/io/hyperswitch/demo_app_threeds/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package io.hyperswitch.demo_app_threeds
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("io.hyperswitch.demo_app_threeds", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/demo-app-threeds/src/main/AndroidManifest.xml b/demo-app-threeds/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..aea25576
--- /dev/null
+++ b/demo-app-threeds/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo-app-threeds/src/main/java/io/hyperswitch/demo_app_threeds/MainActivity.kt b/demo-app-threeds/src/main/java/io/hyperswitch/demo_app_threeds/MainActivity.kt
new file mode 100644
index 00000000..47e1dd0c
--- /dev/null
+++ b/demo-app-threeds/src/main/java/io/hyperswitch/demo_app_threeds/MainActivity.kt
@@ -0,0 +1,538 @@
+package io.hyperswitch.demo_app_threeds
+
+import android.app.Activity
+import android.os.Bundle
+import android.util.Log
+import android.widget.Button
+import android.widget.TextView
+import io.hyperswitch.threeds.models.ThreeDSEnvironment
+import io.hyperswitch.threeds.api.*
+import io.hyperswitch.threeds.models.ChallengeParameters
+import io.hyperswitch.threeds.provider.ProviderRegistry
+import io.hyperswitch.threeds.trident.TridentProviderFactory
+import io.hyperswitch.authentication.AuthenticationSession
+import okhttp3.*
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.RequestBody.Companion.toRequestBody
+import org.json.JSONObject
+import java.io.IOException
+
+class MainActivity : Activity() {
+
+ private lateinit var statusText: TextView
+ private var publishKey: String = ""
+ private var paymentIntentClientSecret: String = ""
+
+ // New merchant-facing API objects
+ private lateinit var authenticationSession: AuthenticationSession
+ private var service: ThreeDSService? = null
+ private var transaction: ThreeDSTransaction? = null
+ private var aReqParams: AuthenticationRequestParameters? = null
+ private var challengeParameters: ChallengeParameters? = null
+
+
+ private val apiKey = ""
+ private val profileId = ""
+ private val baseUrl = ""
+ private var authenticationId: String? = null
+ // Eligibility response data
+ private var threeDsServerTransactionId: String? = null
+ private var messageVersion: String? = null
+ private var directoryServerId: String? = null
+
+ // HTTP client - use singleton to avoid creating multiple instances
+ private val httpClient by lazy {
+ OkHttpClient.Builder()
+ .connectTimeout(15, java.util.concurrent.TimeUnit.SECONDS)
+ .readTimeout(15, java.util.concurrent.TimeUnit.SECONDS)
+ .writeTimeout(15, java.util.concurrent.TimeUnit.SECONDS)
+ .build()
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ statusText = findViewById(R.id.statusText)
+
+ // Register providers for testing
+ ProviderRegistry.registerProvider(TridentProviderFactory())
+
+
+ authenticationSession = AuthenticationSession(
+ activity = this,
+ publishableKey = publishKey
+ )
+
+ setupButtons()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ // Clean up resources to prevent memory leaks
+ service = null
+ transaction = null
+ aReqParams = null
+ challengeParameters = null
+
+ Log.d("ThreeDSTest", "Cleared activity references")
+
+ // Cancel any pending HTTP calls
+ try {
+ httpClient.dispatcher.executorService.shutdown()
+ } catch (e: Exception) {
+ Log.w("ThreeDSTest", "Error shutting down HTTP client: ${e.message}")
+ }
+ }
+
+ private fun setupButtons() {
+ findViewById