{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","br","details","required","admonition"]},"type":"markdown"},"seo":{"title":"Events","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":"events","__idx":0},"children":["Events"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement callbacks to customise your Drop-in payment flow."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Drop-in provides a unified event system that works consistently across all payment methods. You can use these callbacks to inject your own business logic and user experience customisations into the payment flow at critical moments. They ensure that while the SDK handles the complex technical aspects of payment processing, you retain full control over the customer experience and can seamlessly integrate payments into your broader business workflows and systems."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Callbacks enable you to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Validate business rules before payments proceed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Display custom loading states and progress indicators."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Show user-friendly error messages."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track analytics and monitor payment performance."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Integrate with your own systems for fraud detection or customer management."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Implement card-on-file functionality for returning customers."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your callbacks receive normalised data regardless of whether the customer paid with cards, PayPal, or Google Pay."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All events are optional except ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]},", which are required for proper payment handling."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"supported-events","__idx":2},"children":["Supported events"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"ongetshopper","__idx":3},"children":["onGetShopper"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback provides shopper information for card-on-file functionality, allowing returning customers to use saved payment methods."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Provide shopper ID for logged-in users."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Generate anonymous shopper ID for guest checkout."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enable card-on-file for returning customers."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Associate payment methods with customer accounts."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data","__idx":4},"children":["Event data"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback receives no parameters and must return a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Shopper"]}," object."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"return-value","__idx":5},"children":["Return value"]},{"$$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":"Property"},"children":["Property"]},{"$$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":["id"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["A unique shopper identifier. Use customer ID for logged-in users or generate a unique ID for guests."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation","__idx":6},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onGetShopper = {\n    // For logged-in users, return their customer ID\n    val customerId = getCurrentCustomerId()\n    if (customerId != null) {\n        return@onGetShopper Shopper(id = customerId)\n    }\n    \n    // For guest users, generate or retrieve a session-based ID\n    val guestId = getOrCreateGuestId()\n    Shopper(id = guestId)\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The shopper ID is used to store and retrieve saved payment methods. For guests, generate a unique ID (e.g., UUID) that persists across the session. For registered users, use their customer/account ID from your system."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onbeforesubmit","__idx":7},"children":["onBeforeSubmit"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is triggered when a payment method is selected and the user is about to submit payment. This is your last chance to validate data or cancel the payment before it's processed."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Perform final validation before payment submission."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Check inventory availability."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify customer account status."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Display confirmation dialogs."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track analytics events."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Perform fraud checks."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-1","__idx":8},"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":["paymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["PaymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The selected payment method (Card, Paypal, or GooglePay)."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"return-value-1","__idx":9},"children":["Return value"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]}," or no return: Continue with payment submission."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]},": Cancel payment submission."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Suspend function: Async validation (resolved value determines whether to proceed)."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-1","__idx":10},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onBeforeSubmit = { paymentMethod ->\n    Log.d(\"CheckoutDropIn\", \"Payment method selected: $paymentMethod\")\n    \n    // Track analytics\n    analytics.track(\"payment_initiated\", mapOf(\n        \"payment_method\" to paymentMethod.toString(),\n        \"amount\" to 25.00\n    ))\n    \n    // Show confirmation for large amounts\n    if (amount > 100) {\n        val confirmed = showConfirmationDialog(\n            \"Confirm payment of $amount USD?\"\n        )\n        if (!confirmed) return@onBeforeSubmit false\n    }\n    \n    // Check inventory availability\n    val hasStock = checkInventory()\n    if (!hasStock) {\n        showToast(\"Some items are no longer available\")\n        return@onBeforeSubmit false\n    }\n    \n    true // Proceed with payment\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Simple validation example:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onBeforeSubmit = { paymentMethod ->\n    // Simple synchronous validation\n    if (!isValidOrder()) {\n        showToast(\"Please complete all required fields\")\n        return@onBeforeSubmit false // Payment won't proceed\n    }\n    \n    true // Payment will proceed\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onsubmit","__idx":11},"children":["onSubmit"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is triggered when payment processing begins, after ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onBeforeSubmit"]}," validation passes. Use this to show loading indicators and disable UI elements."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Show loading spinners or progress indicators."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Disable submit buttons to prevent double-submission."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Display \"Processing payment...\" messages."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Update UI to show payment is in progress."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track analytics for payment submission."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-2","__idx":12},"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":["paymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["PaymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The payment method being processed (Card, Paypal, or GooglePay)."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-2","__idx":13},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onSubmit = { paymentMethod ->\n    Log.d(\"CheckoutDropIn\", \"Processing payment with: $paymentMethod\")\n    \n    // Show loading overlay\n    showLoadingOverlay(true)\n    \n    // Disable submit button to prevent double-submission\n    disableSubmitButton()\n    \n    // Track analytics\n    analytics.track(\"payment_processing\", mapOf(\n        \"payment_method\" to paymentMethod.toString()\n    ))\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Complete loading state management:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"var loadingTimeout: Job? = null\n\nonSubmit = { paymentMethod ->\n    // Show loading state\n    setLoadingState(true)\n    \n    // Set timeout in case payment takes too long\n    loadingTimeout = lifecycleScope.launch {\n        delay(10000) // 10 seconds\n        showWarning(\"Payment is taking longer than expected. Please wait...\")\n    }\n    \n    // Track start time for performance monitoring\n    paymentStartTime = System.currentTimeMillis()\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onsuccess","__idx":14},"children":["onSuccess"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is triggered after payment succeeds. It receives the final transaction result from the payment processing system."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify payment on your backend (REQUIRED)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Redirect to success page after verification."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Display success messages."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track successful payment analytics."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Update stock levels for purchased items."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Send order confirmation emails to customers."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Clear shopping cart."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-3","__idx":15},"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":"Event data"},"children":["Event data"]},{"$$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":["DropInSubmitResult"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The payment processing result from PXP's backend."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.systemTransactionId"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Unity's system transaction identifier. Use for backend verification."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.merchantTransactionId"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your unique transaction identifier (optional)."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.authenticationId"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["3DS authentication identifier when authentication was performed."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.paymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["PaymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The payment method used.",{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},"Possible values:",{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod.CARD"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod.PAYPAL"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod.GOOGLE_PAY"]}]}]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.paymentData"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["AuthorisationPaymentData?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Google Pay only: Contains additional payment data including email, shipping address, and shipping option. This is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["null"]}," for card, PayPal, and other non-Google Pay methods."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DropInSubmitResult"]}," type:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"data class DropInSubmitResult(\n    val systemTransactionId: String,\n    val merchantTransactionId: String? = null,\n    val authenticationId: String? = null,\n    val paymentMethod: PaymentMethod,\n    val paymentData: AuthorisationPaymentData? = null\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"google-pay-payment-data","__idx":16},"children":["Google Pay payment data"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a payment is completed using Google Pay, the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.paymentData"]}," field contains additional information collected during the Google Pay flow:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"data class AuthorisationPaymentData(\n    val email: String? = null,\n    val shippingAddress: Map<String, String?>? = null,\n    val shippingOption: Map<String, String?>? = null\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["These fields are populated based on your Google Pay configuration:"]},{"$$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":"Field"},"children":["Field"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Populated when"},"children":["Populated when"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["email"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["emailRequired"]}," is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]}," in your Google Pay configuration."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["shippingAddress"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["shippingAddressRequired"]}," is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]}," in your Google Pay configuration."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["shippingOption"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Google Pay shipping options are configured and the user selects one."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Example handling Google Pay payment data:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onSuccess = { result ->\n    Log.d(\"Checkout\", \"Payment successful: ${result.systemTransactionId}\")\n    Log.d(\"Checkout\", \"Payment method: ${result.paymentMethod}\")\n    \n    // Check for Google Pay-specific data\n    if (result.paymentMethod == PaymentMethod.GOOGLE_PAY && result.paymentData != null) {\n        val paymentData = result.paymentData\n        \n        // Email address if requested\n        paymentData.email?.let { email ->\n            Log.d(\"Checkout\", \"Customer email: $email\")\n            // Use email for order confirmation\n        }\n        \n        // Shipping address if requested\n        paymentData.shippingAddress?.let { address ->\n            Log.d(\"Checkout\", \"Shipping address: $address\")\n            // Use address for order fulfillment\n        }\n        \n        // Shipping option if configured\n        paymentData.shippingOption?.let { option ->\n            Log.d(\"Checkout\", \"Shipping option: $option\")\n            // Use selected shipping method\n        }\n    }\n    \n    // CRITICAL: Verify on backend before fulfilling\n    verifyPaymentOnBackend(result)\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback is a frontend event and can be manipulated by malicious users. Never fulfil orders based solely on this callback. Always verify payments on your backend using Unity webhooks or the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/apis/transaction/other/get-transaction-details"},"children":["Get transaction details API"]}," before fulfilling orders."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-3","__idx":17},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onSuccess = { result ->\n    Log.d(\"CheckoutDropIn\", \"Payment successful (frontend notification only)\")\n    Log.d(\"CheckoutDropIn\", \"System transaction ID: ${result.systemTransactionId}\")\n    Log.d(\"CheckoutDropIn\", \"Merchant transaction ID: ${result.merchantTransactionId}\")\n    Log.d(\"CheckoutDropIn\", \"Payment method: ${result.paymentMethod}\")\n    \n    // Clear loading timeout if set\n    loadingTimeout?.cancel()\n    \n    // Hide loading overlay\n    setLoadingState(false)\n    \n    // Track analytics\n    val processingTime = System.currentTimeMillis() - paymentStartTime\n    analytics.track(\"payment_success_frontend\", mapOf(\n        \"system_transaction_id\" to result.systemTransactionId,\n        \"merchant_transaction_id\" to result.merchantTransactionId,\n        \"payment_method\" to result.paymentMethod.toString(),\n        \"processing_time\" to processingTime\n    ))\n    \n    // Show temporary success message\n    showMessage(\"Payment received! Verifying...\", MessageType.SUCCESS)\n    \n    // CRITICAL: Verify payment on backend before fulfilling order\n    lifecycleScope.launch {\n        try {\n            val verification = verifyPaymentOnBackend(\n                systemTransactionId = result.systemTransactionId,\n                merchantTransactionId = result.merchantTransactionId\n            )\n            \n            if (verification.success) {\n                // Payment verified on backend - safe to proceed\n                Log.d(\"CheckoutDropIn\", \"Payment verified on backend: ${verification.orderId}\")\n                \n                // Track backend verification success\n                analytics.track(\"payment_verified\", mapOf(\n                    \"order_id\" to verification.orderId,\n                    \"system_transaction_id\" to result.systemTransactionId\n                ))\n                \n                // Clear cart\n                clearShoppingCart()\n                \n                // Navigate to success page\n                navigateToOrderConfirmation(verification.orderId)\n            } else {\n                // Verification failed\n                Log.e(\"CheckoutDropIn\", \"Backend verification failed: ${verification.error}\")\n                \n                analytics.track(\"payment_verification_failed\", mapOf(\n                    \"system_transaction_id\" to result.systemTransactionId,\n                    \"error\" to verification.error\n                ))\n                \n                showError(\n                    \"Payment verification failed. Please contact support with \" +\n                    \"transaction ID: ${result.merchantTransactionId}\"\n                )\n            }\n        } catch (e: Exception) {\n            // Network or server error during verification\n            Log.e(\"CheckoutDropIn\", \"Failed to verify payment\", e)\n            \n            analytics.track(\"payment_verification_error\", mapOf(\n                \"system_transaction_id\" to result.systemTransactionId,\n                \"error\" to e.message\n            ))\n            \n            // Show error but don't clear cart (webhook may still process it)\n            showError(\n                \"Unable to verify payment. Your payment may still be processing. \" +\n                \"Please check your email for confirmation or contact support with \" +\n                \"transaction ID: ${result.merchantTransactionId}\"\n            )\n        }\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onerror","__idx":18},"children":["onError"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is triggered when an error occurs during the payment process."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Display user-friendly error messages."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Log errors for debugging and monitoring."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track failed payment analytics."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Offer alternative payment methods."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Provide retry options."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Hide loading indicators."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Re-enable form controls."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-4","__idx":19},"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":["error"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["BaseSdkException"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The error object containing details about what went wrong."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["A human-readable error message."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["SDK error code in format ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK####"]}," (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["'SDK1113'"]}," for authentication failed, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["'SDK0500'"]}," for network error). Use this for programmatic error handling."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BaseSdkException"]}," type:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"interface BaseSdkException {\n    val message: String\n    val code: String\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"common-error-scenarios","__idx":20},"children":["Common error scenarios"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following table shows common error scenarios and how to detect and respond to them:"]},{"$$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":"Scenario"},"children":["Scenario"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Detection approach"},"children":["Detection approach"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"User action"},"children":["User action"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Card declined"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"declined\" or specific provider messages"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Try a different card."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Insufficient funds"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"insufficient funds\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Use a different payment method."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Expired card"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"expired\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Use a different card."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Invalid CVV"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"CVV\" or \"security code\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Check security code."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["3DS authentication failed"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code == \"SDK1113\""]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"Authentication failed\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Try again or use different card."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["3DS timeout"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"timeout\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Check connection and retry."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["User cancelled 3DS"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"cancel\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Retry payment."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["PayPal error"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code == \"SDK1116\""]}," or payment method is PayPal"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Try again or use different method."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Session expired"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"session\" or \"expired\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Refresh page and retry."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Network error"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code == \"SDK0500\""]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Check connection and retry."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Configuration error"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code"]}," starts with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"SDK01\""]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"SDK02\""]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Contact support."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-4","__idx":21},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onError = { error ->\n    Log.e(\"CheckoutDropIn\", \"Payment failed\")\n    Log.e(\"CheckoutDropIn\", \"Error code: ${error.code}\")\n    Log.e(\"CheckoutDropIn\", \"Error message: ${error.message}\")\n    \n    // Clear loading timeout if set\n    loadingTimeout?.cancel()\n    \n    // Hide loading overlay\n    setLoadingState(false)\n    \n    // Re-enable submit button\n    enableSubmitButton()\n    \n    // Track error analytics\n    analytics.track(\"payment_failed\", mapOf(\n        \"error_code\" to error.code,\n        \"error_message\" to error.message\n    ))\n    \n    // Log error for monitoring\n    logErrorToMonitoring(\n        category = \"payment_error\",\n        code = error.code,\n        message = error.message,\n        userAgent = Build.MODEL\n    )\n    \n    // Show user-friendly error message based on error code and message\n    val userMessage = when {\n        // Check by SDK error code\n        error.code == \"SDK0500\" -> \n            \"Network connection issue. Please check your internet connection and try again.\"\n        error.code == \"SDK1113\" -> \n            \"3D Secure authentication failed. Please try again or use a different card.\"\n        error.code == \"SDK1115\" -> {\n            // Card payment failed - check message for specifics\n            when {\n                error.message.contains(\"declined\", ignoreCase = true) ->\n                    \"Your card was declined. Please try a different card or contact your bank for more information.\"\n                error.message.contains(\"insufficient funds\", ignoreCase = true) ->\n                    \"Insufficient funds. Please use a different payment method.\"\n                error.message.contains(\"expired\", ignoreCase = true) ->\n                    \"This card has expired. Please use a different card.\"\n                error.message.contains(\"cvv\", ignoreCase = true) || \n                error.message.contains(\"security code\", ignoreCase = true) ->\n                    \"Invalid security code. Please check the CVV on the back of your card and try again.\"\n                else ->\n                    \"Card payment failed. Please check your details and try again.\"\n            }\n        }\n        error.code == \"SDK1116\" ->\n            \"PayPal payment failed. Please try again or use a different payment method.\"\n        error.code == \"SDK1117\" ->\n            \"Google Pay payment failed. Please try again or use a different payment method.\"\n        error.message.contains(\"timeout\", ignoreCase = true) ->\n            \"Request timed out. Please check your internet connection and try again.\"\n        error.message.contains(\"session\", ignoreCase = true) || \n        error.message.contains(\"expired\", ignoreCase = true) ->\n            \"Your payment session has expired. Please refresh the page and try again.\"\n        else -> error.message\n    }\n    \n    showErrorMessage(userMessage)\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Error handling with retry logic:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"var retryCount = 0\nval MAX_RETRIES = 3\n\nonError = { error ->\n    // Check if error is retryable (network issues, timeouts)\n    val isNetworkError = error.code == \"SDK0500\"\n    val isTimeout = error.message.contains(\"timeout\", ignoreCase = true)\n    val isRetryable = isNetworkError || isTimeout\n    \n    if (isRetryable && retryCount < MAX_RETRIES) {\n        retryCount++\n        \n        Log.d(\"CheckoutDropIn\", \"Retryable error, attempt $retryCount/$MAX_RETRIES\")\n        \n        showMessage(\n            \"Connection issue. Attempt $retryCount/$MAX_RETRIES. Please try your payment again.\",\n            MessageType.WARNING\n        )\n    } else {\n        retryCount = 0 // Reset retry count\n        \n        if (isRetryable) {\n            showMessage(\n                \"Unable to process payment after multiple attempts. \" +\n                \"Please check your connection and try again later.\",\n                MessageType.ERROR\n            )\n        } else {\n            showMessage(\n                \"Payment failed: ${error.message}\",\n                MessageType.ERROR\n            )\n        }\n        \n        // Show alternative options for persistent failures\n        showAlternativePaymentMethods()\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"ongetconsent","__idx":22},"children":["onGetConsent"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback controls whether to show a consent checkbox for a specific payment method. This is typically used to get user permission to save payment information for future use (card-on-file)."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Show consent checkbox only for specific payment methods."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Comply with regulations requiring explicit consent for storing payment data."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Allow users to opt-in to card-on-file functionality."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Control consent display based on user type (guest vs registered)."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-5","__idx":23},"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":["paymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["PaymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The payment method being evaluated.",{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},"Possible values:",{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod.CARD"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod.PAYPAL"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod.GOOGLE_PAY"]}]}]}]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"return-value-2","__idx":24},"children":["Return value"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]},": Show consent checkbox for this payment method."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]},": Hide consent checkbox for this payment method."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-5","__idx":25},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"methodConfig = DropInMethodConfig(\n    global = DropInGlobalConfig(\n        // Control consent checkbox for card-on-file\n        onGetConsent = { paymentMethod ->\n            // Show consent for cards and PayPal, but not for wallet payments\n            paymentMethod == PaymentMethod.CARD || paymentMethod == PaymentMethod.PAYPAL\n        }\n    )\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Dynamic consent based on user type:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onGetConsent = { paymentMethod ->\n    // Only show consent for logged-in users\n    val isLoggedIn = checkUserLoginStatus()\n    \n    if (!isLoggedIn) {\n        return@onGetConsent false // Guest users can't save payment methods\n    }\n    \n    // Show consent for cards only\n    paymentMethod == PaymentMethod.CARD\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"oncancel","__idx":26},"children":["onCancel"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is triggered when a payment is cancelled by the user. This allows you to track cancellations, update UI, or perform cleanup operations."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track payment abandonment analytics."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Show user-friendly cancellation message."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Re-enable form fields or buttons."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Clear loading indicators."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Offer alternative payment methods."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Send abandonment emails for cart recovery."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-6","__idx":27},"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":["paymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["PaymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The payment method that was cancelled."]}]},{"$$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":["Any?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Additional cancellation data (varies by payment method)."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is triggered when:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["User closes PayPal popup without completing payment."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["User cancels Google Pay payment sheet."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["User closes 3D Secure authentication window."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["User explicitly cancels the payment flow."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-6","__idx":28},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"methodConfig = DropInMethodConfig(\n    global = DropInGlobalConfig(\n        onCancel = { paymentMethod, data ->\n            Log.d(\"CheckoutDropIn\", \"Payment cancelled: $paymentMethod\")\n            \n            // Track analytics\n            analytics.track(\"payment_cancelled\", mapOf(\n                \"method\" to paymentMethod.toString(),\n                \"timestamp\" to System.currentTimeMillis()\n            ))\n            \n            // Hide loading spinner\n            setIsProcessing(false)\n            \n            // Re-enable checkout button\n            setCheckoutButtonDisabled(false)\n            \n            // Show cancellation message\n            showNotification(\n                type = NotificationType.INFO,\n                message = \"$paymentMethod payment was cancelled. \" +\n                         \"Please try again or choose a different payment method.\"\n            )\n            \n            // Reset payment form\n            resetPaymentForm()\n        }\n    )\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"callback-execution-order","__idx":29},"children":["Callback execution order"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Understanding the callback flow helps you implement proper payment handling:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]},": initial setup"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Called during Drop-in initialisation."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Must return shopper ID for card-on-file functionality."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onBeforeSubmit"]},": validation phase"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["User selects payment method and clicks submit."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Return ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]}," to proceed, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]}," to cancel."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Perform business validation and fraud checks."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSubmit"]},": processing starts (if ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onBeforeSubmit"]}," returns ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]},")"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Show loading indicators."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Disable form fields."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track analytics."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]},": payment completes"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]},": payment succeeded (verify on backend before fulfilling)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]},": payment failed (show error message and offer alternatives)."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onCancel"]},": user cancels (optional)"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Triggered if user closes payment window/sheet."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Update UI and track analytics."]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"complete-integration-example","__idx":30},"children":["Complete integration example"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's a complete example showing all callbacks working together:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.ui.Modifier\nimport com.pxp.checkout.checkoutdropin.CheckoutDropIn\nimport com.pxp.checkout.checkoutdropin.types.*\nimport com.pxp.checkout.models.*\nimport java.time.Instant\nimport java.util.UUID\nimport kotlinx.coroutines.*\n\nvar loadingTimeout: Job? = null\nvar retryCount = 0\nconst val MAX_RETRIES = 3\n\nsuspend fun initializeCheckout(context: Context) {\n    // Get session from backend\n    val sessionData = fetchSessionFromBackend()\n    \n    // Initialise Drop-in with all callbacks\n    val checkoutDropIn = CheckoutDropIn.initialize(\n        context = context,\n        config = CheckoutDropInConfig(\n            environment = Environment.LIVE,\n            session = sessionData,\n            ownerType = \"MerchantGroup\",\n            ownerId = \"MERCHANT-1\",\n            transactionData = DropInTransactionData(\n                amount = 25.0,\n                currency = \"USD\",\n                entryType = EntryType.Ecom,\n                intent = DropInTransactionIntentData(\n                    card = IntentType.Authorisation,\n                    paypalDropInIntent = DropInPayPalIntentType.Authorisation\n                ),\n                merchant = \"MERCHANT-1\",\n                merchantTransactionId = UUID.randomUUID().toString(),\n                merchantTransactionDate = { Instant.now().toString() }\n            ),\n            kountDisabled = false, // OPTIONAL: Set to true to disable Kount fraud detection\n            \n            // Required: Get shopper information\n            onGetShopper = {\n                val customerId = getCurrentCustomerId()\n                Shopper(\n                    id = customerId ?: \"guest-${UUID.randomUUID()}\"\n                )\n            },\n            \n            // Before payment submission\n            onBeforeSubmit = { paymentMethod ->\n                Log.d(\"CheckoutDropIn\", \"Payment method selected: $paymentMethod\")\n                \n                // Track analytics\n                analytics.track(\"payment_initiated\", mapOf(\n                    \"payment_method\" to paymentMethod.toString(),\n                    \"amount\" to 25.00\n                ))\n                \n                // Show confirmation for large amounts\n                if (25.00 > 100) {\n                    val confirmed = showConfirmation(\n                        \"Confirm payment of 25.00 USD?\"\n                    )\n                    if (!confirmed) return@CheckoutDropInConfig false\n                }\n                \n                // Validate inventory\n                val hasStock = checkInventory()\n                if (!hasStock) {\n                    showToast(\"Some items are no longer available\")\n                    return@CheckoutDropInConfig false\n                }\n                \n                true // Proceed with payment\n            },\n            \n            // Payment processing started\n            onSubmit = { paymentMethod ->\n                Log.d(\"CheckoutDropIn\", \"Processing payment...\")\n                \n                // Show loading state\n                showLoadingOverlay(true)\n                disableSubmitButton()\n                \n                // Set timeout warning\n                loadingTimeout = lifecycleScope.launch {\n                    delay(10000)\n                    showMessage(\"Payment is taking longer than expected...\", MessageType.WARNING)\n                }\n                \n                // Track processing start\n                paymentStartTime = System.currentTimeMillis()\n                \n                analytics.track(\"payment_processing\", mapOf(\n                    \"payment_method\" to paymentMethod.toString()\n                ))\n            },\n            \n            // Payment succeeded (frontend notification)\n            onSuccess = { result ->\n                Log.d(\"CheckoutDropIn\", \"Payment successful (verifying on backend...)\")\n                \n                // Clear timeout\n                loadingTimeout?.cancel()\n                \n                // Calculate processing time\n                val processingTime = System.currentTimeMillis() - paymentStartTime\n                Log.d(\"CheckoutDropIn\", \"Payment processed in ${processingTime}ms\")\n                \n                // Track frontend success\n                analytics.track(\"payment_success_frontend\", mapOf(\n                    \"system_transaction_id\" to result.systemTransactionId,\n                    \"payment_method\" to result.paymentMethod.toString(),\n                    \"processing_time\" to processingTime\n                ))\n                \n                // Show verifying message\n                showMessage(\"Payment received! Verifying...\", MessageType.SUCCESS)\n                \n                // CRITICAL: Verify on backend\n                lifecycleScope.launch {\n                    try {\n                        val verified = verifyPaymentOnBackend(\n                            systemTransactionId = result.systemTransactionId,\n                            merchantTransactionId = result.merchantTransactionId\n                        )\n                        \n                        if (verified.success) {\n                            // Backend verification passed\n                            analytics.track(\"payment_verified\", mapOf(\n                                \"order_id\" to verified.orderId\n                            ))\n                            \n                            // Clear cart and redirect\n                            clearCart()\n                            navigateToSuccess(verified.orderId)\n                        } else {\n                            throw Exception(verified.error ?: \"Verification failed\")\n                        }\n                    } catch (e: Exception) {\n                        Log.e(\"CheckoutDropIn\", \"Verification error\", e)\n                        showLoadingOverlay(false)\n                        showError(\n                            \"Payment verification failed. Please contact support with \" +\n                            \"transaction ID: ${result.merchantTransactionId}\"\n                        )\n                    }\n                }\n            },\n            \n            // Payment failed\n            onError = { error ->\n                Log.e(\"CheckoutDropIn\", \"Payment failed: ${error.code}\")\n                Log.e(\"CheckoutDropIn\", \"Error message: ${error.message}\")\n                \n                // Clear timeout\n                loadingTimeout?.cancel()\n                \n                // Hide loading state\n                showLoadingOverlay(false)\n                enableSubmitButton()\n                \n                // Track error\n                analytics.track(\"payment_failed\", mapOf(\n                    \"error_code\" to error.code,\n                    \"error_message\" to error.message\n                ))\n                \n                // Log for monitoring\n                logError(error)\n                \n                // Handle retryable errors\n                val isNetworkError = error.code == \"SDK0500\"\n                val isTimeout = error.message.contains(\"timeout\", ignoreCase = true)\n                if ((isNetworkError || isTimeout) && retryCount < MAX_RETRIES) {\n                    retryCount++\n                    showMessage(\n                        \"Connection issue (attempt $retryCount/$MAX_RETRIES). Please try again.\",\n                        MessageType.WARNING\n                    )\n                    return@CheckoutDropInConfig\n                }\n                \n                retryCount = 0 // Reset\n                \n                // Show user-friendly error\n                val userMessage = when {\n                    error.code == \"SDK1113\" ->\n                        \"3D Secure authentication failed.\"\n                    error.code == \"SDK1115\" ->\n                        \"Card payment failed.\"\n                    error.code == \"SDK1116\" ->\n                        \"PayPal payment failed.\"\n                    error.message.contains(\"declined\", ignoreCase = true) ->\n                        \"Card declined. Please try a different card.\"\n                    error.message.contains(\"insufficient funds\", ignoreCase = true) ->\n                        \"Insufficient funds. Please use a different payment method.\"\n                    error.message.contains(\"expired\", ignoreCase = true) ->\n                        \"This card has expired.\"\n                    error.message.contains(\"cvv\", ignoreCase = true) ->\n                        \"Invalid security code.\"\n                    else -> \"Payment failed. Please try again.\"\n                }\n                \n                showErrorMessage(userMessage)\n                \n                // Offer alternatives for card issues\n                if (error.code == \"SDK1115\" || \n                    error.message.contains(\"card\", ignoreCase = true)) {\n                    showAlternativePaymentMethods()\n                }\n            },\n            \n            // Method-specific configuration\n            methodConfig = DropInMethodConfig(\n                global = DropInGlobalConfig(\n                    // Control consent checkbox\n                    onGetConsent = { paymentMethod ->\n                        // Show consent for cards and PayPal\n                        paymentMethod == PaymentMethod.CARD || \n                        paymentMethod == PaymentMethod.PAYPAL\n                    },\n                    \n                    // Handle cancellation\n                    onCancel = { paymentMethod, data ->\n                        Log.d(\"CheckoutDropIn\", \"Payment cancelled: $paymentMethod\")\n                        \n                        // Clear timeout\n                        loadingTimeout?.cancel()\n                        \n                        // Hide loading\n                        showLoadingOverlay(false)\n                        enableSubmitButton()\n                        \n                        // Track cancellation\n                        analytics.track(\"payment_cancelled\", mapOf(\n                            \"payment_method\" to paymentMethod.toString()\n                        ))\n                        \n                        showMessage(\"Payment was cancelled. Please try again.\", MessageType.INFO)\n                    }\n                )\n            )\n        )\n    )\n    \n    // Create component\n    val component = checkoutDropIn.create()\n    \n    // Render in Compose\n    component.Content(modifier = Modifier.fillMaxWidth())\n}\n","lang":"kotlin"},"children":[]}]},"headings":[{"value":"Events","id":"events","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Supported events","id":"supported-events","depth":2},{"value":"onGetShopper","id":"ongetshopper","depth":3},{"value":"Event data","id":"event-data","depth":4},{"value":"Return value","id":"return-value","depth":4},{"value":"Example implementation","id":"example-implementation","depth":4},{"value":"onBeforeSubmit","id":"onbeforesubmit","depth":3},{"value":"Event data","id":"event-data-1","depth":4},{"value":"Return value","id":"return-value-1","depth":4},{"value":"Example implementation","id":"example-implementation-1","depth":4},{"value":"onSubmit","id":"onsubmit","depth":3},{"value":"Event data","id":"event-data-2","depth":4},{"value":"Example implementation","id":"example-implementation-2","depth":4},{"value":"onSuccess","id":"onsuccess","depth":3},{"value":"Event data","id":"event-data-3","depth":4},{"value":"Google Pay payment data","id":"google-pay-payment-data","depth":4},{"value":"Example implementation","id":"example-implementation-3","depth":4},{"value":"onError","id":"onerror","depth":3},{"value":"Event data","id":"event-data-4","depth":4},{"value":"Common error scenarios","id":"common-error-scenarios","depth":4},{"value":"Example implementation","id":"example-implementation-4","depth":4},{"value":"onGetConsent","id":"ongetconsent","depth":3},{"value":"Event data","id":"event-data-5","depth":4},{"value":"Return value","id":"return-value-2","depth":4},{"value":"Example implementation","id":"example-implementation-5","depth":4},{"value":"onCancel","id":"oncancel","depth":3},{"value":"Event data","id":"event-data-6","depth":4},{"value":"Example implementation","id":"example-implementation-6","depth":4},{"value":"Callback execution order","id":"callback-execution-order","depth":2},{"value":"Complete integration example","id":"complete-integration-example","depth":2}],"frontmatter":{"seo":{"title":"Events"}},"lastModified":"2026-05-21T11:24:56.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/drop-in/android/events","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}