{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","admonition","br","details","required"]},"type":"markdown"},"seo":{"title":"3DS transactions","description":"Transform your commerce with PXP's unified platform—seamless payments, real-time insights, and global growth in one powerful integration.","lang":"en-UK","siteUrl":"https://developer.pxp.io","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"3ds-transactions","__idx":0},"children":["3DS transactions"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Learn about 3D Secure authentication with Google Pay for enhanced transaction security."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["By implementing 3DS authentication with Google Pay on Android, you benefit from:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Enhanced security:"]}," Additional authentication layer protects against fraudulent transactions."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Liability shift:"]}," Shifts liability from merchant to card issuer for authenticated transactions."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Reduced chargebacks:"]}," Significantly decreases chargeback rates through strong authentication."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Regulatory compliance:"]}," Meets Strong Customer Authentication (SCA) requirements under PSD2 and similar regulations."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Higher success rate:"]}," Banks are more likely to approve 3DS-authenticated transactions."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Fraud prevention:"]}," Real-time risk assessment and challenge when necessary."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["However, the 3DS payment flow is longer than the non-3DS one due to the additional authentication steps. It may also require active customer participation if a challenge is presented."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["3D Secure authentication is strongly recommended for high-value transactions, subscription services, and any scenario where enhanced security is required. It significantly reduces fraud risk and chargebacks whilst providing liability shift benefits."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"payment-flow","__idx":2},"children":["Payment flow"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The 3DS Google Pay payment flow consists of nine key steps."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1-button-interaction","__idx":3},"children":["Step 1: Button interaction"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The customer taps the Google Pay button in your Android app, triggering the payment sheet to open. Google Pay handles device authentication (biometric or PIN) internally."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2-payment-method-selection","__idx":4},"children":["Step 2: Payment method selection"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Within the Google Pay payment sheet, the customer selects their preferred payment method. Google Pay tokenises the payment data using its secure tokenisation system."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-3-payment-sheet-completion","__idx":5},"children":["Step 3: Payment sheet completion"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The customer confirms the payment in the Google Pay sheet. The SDK receives the encrypted payment token from Google Pay."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-4-pre-initiation","__idx":6},"children":["Step 4: Pre-initiation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This is the initial step in the 3DS authentication flow. It establishes the authentication session by sending transaction and card details to the payment processor."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This step has two associated callbacks:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPreInitiateAuthentication"]},":"]}," Returns configuration for the authentication setup."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostInitiateAuthentication"]},":"]}," Receives the result of the pre-initiation call."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-5-fingerprinting","__idx":7},"children":["Step 5: Fingerprinting"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["During this step, device information and characteristics are collected by the fingerprinting component. The SDK gathers device data and submits transaction details to the issuer's fingerprint URL, enabling risk assessment based on the user's device profile."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-6-authentication","__idx":8},"children":["Step 6: Authentication"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The 3DS server evaluates the transaction risk and determines the authentication path:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Frictionless flow:"]}," If the transaction is low-risk, authentication completes automatically without customer interaction"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Challenge flow:"]}," If additional verification is needed, the customer completes the 3DS authentication challenge in a native Android dialog or WebView (PIN entry, SMS code, biometric verification, etc.)"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The authentication step has two associated callbacks:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPreAuthentication"]},":"]}," Configures the main authentication parameters."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostAuthentication"]},":"]}," Receives authentication results and challenge data."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-7-authentication-result","__idx":9},"children":["Step 7: Authentication result"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The SDK receives the 3DS authentication result indicating whether authentication was successful, failed, or requires additional action."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-8-authorisation","__idx":10},"children":["Step 8: Authorisation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This is the final processing step where the SDK sends the authorisation request to the payment gateway, including the 3DS authentication data. You receive the transaction data along with the 3DS authentication results and decide whether to proceed."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The authorisation step has two associated callbacks:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPreAuthorisation"]},":"]}," Provides final transaction data, including 3DS authentication results. This is your last chance to modify the transaction before authorisation."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostAuthorisation"]},":"]}," Receives the final transaction result from the payment gateway. The transaction is either approved or declined and final transaction details are available, along with 3DS authentication confirmation."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-9-authorisation-result","__idx":11},"children":["Step 9: Authorisation result"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You receive the final authorisation response from the payment gateway. The transaction is either approved or declined and final transaction details are available, along with 3DS authentication confirmation."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"implementation","__idx":12},"children":["Implementation"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"before-you-start","__idx":13},"children":["Before you start"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To use 3DS with Google Pay payments on Android:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Ensure 3D Secure is enabled in the Unity Portal for your merchant group."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Configure Google Pay in the Unity Portal with your gateway merchant ID."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Register your Android app package name and certificate in the Unity Portal."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Get your 3DS provider ID from your payment processor."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Ensure your app has the required permissions in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AndroidManifest.xml"]},"."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1-initialise-the-sdk","__idx":14},"children":["Step 1: Initialise the SDK"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Initialise the PXP Checkout SDK with your merchant credentials:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import com.pxp.PxpCheckout\nimport com.pxp.checkout.models.*\nimport java.text.SimpleDateFormat\nimport java.util.*\n\nclass PaymentActivity : ComponentActivity() {\n    \n    private lateinit var pxpCheckout: PxpCheckout\n    \n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        \n        // Fetch session from your secure backend\n        val sessionConfig = fetchSessionFromBackend()\n        \n        // Initialise SDK\n        pxpCheckout = PxpCheckout.builder()\n            .withConfig(\n                PxpSdkConfig(\n                    environment = Environment.TEST,\n                    session = sessionConfig,\n                    transactionData = TransactionData(\n                        currency = \"GBP\",\n                        amount = 299.99,\n                        merchant = \"YOUR_MERCHANT_ID\",\n                        merchantTransactionId = UUID.randomUUID().toString(),\n                        merchantTransactionDate = {\n                            SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss'Z'\", Locale.US).apply {\n                                timeZone = TimeZone.getTimeZone(\"UTC\")\n                            }.format(Date())\n                        },\n                        entryType = EntryType.Ecom,\n                        intent = TransactionIntentData(\n                            card = IntentType.Authorisation\n                        )\n                    ),\n                    ownerType = \"MerchantGroup\",\n                    ownerId = \"your-owner-id\"\n                )\n            )\n            .withContext(this)\n            .build()\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2-implement-callbacks","__idx":15},"children":["Step 2: Implement callbacks"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Configure the Google Pay button with the required callbacks for 3DS authentication:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import com.pxp.checkout.components.googlepay.*\nimport com.pxp.checkout.components.googlepay.types.*\nimport com.pxp.checkout.components.threeds.ChallengeWindowSize\nimport com.pxp.checkout.models.*\nimport com.pxp.checkout.services.kount.*\nimport com.pxp.checkout.services.models.authentication.*\n\nval googlePayConfig = GooglePayButtonComponentConfig().apply {\n    \n    // Payment request configuration\n    paymentDataRequest = PaymentDataRequest(\n        allowedPaymentMethods = listOf(\n            PaymentMethodSpecification(\n                parameters = PaymentMethodParameters(\n                    allowedCardNetworks = listOf(\n                        CardNetwork.VISA,\n                        CardNetwork.MASTERCARD,\n                        CardNetwork.AMEX\n                    ),\n                    // Prefer 3DS cryptogram authentication\n                    allowedAuthMethods = listOf(\n                        CardAuthMethod.CRYPTOGRAM_3DS\n                    )\n                )\n            )\n        ),\n        transactionInfo = TransactionInfo(\n            currencyCode = \"GBP\",\n            totalPriceStatus = TotalPriceStatus.FINAL,\n            totalPrice = \"299.99\"\n        )\n    )\n    \n    // RECOMMENDED: Use Unity authentication strategy\n    useUnityAuthenticationStrategy = true\n    \n    // REQUIRED: Provide 3DS pre-initiation configuration\n    onPreInitiateAuthentication = {\n        PreInitiateIntegratedAuthenticationData(\n            providerId = \"your_3ds_provider_id\", // Optional\n            requestorAuthenticationIndicator = RequestorAuthenticationIndicatorType.PAYMENT_TRANSACTION,\n            timeout = 300 // 5 minutes in seconds\n        )\n    }\n    \n    // OPTIONAL: Handle the pre-initiation result\n    onPostInitiateAuthentication = { result ->\n        when (result) {\n            is FailedAuthenticationResult -> {\n                Log.e(\"GooglePay3DS\", \"Pre-initiation failed: ${result.errorReason}\")\n            }\n            is MerchantAuthenticationResult -> {\n                Log.d(\"GooglePay3DS\", \"Pre-initiation complete: ${result.authenticationId}\")\n                Log.d(\"GooglePay3DS\", \"3DS supported: ${result.threeDSecureSupported}\")\n            }\n        }\n    }\n    \n    // REQUIRED: Configure main authentication\n    onPreAuthentication = suspend {\n        // This is a suspend function - no need for lifecycleScope.async\n        // Get authentication decision from backend\n        val decision = getAuthenticationDecision()\n        \n        if (decision == null) {\n            // Not proceeding with authentication\n            null\n        } else {\n            InitiateIntegratedAuthenticationData(\n                merchantCountryNumericCode = \"826\", // United Kingdom\n                merchantLegalName = \"Your Store Limited\",\n                challengeWindowSize = ChallengeWindowSize.FULL_SCREEN,\n                requestorChallengeIndicator = decision.challengeIndicator \n                    ?: RequestorChallengeIndicatorType.NO_PREFERENCE,\n                timeout = decision.timeout ?: 300\n            )\n        }\n    }\n    \n    // OPTIONAL: Handle the authentication result\n    onPostAuthentication = { data ->\n        Log.d(\"GooglePay3DS\", \"Authentication complete: ${data.authenticationId}\")\n        \n        // Note: This callback is not suspend, so use coroutine scope if needed\n        // Use lifecycleScope from your Activity or ViewModel context\n    }\n    \n    // REQUIRED: Final transaction review before authorisation\n    onPreAuthorisation = suspend { data ->\n        // This is a suspend function - no need for lifecycleScope.async\n        Log.d(\"GooglePay3DS\", \"Processing payment. Token: ${data?.gatewayTokenId}\")\n        \n        // Get authorisation decision from backend\n        val transactionDecision = getAuthorisationDecision(data?.gatewayTokenId)\n        \n        if (transactionDecision == null) {\n            null\n        } else {\n            // Return transaction data with risk screening\n            GooglePayTransactionInitData(\n                riskScreeningData = RiskScreeningData(\n                    performRiskScreening = true,\n                    excludeDeviceData = false,\n                    userIp = \"192.168.1.100\",\n                    account = RiskScreeningAccount(\n                        id = \"user_12345678\",\n                        creationDateTime = \"2024-01-15T10:30:00.000Z\"\n                    ),\n                    items = listOf(\n                        RiskScreeningItem(\n                            price = 299.99,\n                            quantity = 1,\n                            category = \"Electronics\",\n                            sku = \"GPAY-PROD-001\"\n                        )\n                    ),\n                    fulfillments = listOf(\n                        RiskScreeningFulfillment(\n                            type = FulfillmentType.SHIPPED,\n                            shipping = RiskScreeningShipping(\n                                shippingMethod = ShippingMethod.EXPRESS\n                            ),\n                            recipientPerson = RiskScreeningRecipientPerson(\n                                phoneNumber = \"+1234567890\",\n                                email = \"customer@example.com\"\n                            )\n                        )\n                    )\n                )\n            )\n        }\n    }\n    \n    // REQUIRED: Handle the final result\n    onPostAuthorisation = { result, paymentData ->\n        when (result) {\n            is MerchantSubmitResult -> {\n                // Success\n                Log.d(\"GooglePay3DS\", \"Payment successful!\")\n                Log.d(\"GooglePay3DS\", \"Merchant Txn: ${result.merchantTransactionId}\")\n                Log.d(\"GooglePay3DS\", \"System Txn: ${result.systemTransactionId}\")\n                \n                // Navigate to success screen\n                navigateToSuccess(result.merchantTransactionId)\n            }\n            is FailedSubmitResult -> {\n                // Failure\n                Log.e(\"GooglePay3DS\", \"Payment failed: ${result.errorReason}\")\n                showError(result.errorReason)\n            }\n        }\n    }\n    \n    // OPTIONAL: Handle errors\n    onError = { error ->\n        Log.e(\"GooglePay3DS\", \"Error: ${error.message}\", error)\n        showError(\"Payment error. Please try again.\")\n    }\n    \n    // OPTIONAL: Handle cancellation\n    onCancel = {\n        Log.d(\"GooglePay3DS\", \"Payment cancelled by user\")\n        showMessage(\"Payment cancelled\")\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-3-handle-common-scenarios","__idx":16},"children":["Step 3: Handle common scenarios"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"conditional-3ds","__idx":17},"children":["Conditional 3DS"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Only trigger 3DS authentication above a certain amount:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"val googlePayConfig = GooglePayButtonComponentConfig().apply {\n    // ... basic configuration\n    \n    onPreInitiateAuthentication = {\n        val amount = getTransactionAmount()\n        \n        if (amount > 100.0) {\n            PreInitiateIntegratedAuthenticationData(\n                providerId = \"your_provider\",\n                requestorAuthenticationIndicator = RequestorAuthenticationIndicatorType.PAYMENT_TRANSACTION,\n                timeout = 300\n            )\n        } else {\n            // Return null to skip 3DS for low-value transactions\n            null\n        }\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"challenge-indicator-selection","__idx":18},"children":["Challenge indicator selection"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Select appropriate challenge indicators based on transaction risk:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"fun selectChallengeIndicator(transaction: Transaction): RequestorChallengeIndicatorType {\n    return when {\n        // High-value transactions\n        transaction.amount > 500.0 -> {\n            RequestorChallengeIndicatorType.CHALLENGE_REQUESTED_MANDATE\n        }\n        \n        // Subscription first payment\n        transaction.type == TransactionType.SUBSCRIPTION && transaction.isFirstPayment -> {\n            RequestorChallengeIndicatorType.CHALLENGE_REQUESTED_3DS_REQUESTOR_PREFERENCE\n        }\n        \n        // Trusted returning customers\n        transaction.customerTrust == CustomerTrust.HIGH -> {\n            RequestorChallengeIndicatorType.NO_CHALLENGE_REQUESTED\n        }\n        \n        // Default\n        else -> RequestorChallengeIndicatorType.NO_PREFERENCE\n    }\n}\n\nval googlePayConfig = GooglePayButtonComponentConfig().apply {\n    // ... basic configuration\n    \n    onPreAuthentication = suspend {\n        val decision = getAuthenticationDecision()\n        \n        if (decision == null) {\n            null\n        } else {\n            val transaction = getCurrentTransaction()\n            val challengeIndicator = selectChallengeIndicator(transaction)\n            \n            InitiateIntegratedAuthenticationData(\n                merchantCountryNumericCode = \"826\",\n                merchantLegalName = \"Your Store Ltd\",\n                challengeWindowSize = ChallengeWindowSize.FULL_SCREEN,\n                requestorChallengeIndicator = challengeIndicator\n            )\n        }\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"soft-decline-retry","__idx":19},"children":["Soft decline retry"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Handle soft declines by retrying with forced 3DS challenge:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"val googlePayConfig = GooglePayButtonComponentConfig().apply {\n    // ... other configuration\n    \n    onPreRetrySoftDecline = { result ->\n        Log.d(\"GooglePay3DS\", \"Soft decline detected, retrying with 3DS challenge\")\n        \n        // Access result details based on result type\n        when (result) {\n            is RefusedSubmitResult -> {\n                // Track soft decline\n                trackEvent(\"payment-soft-decline\", mapOf(\n                    \"stateCode\" to result.stateData.code,\n                    \"stateMessage\" to result.stateData.message,\n                    \"providerCode\" to (result.providerResponse?.code ?: \"\")\n                ))\n            }\n            else -> {\n                Log.w(\"GooglePay3DS\", \"Unexpected result type for soft decline: ${result::class.simpleName}\")\n            }\n        }\n        \n        // Retry with forced 3DS challenge\n        GooglePayButtonComponentConfig.RetryConfiguration(\n            retry = true,\n            updatedConfigs = GooglePayButtonComponentConfig.RetryConfiguration.UpdatedConfigs(\n                onPreInitiateAuthentication = {\n                    PreInitiateIntegratedAuthenticationData(\n                        providerId = \"your_3ds_provider_id\",\n                        requestorAuthenticationIndicator = RequestorAuthenticationIndicatorType.PAYMENT_TRANSACTION,\n                        timeout = 300\n                    )\n                },\n                onPreAuthentication = suspend {\n                    InitiateIntegratedAuthenticationData(\n                        merchantCountryNumericCode = \"826\",\n                        merchantLegalName = \"Your Store Ltd\",\n                        challengeWindowSize = ChallengeWindowSize.FULL_SCREEN,\n                        // Force challenge on retry\n                        requestorChallengeIndicator = RequestorChallengeIndicatorType.CHALLENGE_REQUESTED_MANDATE\n                    )\n                }\n            )\n        )\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-4-handle-errors","__idx":20},"children":["Step 4: Handle errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement comprehensive error handling for 3DS payments:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"val googlePayConfig = GooglePayButtonComponentConfig().apply {\n    // ... basic configuration\n    \n    onPostAuthentication = { data ->\n        // Note: This is a non-suspend callback\n        // Use lifecycleScope from your Activity or ViewModel context if you need to call suspend functions\n        \n        Log.d(\"GooglePay3DS\", \"Authentication complete: ${data.authenticationId}\")\n        // Process authentication result or trigger backend calls\n    }\n    \n    onError = { error ->\n        Log.e(\"GooglePay3DS\", \"Payment error\", error)\n        \n        // Handle error\n        val errorMessage = \"Payment failed. Please try again or use a different payment method.\"\n        showError(errorMessage)\n    }\n    \n    onPostAuthorisation = { result, paymentData ->\n        when (result) {\n            is MerchantSubmitResult -> {\n                handlePaymentSuccess(result, paymentData)\n            }\n            is FailedSubmitResult -> {\n                handlePaymentFailure(result)\n            }\n        }\n    }\n}\n\nfun handlePaymentSuccess(result: MerchantSubmitResult, paymentData: AuthorisationPaymentData) {\n    Log.d(\"GooglePay3DS\", \"✅ Payment successful with 3DS\")\n    Log.d(\"GooglePay3DS\", \"Transaction ID: ${result.merchantTransactionId}\")\n    Log.d(\"GooglePay3DS\", \"System Transaction ID: ${result.systemTransactionId}\")\n    \n    // Store transaction details\n    storeTransactionRecord(\n        transactionId = result.merchantTransactionId,\n        systemTransactionId = result.systemTransactionId,\n        processingType = \"3ds\",\n        paymentMethod = \"google-pay\",\n        timestamp = System.currentTimeMillis()\n    )\n    \n    // Navigate to success page\n    navigateToSuccess(result.merchantTransactionId)\n}\n\nfun handlePaymentFailure(result: FailedSubmitResult) {\n    Log.e(\"GooglePay3DS\", \"❌ Payment failed\")\n    Log.e(\"GooglePay3DS\", \"Error code: ${result.errorCode}\")\n    Log.e(\"GooglePay3DS\", \"Error reason: ${result.errorReason}\")\n    Log.e(\"GooglePay3DS\", \"Correlation ID: ${result.correlationId}\")\n    \n    showError(\"Payment failed: ${result.errorReason}\")\n    \n    // Log for analysis\n    logPaymentDecline(\n        errorCode = result.errorCode,\n        errorReason = result.errorReason,\n        correlationId = result.correlationId,\n        httpStatusCode = result.httpStatusCode,\n        timestamp = System.currentTimeMillis()\n    )\n    \n    // Offer alternative payment methods\n    showAlternativePaymentOptions()\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"complete-example","__idx":21},"children":["Complete example"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following example shows a complete 3DS Google Pay implementation with Jetpack Compose:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import androidx.compose.foundation.layout.*\nimport androidx.compose.material3.*\nimport androidx.compose.runtime.*\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.unit.dp\nimport com.pxp.PxpCheckout\nimport com.pxp.checkout.components.googlepay.*\nimport com.pxp.checkout.components.googlepay.types.*\nimport com.pxp.checkout.components.threeds.ChallengeWindowSize\nimport com.pxp.checkout.models.*\nimport com.pxp.checkout.services.kount.*\nimport com.pxp.checkout.services.models.authentication.*\nimport com.pxp.checkout.types.ComponentType\nimport kotlinx.coroutines.launch\nimport java.util.*\n\n@Composable\nfun GooglePay3DSCheckout(\n    pxpCheckout: PxpCheckout,\n    amount: String,\n    onSuccess: (String) -> Unit,\n    onError: (String) -> Unit\n) {\n    var isProcessing by remember { mutableStateOf(false) }\n    var errorMessage by remember { mutableStateOf<String?>(null) }\n    val coroutineScope = rememberCoroutineScope()\n    \n    // Create Google Pay button component with 3DS\n    val googlePayComponent = remember {\n        pxpCheckout.createComponent<\n            GooglePayButtonComponent,\n            GooglePayButtonComponentConfig\n        >(\n            type = ComponentType.GOOGLE_PAY_BUTTON,\n            config = GooglePayButtonComponentConfig().apply {\n                \n                paymentDataRequest = PaymentDataRequest(\n                    allowedPaymentMethods = listOf(\n                        PaymentMethodSpecification(\n                            parameters = PaymentMethodParameters(\n                                allowedCardNetworks = listOf(\n                                    CardNetwork.VISA,\n                                    CardNetwork.MASTERCARD,\n                                    CardNetwork.AMEX\n                                ),\n                                allowedAuthMethods = listOf(\n                                    CardAuthMethod.CRYPTOGRAM_3DS\n                                )\n                            )\n                        )\n                    ),\n                    transactionInfo = TransactionInfo(\n                        currencyCode = \"GBP\",\n                        countryCode = \"GB\",\n                        totalPriceStatus = TotalPriceStatus.FINAL,\n                        totalPrice = amount\n                    )\n                )\n                \n                // Use Unity authentication strategy\n                useUnityAuthenticationStrategy = true\n                \n                // Step 1: Set up 3DS\n                onPreInitiateAuthentication = {\n                    Log.d(\"GooglePay3DS\", \"🔐 Initiating 3DS authentication\")\n                    PreInitiateIntegratedAuthenticationData(\n                        providerId = BuildConfig.THREEDS_PROVIDER_ID,\n                        requestorAuthenticationIndicator = RequestorAuthenticationIndicatorType.PAYMENT_TRANSACTION,\n                        timeout = 300\n                    )\n                }\n                \n                // Step 2: Handle pre-initiation result\n                onPostInitiateAuthentication = { result ->\n                    when (result) {\n                        is FailedAuthenticationResult -> {\n                            Log.e(\"GooglePay3DS\", \"Pre-initiation failed: ${result.errorReason}\")\n                        }\n                        is MerchantAuthenticationResult -> {\n                            Log.d(\"GooglePay3DS\", \"Pre-authentication check: ${result.authenticationId}\")\n                            Log.d(\"GooglePay3DS\", \"3DS supported: ${result.threeDSecureSupported}\")\n\n                            val authId = result.authenticationId ?: return@onPostInitiateAuthentication\n\n                            coroutineScope.launch {\n                                val authResult = fetchAuthenticationResultFromBackend(authId)\n                                evaluateAuthenticationAndUpdateSession(authResult)\n\n                                if (authResult.scaMandated) {\n                                    Log.d(\"GooglePay3DS\", \"SCA mandated - full authentication required\")\n                                }\n                            }\n                        }\n                    }\n                }\n                \n                // Step 3: Configure authentication\n                onPreAuthentication = suspend {\n                    Log.d(\"GooglePay3DS\", \"🔍 Configuring full 3DS authentication\")\n                    \n                    val decision = getAuthenticationDecision()\n                    \n                    if (decision == null) {\n                        null // Skip authentication\n                    } else {\n                        // Assess transaction risk\n                        val transactionAmount = amount.toDoubleOrNull() ?: 0.0\n                        val customerHistory = getCustomerHistory()\n                        val isHighRisk = transactionAmount > 500.0 || \n                            customerHistory.chargebacks > 0\n                        \n                        val challengeIndicator = when {\n                            isHighRisk -> RequestorChallengeIndicatorType.CHALLENGE_REQUESTED_MANDATE\n                            transactionAmount < 30.0 && \n                                customerHistory.successfulTransactions > 10 -> {\n                                RequestorChallengeIndicatorType.NO_CHALLENGE_REQUESTED\n                            }\n                            else -> RequestorChallengeIndicatorType.NO_PREFERENCE\n                        }\n                        \n                        InitiateIntegratedAuthenticationData(\n                            merchantCountryNumericCode = \"826\",\n                            merchantLegalName = \"Your Store Limited\",\n                            challengeWindowSize = ChallengeWindowSize.FULL_SCREEN,\n                            requestorChallengeIndicator = challengeIndicator\n                        )\n                    }\n                }\n                \n                // Step 4: Handle authentication result\n                onPostAuthentication = { data ->\n                    Log.d(\"GooglePay3DS\", \"✅ 3DS authentication completed: ${data.authenticationId}\")\n                    \n                    coroutineScope.launch {\n                        val authResult = fetchAuthenticationResultFromBackend(data.authenticationId)\n                        \n                        if (authResult.state == AuthenticationState.AUTHENTICATION_FAILED) {\n                            errorMessage = \"Card verification failed. Please try again.\"\n                            return@launch\n                        }\n                        \n                        evaluateAuthenticationAndUpdateAuthorization(authResult)\n                    }\n                }\n                \n                // Step 5: Final authorisation\n                onPreAuthorisation = suspend { data ->\n                    Log.d(\"GooglePay3DS\", \"💳 Processing payment with 3DS data\")\n                    \n                    val transactionDecision = getAuthorisationDecision(data?.gatewayTokenId)\n                    \n                    if (transactionDecision == null) {\n                        null\n                    } else {\n                        GooglePayTransactionInitData(\n                            riskScreeningData = RiskScreeningData(\n                                performRiskScreening = true,\n                                excludeDeviceData = false,\n                                userIp = \"192.168.1.100\",\n                                account = RiskScreeningAccount(\n                                    id = \"user_12345678\",\n                                    creationDateTime = \"2024-01-15T10:30:00.000Z\"\n                                ),\n                                items = listOf(\n                                    RiskScreeningItem(\n                                        price = 299.99,\n                                        quantity = 1,\n                                        category = \"Electronics\",\n                                        sku = \"GPAY-PROD-001\"\n                                    )\n                                ),\n                                fulfillments = listOf(\n                                    RiskScreeningFulfillment(\n                                        type = FulfillmentType.SHIPPED,\n                                        shipping = RiskScreeningShipping(\n                                            shippingMethod = ShippingMethod.EXPRESS\n                                        ),\n                                        recipientPerson = RiskScreeningRecipientPerson(\n                                            phoneNumber = \"+1234567890\",\n                                            email = \"customer@example.com\"\n                                        )\n                                    )\n                                )\n                            )\n                        )\n                    }\n                }\n                \n                // Step 6: Handle success/failure\n                onPostAuthorisation = { result, _ ->\n                    isProcessing = false\n                    \n                    when (result) {\n                        is MerchantSubmitResult -> {\n                            Log.d(\"GooglePay3DS\", \"✅ Payment authorised with 3DS\")\n                            onSuccess(result.merchantTransactionId)\n                        }\n                        is FailedSubmitResult -> {\n                            Log.e(\"GooglePay3DS\", \"❌ Payment declined: ${result.errorReason}\")\n                            errorMessage = \"Payment declined. Please try another payment method.\"\n                        }\n                    }\n                }\n                \n                // Step 7: Error handling\n                onError = { error ->\n                    Log.e(\"GooglePay3DS\", \"Error during 3DS flow\", error)\n                    isProcessing = false\n                    errorMessage = \"An error occurred. Please try again.\"\n                }\n                \n                onCancel = {\n                    Log.d(\"GooglePay3DS\", \"Payment cancelled by user\")\n                    isProcessing = false\n                    errorMessage = null\n                }\n            }\n        )\n    }\n    \n    // UI\n    Surface(\n        modifier = Modifier.fillMaxSize(),\n        color = MaterialTheme.colorScheme.background\n    ) {\n        Column(\n            modifier = Modifier\n                .fillMaxSize()\n                .padding(16.dp)\n        ) {\n            // Order summary\n            Card(\n                modifier = Modifier\n                    .fillMaxWidth()\n                    .padding(bottom = 24.dp)\n            ) {\n                Column(modifier = Modifier.padding(16.dp)) {\n                    Text(\n                        text = \"Order summary\",\n                        style = MaterialTheme.typography.titleLarge\n                    )\n                    \n                    Spacer(modifier = Modifier.height(16.dp))\n                    \n                    Row(\n                        modifier = Modifier.fillMaxWidth(),\n                        horizontalArrangement = Arrangement.SpaceBetween\n                    ) {\n                        Text(\"Premium Product\")\n                        Text(\"£$amount\")\n                    }\n                    \n                    Divider(modifier = Modifier.padding(vertical = 8.dp))\n                    \n                    Row(\n                        modifier = Modifier.fillMaxWidth(),\n                        horizontalArrangement = Arrangement.SpaceBetween\n                    ) {\n                        Text(\n                            text = \"Total\",\n                            style = MaterialTheme.typography.titleMedium\n                        )\n                        Text(\n                            text = \"£$amount\",\n                            style = MaterialTheme.typography.titleMedium\n                        )\n                    }\n                }\n            }\n            \n            // Payment section\n            Card(modifier = Modifier.fillMaxWidth()) {\n                Column(modifier = Modifier.padding(16.dp)) {\n                    Text(\n                        text = \"Pay with Google Pay (3DS Secure)\",\n                        style = MaterialTheme.typography.titleLarge\n                    )\n                    \n                    Spacer(modifier = Modifier.height(16.dp))\n                    \n                    // Error message\n                    errorMessage?.let { error ->\n                        Card(\n                            modifier = Modifier\n                                .fillMaxWidth()\n                                .padding(bottom = 16.dp),\n                            colors = CardDefaults.cardColors(\n                                containerColor = MaterialTheme.colorScheme.errorContainer\n                            )\n                        ) {\n                            Text(\n                                text = error,\n                                modifier = Modifier.padding(12.dp),\n                                color = MaterialTheme.colorScheme.onErrorContainer\n                            )\n                        }\n                    }\n                    \n                    // Google Pay button\n                    googlePayComponent?.Content(\n                        modifier = Modifier\n                            .fillMaxWidth()\n                            .height(56.dp)\n                    )\n                    \n                    // Processing indicator\n                    if (isProcessing) {\n                        LinearProgressIndicator(\n                            modifier = Modifier\n                                .fillMaxWidth()\n                                .padding(top = 16.dp)\n                        )\n                        \n                        Text(\n                            text = \"Processing secure payment...\",\n                            modifier = Modifier.padding(top = 8.dp),\n                            style = MaterialTheme.typography.bodyMedium,\n                            color = MaterialTheme.colorScheme.onSurfaceVariant\n                        )\n                    }\n                    \n                    Spacer(modifier = Modifier.height(16.dp))\n                    \n                    // Security info\n                    Column(\n                        modifier = Modifier.padding(vertical = 8.dp),\n                        verticalArrangement = Arrangement.spacedBy(4.dp)\n                    ) {\n                        Text(\n                            text = \"✓ Protected by 3D Secure authentication\",\n                            style = MaterialTheme.typography.bodySmall,\n                            color = MaterialTheme.colorScheme.onSurfaceVariant\n                        )\n                        Text(\n                            text = \"✓ Fast and secure checkout with Google Pay\",\n                            style = MaterialTheme.typography.bodySmall,\n                            color = MaterialTheme.colorScheme.onSurfaceVariant\n                        )\n                        Text(\n                            text = \"✓ Additional verification for your safety\",\n                            style = MaterialTheme.typography.bodySmall,\n                            color = MaterialTheme.colorScheme.onSurfaceVariant\n                        )\n                    }\n                }\n            }\n        }\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"callback-data","__idx":22},"children":["Callback data"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This section describes the data received by the different callbacks as part of the 3DS Google Pay flow on Android."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPreInitiateAuthentication"]}," callback doesn't receive any parameters. Instead, it returns your 3DS configuration in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PreInitiateIntegratedAuthenticationData"]}," object."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onpostinitiateauthentication","__idx":23},"children":["onPostInitiateAuthentication"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostInitiateAuthentication"]}," callback receives a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MerchantAuthenticationResult"]}," on success, or a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FailedAuthenticationResult"]}," on failure. On success, the SDK exposes two fields: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authenticationId"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["threeDSecureSupported"]},". Use the ID to retrieve full pre-initiate details from your backend."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When both ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authenticationId"]}," is absent and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["threeDSecureSupported"]}," is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]},", the SDK skips the remaining 3DS flow and doesn't invoke ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPreAuthentication"]},". This early-exit check applies when ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["useUnityAuthenticationStrategy"]}," is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]},". When ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["useUnityAuthenticationStrategy"]}," is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]},", the SDK uses Unity's authentication strategy API instead."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data","__idx":24},"children":["Event data"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Parameter"},"children":["Parameter"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["AuthenticationResult"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Authentication initiation result. Success is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MerchantAuthenticationResult"]},"; failure is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FailedAuthenticationResult"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.authenticationId"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The unique identifier for this 3DS session. May be null when 3DS isn't required. Use this ID to retrieve the full PreInitiateAuthentication result from the Unity backend."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.threeDSecureSupported"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["Boolean"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Whether 3DS authentication is supported for this transaction."]}]}]}]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authenticationId"]}," with the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/apis/three-d-secure-authentication/integrated-authentication/get-preinitiate-authentication-details"},"children":["Get 3DS pre-initiate authentication details"]}," API to retrieve pre-authentication results including SCA mandates, exemptions, and state."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation","__idx":25},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"// Within an Activity\nonPostInitiateAuthentication = { data ->\n    when (data) {\n        is FailedAuthenticationResult -> {\n            Log.e(\"GooglePay3DS\", \"3DS pre-initiation failed: ${data.errorReason}\")\n            return@onPostInitiateAuthentication\n        }\n        is MerchantAuthenticationResult -> {\n            Log.d(\"GooglePay3DS\", \"Authentication ID: ${data.authenticationId}\")\n            Log.d(\"GooglePay3DS\", \"3DS supported: ${data.threeDSecureSupported}\")\n\n            if (data.authenticationId.isNullOrEmpty() && !data.threeDSecureSupported) {\n                Log.d(\"GooglePay3DS\", \"3DS not supported — SDK skips authentication\")\n                return@onPostInitiateAuthentication\n            }\n\n            val authId = data.authenticationId ?: return@onPostInitiateAuthentication\n\n            lifecycleScope.launch {\n                val authResult = fetchAuthenticationResultFromBackend(authId)\n\n                when (authResult.state) {\n                    \"PendingClientData\" -> Log.d(\"GooglePay3DS\", \"Waiting for client data collection\")\n                    else -> Log.d(\"GooglePay3DS\", \"Authentication state: ${authResult.state}\")\n                }\n\n                if (authResult.scaMandated) {\n                    Log.d(\"GooglePay3DS\", \"SCA is required - 3DS must complete successfully\")\n                    showMessage(\"Additional verification required\")\n                }\n\n                when (authResult.applicableExemptions) {\n                    \"LVP\" -> Log.d(\"GooglePay3DS\", \"Low value exemption available\")\n                    \"TRA\" -> Log.d(\"GooglePay3DS\", \"Transaction risk analysis exemption available\")\n                }\n\n                evaluateAuthenticationAndUpdateSession(authResult)\n            }\n        }\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onpreauthentication","__idx":26},"children":["onPreAuthentication"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPreAuthentication"]}," callback receives no parameters. Return authentication configuration or null to skip."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-1","__idx":27},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onPreAuthentication = suspend {\n    // Get authentication decision evaluated after onPostInitiateAuthentication\n    val decision = getAuthenticationDecision()\n    \n    if (decision == null) {\n        // Not proceeding with authentication\n        Log.d(\"GooglePay3DS\", \"Skipping authentication based on backend decision\")\n        null\n    } else {\n        Log.d(\"GooglePay3DS\", \"Proceeding with authentication\")\n        \n        // Check if SCA is mandated to adjust challenge preference\n        val challengeIndicator = when {\n            decision.scaMandated -> {\n                Log.d(\"GooglePay3DS\", \"SCA mandated - requesting challenge\")\n                RequestorChallengeIndicatorType.CHALLENGE_REQUESTED_MANDATE\n            }\n            decision.applicableExemptions == \"LVP\" -> {\n                Log.d(\"GooglePay3DS\", \"Low value exemption - requesting no challenge\")\n                RequestorChallengeIndicatorType.NO_CHALLENGE_REQUESTED_LOW_VALUE_EXEMPTION\n            }\n            decision.applicableExemptions == \"TRA\" -> {\n                Log.d(\"GooglePay3DS\", \"TRA exemption - requesting no challenge\")\n                RequestorChallengeIndicatorType.NO_CHALLENGE_REQUESTED_TRANSACTION_RISK_ANALYSIS\n            }\n            else -> RequestorChallengeIndicatorType.NO_PREFERENCE\n        }\n        \n        InitiateIntegratedAuthenticationData(\n            merchantCountryNumericCode = \"826\",\n            merchantLegalName = \"Your Company Ltd\",\n            challengeWindowSize = ChallengeWindowSize.FULL_SCREEN,\n            requestorChallengeIndicator = challengeIndicator,\n            timeout = if (decision.scaMandated) 600 else 300\n        )\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"challenge-window-sizes","__idx":28},"children":["Challenge window sizes"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Value"},"children":["Value"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Dimensions"},"children":["Dimensions"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FULL_SCREEN"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Fullscreen"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Full-screen window (recommended for mobile)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IFRAME_250x400"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["250x400 px"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Compact window"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IFRAME_390x400"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["390x400 px"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Standard window"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IFRAME_500x600"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["500x600 px"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Medium window"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IFRAME_600x400"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["600x400 px"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Wide window"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"challenge-indicators","__idx":29},"children":["Challenge indicators"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Value"},"children":["Value"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"When to use"},"children":["When to use"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NO_PREFERENCE"]}," (01)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No preference"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Standard transactions"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NO_CHALLENGE_REQUESTED"]}," (02)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No challenge requested"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Low-risk transactions"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CHALLENGE_REQUESTED_3DS_REQUESTOR_PREFERENCE"]}," (03)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Challenge requested: Your preference"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When additional security desired"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CHALLENGE_REQUESTED_MANDATE"]}," (04)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Challenge requested: Mandate"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["High-value or high-risk transactions"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NO_CHALLENGE_REQUESTED_TRA_PERFORMED"]}," (05)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No challenge requested (transaction risk analysis performed)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When you have performed risk analysis"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NO_CHALLENGE_REQUESTED_LOW_VALUE_EXEMPTION"]}," (10)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No challenge requested (Low value exemption)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Low-value transactions under exemption thresholds"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onpostauthentication","__idx":30},"children":["onPostAuthentication"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostAuthentication"]}," callback receives only the authentication identifier."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-1","__idx":31},"children":["Event data"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Parameter"},"children":["Parameter"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["AuthenticationResult"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Authentication result containing authentication details."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.authenticationId"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The unique identifier for the authentication attempt. Use to retrieve full details from the Unity backend."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-2","__idx":32},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"// Within an Activity\nonPostAuthentication = { data ->\n    Log.d(\"GooglePay3DS\", \"3DS authentication completed: ${data.authenticationId}\")\n    \n    // Use lifecycleScope in Activity context\n    lifecycleScope.launch {\n        // Retrieve full authentication result from backend\n        val authResult = fetchAuthenticationResultFromBackend(data.authenticationId)\n        \n        Log.d(\"GooglePay3DS\", \"Authentication result: $authResult\")\n        \n        // Check transaction status\n        when (authResult.transactionStatus) {\n            \"Y\" -> {\n                Log.d(\"GooglePay3DS\", \"Authentication successful - no challenge needed\")\n                showMessage(\"Card verified successfully\")\n            }\n            \"C\" -> {\n                Log.d(\"GooglePay3DS\", \"Challenge completed - checking result...\")\n                if (authResult.state == \"AuthenticationSuccessful\") {\n                    Log.d(\"GooglePay3DS\", \"Challenge completed successfully\")\n                    showMessage(\"Verification completed\")\n                } else {\n                    Log.e(\"GooglePay3DS\", \"Challenge failed\")\n                    showError(\"Verification failed. Please try again.\")\n                    return@launch // Stop payment\n                }\n            }\n            \"N\" -> {\n                Log.e(\"GooglePay3DS\", \"Authentication failed\")\n                showError(\"Card verification failed\")\n                return@launch // Stop payment\n            }\n            \"R\" -> {\n                Log.e(\"GooglePay3DS\", \"Authentication rejected\")\n                showError(\"Payment was rejected by your bank\")\n                return@launch // Stop payment\n            }\n        }\n        \n        // Evaluate authentication result to update authorisation decision\n        evaluateAuthenticationAndUpdateAuthorization(authResult)\n        \n        Log.d(\"GooglePay3DS\", \"Proceeding to final authorisation...\")\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onpreauthorisation","__idx":33},"children":["onPreAuthorisation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPreAuthorisation"]}," callback receives only the gateway token ID."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-2","__idx":34},"children":["Event data"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Parameter"},"children":["Parameter"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["PreAuthorisationData?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Pre-authorisation data containing token identifiers."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.gatewayTokenId"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The gateway token identifier for the payment. Use this ID to retrieve full token details from the Unity backend."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-3","__idx":35},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onPreAuthorisation = suspend { data ->\n    Log.d(\"GooglePay3DS\", \"Pre-authorisation for token: ${data?.gatewayTokenId}\")\n    \n    // Retrieve token details and make authorisation decision\n    val transactionDecision = getAuthorisationDecision(data?.gatewayTokenId)\n    \n    if (transactionDecision == null) {\n        Log.d(\"GooglePay3DS\", \"Not proceeding with authorisation\")\n        null\n    } else {\n        // Perform pre-payment validation\n        val isHighRisk = checkCustomerRiskProfile()\n        val customerTier = getCustomerTier()\n        \n        GooglePayTransactionInitData(\n            riskScreeningData = RiskScreeningData(\n                performRiskScreening = true,\n                excludeDeviceData = false,\n                userIp = \"192.168.1.100\",\n                account = RiskScreeningAccount(\n                    id = \"user_12345678\",\n                    creationDateTime = \"2024-01-15T10:30:00.000Z\"\n                ),\n                items = listOf(\n                    RiskScreeningItem(\n                        price = 299.99,\n                        quantity = 1,\n                        category = \"Electronics\",\n                        sku = \"GPAY-PROD-001\"\n                    )\n                ),\n                fulfillments = listOf(\n                    RiskScreeningFulfillment(\n                        type = FulfillmentType.SHIPPED,\n                        shipping = RiskScreeningShipping(\n                            shippingMethod = ShippingMethod.EXPRESS\n                        ),\n                        recipientPerson = RiskScreeningRecipientPerson(\n                            phoneNumber = \"+1234567890\",\n                            email = \"customer@example.com\"\n                        )\n                    )\n                )\n            ),\n            psd2Data = GooglePayTransactionInitData.Psd2Data(\n                scaExemption = if (cartTotal < 30.0) {\n                    ScaExemptionType.LOW_VALUE\n                } else {\n                    ScaExemptionType.TRANSACTION_RISK_ANALYSIS\n                }\n            )\n        )\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onpostauthorisation","__idx":36},"children":["onPostAuthorisation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostAuthorisation"]}," callback receives the authorisation result and original payment data."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-3","__idx":37},"children":["Event data"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Parameter"},"children":["Parameter"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["SubmitResult?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Transaction result - either ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MerchantSubmitResult"]}," (success) or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FailedSubmitResult"]}," (failure)."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["paymentData"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["AuthorisationPaymentData"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Google Pay payment data collected during checkout (email, shipping address, shipping option)."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"success-result","__idx":38},"children":["Success result"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"data class MerchantSubmitResult(\n    val merchantTransactionId: String,\n    val systemTransactionId: String\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"failure-result","__idx":39},"children":["Failure result"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"data class FailedSubmitResult(\n    val errorCode: String,\n    val errorReason: String,\n    val correlationId: String,\n    val httpStatusCode: Int\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-4","__idx":40},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onPostAuthorisation = { result, paymentData ->\n    Log.d(\"GooglePay3DS\", \"3DS Google Pay payment result\")\n    \n    when (result) {\n        is MerchantSubmitResult -> {\n            // Success\n            Log.d(\"GooglePay3DS\", \"Payment successful with 3DS!\")\n            Log.d(\"GooglePay3DS\", \"Merchant Txn: ${result.merchantTransactionId}\")\n            Log.d(\"GooglePay3DS\", \"System Txn: ${result.systemTransactionId}\")\n            \n            // Store transaction details\n            storeTransactionRecord(\n                merchantTransactionId = result.merchantTransactionId,\n                systemTransactionId = result.systemTransactionId,\n                paymentMethod = \"google-pay\",\n                processingType = \"3ds\",\n                liabilityShift = true,\n                timestamp = System.currentTimeMillis()\n            )\n            \n            // Navigate to success page\n            navigateToSuccess(result.merchantTransactionId)\n        }\n        is FailedSubmitResult -> {\n            // Failure\n            Log.e(\"GooglePay3DS\", \"Payment failed\")\n            Log.e(\"GooglePay3DS\", \"Error code: ${result.errorCode}\")\n            Log.e(\"GooglePay3DS\", \"Error reason: ${result.errorReason}\")\n            Log.e(\"GooglePay3DS\", \"Correlation ID: ${result.correlationId}\")\n            \n            // Handle specific error types\n            handlePaymentFailure(result)\n        }\n    }\n}\n","lang":"kotlin"},"children":[]}]},"headings":[{"value":"3DS transactions","id":"3ds-transactions","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Payment flow","id":"payment-flow","depth":2},{"value":"Step 1: Button interaction","id":"step-1-button-interaction","depth":3},{"value":"Step 2: Payment method selection","id":"step-2-payment-method-selection","depth":3},{"value":"Step 3: Payment sheet completion","id":"step-3-payment-sheet-completion","depth":3},{"value":"Step 4: Pre-initiation","id":"step-4-pre-initiation","depth":3},{"value":"Step 5: Fingerprinting","id":"step-5-fingerprinting","depth":3},{"value":"Step 6: Authentication","id":"step-6-authentication","depth":3},{"value":"Step 7: Authentication result","id":"step-7-authentication-result","depth":3},{"value":"Step 8: Authorisation","id":"step-8-authorisation","depth":3},{"value":"Step 9: Authorisation result","id":"step-9-authorisation-result","depth":3},{"value":"Implementation","id":"implementation","depth":2},{"value":"Before you start","id":"before-you-start","depth":3},{"value":"Step 1: Initialise the SDK","id":"step-1-initialise-the-sdk","depth":3},{"value":"Step 2: Implement callbacks","id":"step-2-implement-callbacks","depth":3},{"value":"Step 3: Handle common scenarios","id":"step-3-handle-common-scenarios","depth":3},{"value":"Conditional 3DS","id":"conditional-3ds","depth":4},{"value":"Challenge indicator selection","id":"challenge-indicator-selection","depth":4},{"value":"Soft decline retry","id":"soft-decline-retry","depth":4},{"value":"Step 4: Handle errors","id":"step-4-handle-errors","depth":3},{"value":"Complete example","id":"complete-example","depth":3},{"value":"Callback data","id":"callback-data","depth":2},{"value":"onPostInitiateAuthentication","id":"onpostinitiateauthentication","depth":3},{"value":"Event data","id":"event-data","depth":4},{"value":"Example implementation","id":"example-implementation","depth":4},{"value":"onPreAuthentication","id":"onpreauthentication","depth":3},{"value":"Example implementation","id":"example-implementation-1","depth":4},{"value":"Challenge window sizes","id":"challenge-window-sizes","depth":4},{"value":"Challenge indicators","id":"challenge-indicators","depth":4},{"value":"onPostAuthentication","id":"onpostauthentication","depth":3},{"value":"Event data","id":"event-data-1","depth":4},{"value":"Example implementation","id":"example-implementation-2","depth":4},{"value":"onPreAuthorisation","id":"onpreauthorisation","depth":3},{"value":"Event data","id":"event-data-2","depth":4},{"value":"Example implementation","id":"example-implementation-3","depth":4},{"value":"onPostAuthorisation","id":"onpostauthorisation","depth":3},{"value":"Event data","id":"event-data-3","depth":4},{"value":"Success result","id":"success-result","depth":4},{"value":"Failure result","id":"failure-result","depth":4},{"value":"Example implementation","id":"example-implementation-4","depth":4}],"frontmatter":{"seo":{"title":"3DS transactions"}},"lastModified":"2026-07-10T12:27:32.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/components/android/google-pay/3ds","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}