Process Google Pay transactions without 3D Secure authentication for faster, streamlined checkout.
By implementing a non-3DS Google Pay payment flow on Android, you benefit from:
- Faster checkout: Streamlined payment process with fewer steps and no authentication redirects.
- Better conversion: Reduced friction leads to higher completion rates.
- Simplified integration: Fewer callbacks and less complex implementation.
- Lower latency: Direct payment processing without authentication steps.
- Native security: Benefits from Google Pay's tokenisation and biometric authentication.
However, non-3DS payments may not qualify for liability shift protection and are best suited for low-risk transactions, trusted customers, or regions where Strong Customer Authentication (SCA) isn't mandated.
Google Pay provides inherent security through device-based authentication (fingerprint, face recognition, or PIN) and payment tokenisation, making non-3DS flows suitable for many transaction types.
The non-3DS Google Pay payment flow consists of five streamlined steps:
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.
Within the Google Pay payment sheet, the customer selects their preferred payment method. Google Pay tokenises the payment data using its secure tokenisation system.
The customer confirms the payment in the Google Pay sheet. The SDK receives the encrypted payment token from Google Pay.
The SDK evaluates whether 3DS authentication is required. In non-3DS flows, authentication is skipped based on:
- Configuration not requiring 3DS (no
onPreInitiateAuthenticationcallback provided). - Transaction falling below risk thresholds.
- Regulatory exemptions being applicable.
- Merchant risk assessment.
Since 3DS isn't required, the flow proceeds directly to authorisation.
The SDK sends the authorisation request with the Google Pay token directly to the payment gateway without 3DS authentication data.
onPreAuthorisation: Provides transaction data for final review before authorisation. This is your last opportunity to add additional data or cancel the transaction.onPostAuthorisation: Receives the final transaction result. The transaction is either authorised or declined.
To use non-3DS Google Pay payments on Android:
- Ensure your merchant account supports non-3DS transactions.
- Configure Google Pay in the Unity Portal with your gateway merchant ID.
- Register your Android app package name and certificate in the Unity Portal.
- Consider implementing additional fraud prevention measures.
Initialise the PXP Checkout SDK with your merchant credentials:
import com.pxp.PxpCheckout
import com.pxp.checkout.models.*
import java.text.SimpleDateFormat
import java.util.*
val pxpCheckout = PxpCheckout.builder()
.withConfig(
PxpSdkConfig(
environment = Environment.TEST,
session = sessionData,
ownerId = "your-owner-id",
ownerType = "MerchantGroup",
transactionData = TransactionData(
currency = "GBP",
amount = 25.00,
merchantTransactionId = UUID.randomUUID().toString(),
merchantTransactionDate = { SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date()) },
entryType = EntryType.Ecom,
intent = TransactionIntentData(
card = IntentType.Authorisation
),
merchant = "Merchant Name"
)
)
)
.withContext(context)
.build()Configure the Google Pay button with the required callbacks for non-3DS payments:
import com.pxp.checkout.components.googlepay.*
import com.pxp.checkout.components.googlepay.types.*
import com.pxp.checkout.models.*
import com.pxp.checkout.services.kount.*
val googlePayConfig = GooglePayButtonComponentConfig().apply {
paymentDataRequest = PaymentDataRequest(
allowedPaymentMethods = listOf(
PaymentMethodSpecification(
parameters = PaymentMethodParameters(
allowedCardNetworks = listOf(
CardNetwork.VISA,
CardNetwork.MASTERCARD,
CardNetwork.AMEX
),
// Both methods supported - Google Pay will use best available
allowedAuthMethods = listOf(
CardAuthMethod.PAN_ONLY,
CardAuthMethod.CRYPTOGRAM_3DS
)
)
)
),
transactionInfo = TransactionInfo(
currencyCode = "GBP",
totalPriceStatus = TotalPriceStatus.FINAL,
totalPrice = "49.99"
)
)
// REQUIRED: Final transaction review before authorisation
onPreAuthorisation = suspend { data ->
Log.d("GooglePay", "Processing non-3DS payment")
Log.d("GooglePay", "Gateway Token ID: ${data?.gatewayTokenId}")
// Add risk screening data
GooglePayTransactionInitData(
riskScreeningData = RiskScreeningData(
performRiskScreening = true,
excludeDeviceData = false,
userIp = "192.168.1.100",
account = RiskScreeningAccount(
id = "user_12345678",
creationDateTime = "2024-01-15T10:30:00.000Z"
),
items = listOf(
RiskScreeningItem(
price = 99.99,
quantity = 1,
category = "Electronics",
sku = "GPAY-PROD-001"
)
),
fulfillments = listOf(
RiskScreeningFulfillment(
type = FulfillmentType.SHIPPED,
shipping = RiskScreeningShipping(
shippingMethod = ShippingMethod.STANDARD
),
recipientPerson = RiskScreeningRecipientPerson(
phoneNumber = "+1234567890",
email = "customer@example.com"
)
)
)
)
)
}
// REQUIRED: Handle the final result
onPostAuthorisation = { result, paymentData ->
Log.d("GooglePay", "Payment result: $result")
when (result) {
is MerchantSubmitResult -> {
// Success
Log.d("GooglePay", "Payment successful!")
Log.d("GooglePay", "Transaction ID: ${result.merchantTransactionId}")
Log.d("GooglePay", "System Txn ID: ${result.systemTransactionId}")
// Navigate to success screen
navigateToSuccess(result.merchantTransactionId)
}
is FailedSubmitResult -> {
// Failure
Log.e("GooglePay", "Payment declined: ${result.errorReason}")
showError("Payment declined. Please try another payment method.")
}
}
}
// OPTIONAL: Handle errors
onError = { error ->
Log.e("GooglePay", "Payment error", error)
showError("An error occurred. Please try again.")
}
// OPTIONAL: Handle cancellation
onCancel = {
Log.d("GooglePay", "Payment cancelled by user")
showMessage("Payment cancelled")
}
}Apply different risk measures based on transaction amounts:
val googlePayConfig = GooglePayButtonComponentConfig().apply {
// ... basic configuration
onPreAuthorisation = suspend { data ->
Log.d("GooglePay", "Gateway Token ID: ${data?.gatewayTokenId}")
// Get transaction amount
val amount = getTransactionAmount().toDoubleOrNull() ?: 0.0
// Different handling based on amount
when {
amount < 30.0 -> {
// Low-value transaction - minimal checks
Log.d("GooglePay", "Low-value transaction: $amount")
GooglePayTransactionInitData(
riskScreeningData = RiskScreeningData(
performRiskScreening = false,
excludeDeviceData = true
)
)
}
amount < 100.0 -> {
// Medium-value transaction - standard checks
Log.d("GooglePay", "Medium-value transaction: $amount")
GooglePayTransactionInitData(
riskScreeningData = RiskScreeningData(
performRiskScreening = true,
excludeDeviceData = false,
userIp = "192.168.1.100",
account = RiskScreeningAccount(
id = "user_12345678",
creationDateTime = "2024-01-15T10:30:00.000Z"
),
fulfillments = listOf(
RiskScreeningFulfillment(
type = FulfillmentType.SHIPPED,
shipping = RiskScreeningShipping(
shippingMethod = ShippingMethod.STANDARD
),
recipientPerson = RiskScreeningRecipientPerson(
phoneNumber = "+1234567890"
)
)
)
)
)
}
else -> {
// High-value transaction - enhanced checks
Log.d("GooglePay", "High-value transaction: $amount")
GooglePayTransactionInitData(
riskScreeningData = RiskScreeningData(
performRiskScreening = true,
excludeDeviceData = false,
userIp = "192.168.1.100",
account = RiskScreeningAccount(
id = "user_12345678",
creationDateTime = "2024-01-15T10:30:00.000Z"
),
items = listOf(
RiskScreeningItem(
price = amount,
quantity = 1,
category = "high-value"
)
),
fulfillments = listOf(
RiskScreeningFulfillment(
type = FulfillmentType.SHIPPED,
shipping = RiskScreeningShipping(
shippingMethod = ShippingMethod.EXPRESS
),
recipientPerson = RiskScreeningRecipientPerson(
phoneNumber = "+1234567890"
)
)
)
)
)
}
}
}
}Handle different customer types with varying risk profiles:
data class CustomerRiskProfile(
val level: RiskLevel,
val verification: VerificationLevel,
val reason: String
)
enum class RiskLevel { HIGH, MEDIUM, LOW }
enum class VerificationLevel { ENHANCED, STANDARD, MINIMAL }
fun getCustomerRiskProfile(customerId: String): CustomerRiskProfile {
val customer = getCustomerDetails(customerId)
return when {
customer.previousOrders == 0 -> {
CustomerRiskProfile(
level = RiskLevel.HIGH,
verification = VerificationLevel.ENHANCED,
reason = "new-customer"
)
}
customer.previousOrders > 10 && customer.chargebacks == 0 -> {
CustomerRiskProfile(
level = RiskLevel.LOW,
verification = VerificationLevel.MINIMAL,
reason = "trusted-customer"
)
}
else -> {
CustomerRiskProfile(
level = RiskLevel.MEDIUM,
verification = VerificationLevel.STANDARD,
reason = "returning-customer"
)
}
}
}
val googlePayConfig = GooglePayButtonComponentConfig().apply {
// ... basic configuration
onPreAuthorisation = suspend { data ->
val customerId = getCurrentCustomerId()
val riskProfile = getCustomerRiskProfile(customerId)
Log.d("GooglePay", "Customer risk profile: $riskProfile")
GooglePayTransactionInitData(
riskScreeningData = RiskScreeningData(
performRiskScreening = riskProfile.level != RiskLevel.LOW,
excludeDeviceData = false,
userIp = "192.168.1.100",
account = RiskScreeningAccount(
id = customerId,
creationDateTime = "2024-01-15T10:30:00.000Z"
),
fulfillments = listOf(
RiskScreeningFulfillment(
type = FulfillmentType.SHIPPED,
recipientPerson = RiskScreeningRecipientPerson(
phoneNumber = "+1234567890"
)
)
)
)
)
}
}Apply different rules based on customer location:
suspend fun getCustomerGeolocation(): Geolocation {
// Implement geolocation detection
return Geolocation(
countryCode = "GB",
region = "England",
city = "London"
)
}
data class Geolocation(
val countryCode: String,
val region: String,
val city: String
)
val googlePayConfig = GooglePayButtonComponentConfig().apply {
// ... basic configuration
onPreAuthorisation = suspend { data ->
Log.d("GooglePay", "Gateway Token ID: ${data?.gatewayTokenId}")
val geolocation = getCustomerGeolocation()
// Check if customer is in high-risk region
val highRiskCountries = listOf("XX", "YY", "ZZ")
val isHighRisk = geolocation.countryCode in highRiskCountries
Log.d("GooglePay", "Customer location: ${geolocation.countryCode}, High risk: $isHighRisk")
GooglePayTransactionInitData(
riskScreeningData = RiskScreeningData(
performRiskScreening = true,
excludeDeviceData = false,
userIp = geolocation.ipAddress,
account = RiskScreeningAccount(
id = "user_12345678",
creationDateTime = "2024-01-15T10:30:00.000Z"
),
fulfillments = listOf(
RiskScreeningFulfillment(
type = FulfillmentType.SHIPPED,
recipientPerson = RiskScreeningRecipientPerson(
phoneNumber = "+1234567890"
)
)
)
)
)
}
}Implement comprehensive error handling for non-3DS payments:
val googlePayConfig = GooglePayButtonComponentConfig().apply {
// ... basic configuration
onPostAuthorisation = { result, paymentData ->
when (result) {
is MerchantSubmitResult -> {
// Payment successful
handlePaymentSuccess(result, paymentData)
}
is FailedSubmitResult -> {
// Payment declined or failed
handlePaymentFailure(result)
}
}
}
onError = { error ->
Log.e("GooglePay", "Payment error", error)
// Handle specific error types
val errorMessage = when (error) {
is GooglePayNotReadyException -> {
"Google Pay is not available on this device. Please try another payment method."
}
is GooglePayConfigurationValidationFailedException -> {
logCriticalError("Google Pay configuration error", error)
"Payment system configuration error. Please contact support."
}
is GooglePayLoadFailedException -> {
"Failed to load Google Pay. Please try again."
}
is GooglePayPaymentFailedException -> {
"Payment failed. Please try another payment method."
}
else -> {
"An error occurred. Please try again or use a different payment method."
}
}
showError(errorMessage)
}
onCancel = {
Log.d("GooglePay", "Payment cancelled by user")
// Customer closed Google Pay sheet
showMessage("Payment cancelled. Your order is still in your cart.")
}
}
fun handlePaymentSuccess(result: MerchantSubmitResult, paymentData: AuthorisationPaymentData) {
Log.d("GooglePay", "Payment successful")
Log.d("GooglePay", "Transaction ID: ${result.merchantTransactionId}")
Log.d("GooglePay", "System Txn ID: ${result.systemTransactionId}")
// Store transaction details
storeTransactionRecord(
TransactionRecord(
transactionId = result.merchantTransactionId,
systemTransactionId = result.systemTransactionId,
processingType = "non-3ds",
paymentMethod = "google-pay",
timestamp = System.currentTimeMillis()
)
)
// Navigate to success screen
navigateToSuccess(result.merchantTransactionId)
}
fun handlePaymentFailure(result: FailedSubmitResult) {
Log.e("GooglePay", "Payment failed")
Log.e("GooglePay", "Error code: ${result.errorCode}")
Log.e("GooglePay", "Error reason: ${result.errorReason}")
Log.e("GooglePay", "Correlation ID: ${result.correlationId}")
// Show user-friendly error message
showError("Payment declined. Please try another payment method.")
// Log decline for analysis
logPaymentDecline(
PaymentDeclineLog(
errorCode = result.errorCode,
errorReason = result.errorReason,
correlationId = result.correlationId,
httpStatusCode = result.httpStatusCode,
timestamp = System.currentTimeMillis()
)
)
// Offer alternative payment methods
showAlternativePaymentOptions()
}
data class TransactionRecord(
val transactionId: String,
val systemTransactionId: String,
val processingType: String,
val paymentMethod: String,
val timestamp: Long
)
data class PaymentDeclineLog(
val errorCode: String,
val errorReason: String,
val correlationId: String,
val httpStatusCode: Int,
val timestamp: Long
)The following example shows a complete non-3DS Google Pay implementation with Jetpack Compose:
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.pxp.PxpCheckout
import com.pxp.checkout.components.googlepay.*
import com.pxp.checkout.components.googlepay.types.*
import com.pxp.checkout.services.kount.*
import com.pxp.checkout.types.ComponentType
import kotlinx.coroutines.CompletableDeferred
import java.util.*
@Composable
fun GooglePayCheckout(
pxpCheckout: PxpCheckout,
amount: String,
onSuccess: (String) -> Unit,
onError: (String) -> Unit
) {
var isProcessing by remember { mutableStateOf(false) }
var errorMessage by remember { mutableStateOf<String?>(null) }
// Create Google Pay button (non-3DS)
val googlePayComponent = remember {
pxpCheckout.createComponent<
GooglePayButtonComponent,
GooglePayButtonComponentConfig
>(
type = ComponentType.GOOGLE_PAY_BUTTON,
config = GooglePayButtonComponentConfig().apply {
style = GooglePayButtonStyle(
type = GooglePayButtonType.PAY,
theme = GooglePayButtonTheme.DARK,
cornerRadius = 8
)
paymentDataRequest = PaymentDataRequest(
allowedPaymentMethods = listOf(
PaymentMethodSpecification(
parameters = PaymentMethodParameters(
allowedCardNetworks = listOf(
CardNetwork.VISA,
CardNetwork.MASTERCARD,
CardNetwork.AMEX
),
allowedAuthMethods = listOf(
CardAuthMethod.PAN_ONLY,
CardAuthMethod.CRYPTOGRAM_3DS
)
)
)
),
transactionInfo = TransactionInfo(
currencyCode = "GBP",
countryCode = "GB",
totalPriceStatus = TotalPriceStatus.FINAL,
totalPrice = amount,
totalPriceLabel = "Total"
)
)
// Handle button click
onGooglePaymentButtonClicked = {
Log.d("GooglePay", "Button clicked")
isProcessing = true
errorMessage = null
CompletableDeferred(Unit)
}
// Pre-authorisation - add risk data
onPreAuthorisation = suspend { data ->
Log.d("GooglePay", "Processing non-3DS payment")
Log.d("GooglePay", "Gateway Token ID: ${data?.gatewayTokenId}")
// Assess risk
val customerId = getCurrentCustomerId()
val riskProfile = assessCustomerRisk(customerId)
GooglePayTransactionInitData(
riskScreeningData = RiskScreeningData(
performRiskScreening = true,
excludeDeviceData = false,
userIp = "192.168.1.100",
account = RiskScreeningAccount(
id = customerId,
creationDateTime = "2024-01-15T10:30:00.000Z"
),
items = listOf(
RiskScreeningItem(
price = 99.99,
quantity = 1,
category = "Electronics"
)
),
fulfillments = listOf(
RiskScreeningFulfillment(
type = FulfillmentType.SHIPPED,
shipping = RiskScreeningShipping(
shippingMethod = ShippingMethod.STANDARD
),
recipientPerson = RiskScreeningRecipientPerson(
phoneNumber = "+1234567890"
)
)
)
)
)
}
// Post-authorisation - handle result
onPostAuthorisation = { result, _ ->
Log.d("GooglePay", "Payment result received")
isProcessing = false
when (result) {
is MerchantSubmitResult -> {
Log.d("GooglePay", "Payment authorised")
// Track successful payment
trackPaymentSuccess(
transactionId = result.merchantTransactionId,
systemTransactionId = result.systemTransactionId,
paymentMethod = "google-pay"
)
onSuccess(result.merchantTransactionId)
}
is FailedSubmitResult -> {
Log.e("GooglePay", "Payment declined: ${result.errorReason}")
errorMessage = "Payment declined. Please try another payment method."
// Track decline
trackPaymentDecline(
errorCode = result.errorCode,
errorReason = result.errorReason,
correlationId = result.correlationId
)
}
}
}
// Error handling
onError = { error ->
Log.e("GooglePay", "Payment error", error)
isProcessing = false
errorMessage = "An error occurred. Please try again."
// Track error
trackPaymentError(
errorType = error::class.simpleName ?: "Unknown",
errorMessage = error.message ?: "Unknown error"
)
}
// Cancellation handling
onCancel = {
Log.d("GooglePay", "Payment cancelled by user")
isProcessing = false
errorMessage = null
// Track cancellation
trackPaymentCancellation()
}
}
)
}
// UI
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
// Order summary
Card(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 24.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Order summary",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text("Premium Headphones")
Text("£45.00")
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text("VAT (20%)")
Text("£4.99")
}
Divider(modifier = Modifier.padding(vertical = 8.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "Total",
style = MaterialTheme.typography.titleMedium
)
Text(
text = "£$amount",
style = MaterialTheme.typography.titleMedium
)
}
}
}
// Payment section
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Pay with Google Pay",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
// Error message
errorMessage?.let { error ->
Card(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.errorContainer
)
) {
Text(
text = error,
modifier = Modifier.padding(12.dp),
color = MaterialTheme.colorScheme.onErrorContainer
)
}
}
// Google Pay button
googlePayComponent?.Content(
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
)
// Processing indicator
if (isProcessing) {
Spacer(modifier = Modifier.height(16.dp))
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth()
)
Text(
text = "Processing payment...",
modifier = Modifier.padding(top = 8.dp),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Spacer(modifier = Modifier.height(16.dp))
// Security info
Column(
modifier = Modifier.padding(vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
Text(
text = "✓ Fast and secure checkout with Google Pay",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = "✓ No need to enter card details",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = "✓ Protected by Google Pay's security",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
}
}
}
// Helper functions
private fun getCurrentCustomerId(): String {
// Get customer ID from your auth system
return "customer-123"
}
private suspend fun assessCustomerRisk(customerId: String): String {
// Implement your risk assessment logic
val orderHistory = getCustomerOrderHistory(customerId)
return when {
orderHistory.totalOrders > 10 && orderHistory.chargebacks == 0 -> "low"
orderHistory.totalOrders == 0 -> "high"
else -> "medium"
}
}
private fun trackPaymentSuccess(
transactionId: String,
systemTransactionId: String,
paymentMethod: String
) {
Log.d("Analytics", "Tracking payment success: $transactionId")
// Implement your analytics tracking
}
private fun trackPaymentDecline(
errorCode: String,
errorReason: String,
correlationId: String
) {
Log.d("Analytics", "Tracking payment decline: $errorCode")
// Implement your analytics tracking
}
private fun trackPaymentError(errorType: String, errorMessage: String) {
Log.d("Analytics", "Tracking payment error: $errorType")
// Implement your analytics tracking
}
private fun trackPaymentCancellation() {
Log.d("Analytics", "Tracking payment cancellation")
// Implement your analytics tracking
}This section describes the data received by the different callbacks as part of the non-3DS Google Pay flow on Android.
The onPreAuthorisation callback receives pre-authorisation data containing token identifiers. Use this to retrieve token details and make authorisation decisions.
| Parameter | Description |
|---|---|
dataPreAuthorisationData? | Pre-authorisation data containing token identifiers. |
data.gatewayTokenIdString? | The gateway token identifier for the payment. Use this ID to retrieve full token details from the Unity backend. |
data.schemeTokenIdString? | The scheme token identifier for the payment (e.g., Visa Token Service, Mastercard Digital Enablement Service). |
Use the gatewayTokenId with the Get masked card data related to gateway token API to retrieve full token details including card scheme, funding source (credit/debit), masked PAN, and expiry date.
onPreAuthorisation = suspend { data ->
Log.d("GooglePay", "Non-3DS authorisation for token: ${data?.gatewayTokenId}")
// Retrieve token details and make authorisation decision
val transactionDecision = getAuthorisationDecision(data?.gatewayTokenId)
if (transactionDecision == null) {
Log.d("GooglePay", "Not proceeding with authorisation")
null
} else {
// Add risk screening data
GooglePayTransactionInitData(
riskScreeningData = RiskScreeningData(
performRiskScreening = true,
excludeDeviceData = false,
userIp = "192.168.1.100",
account = RiskScreeningAccount(
id = "user_12345678",
creationDateTime = "2024-01-15T10:30:00.000Z"
),
fulfillments = listOf(
RiskScreeningFulfillment(
type = FulfillmentType.SHIPPED,
recipientPerson = RiskScreeningRecipientPerson(
phoneNumber = "+1234567890"
)
)
)
)
)
}
}3DS external data should no longer be provided via the callback. For non-3DS flows, no 3DS data is applicable.
The onPostAuthorisation callback receives the authorisation result and the original payment data from Google Pay.
| Parameter | Description |
|---|---|
resultSubmitResult? | Transaction result - either MerchantSubmitResult (success) or FailedSubmitResult (failure). |
paymentDataAuthorisationPaymentData required | Google Pay payment data collected during checkout (email, shipping address, shipping option). |
When the payment is successful, you'll receive a MerchantSubmitResult:
data class MerchantSubmitResult(
val merchantTransactionId: String,
val systemTransactionId: String
)| Property | Type | Description |
|---|---|---|
merchantTransactionId | String | The merchant's unique identifier for the transaction that was provided during SDK initialisation. |
systemTransactionId | String | The system's unique identifier for the transaction. Use this with merchantTransactionId to retrieve full authorisation details from the Unity backend. |
When the payment fails, you'll receive a FailedSubmitResult:
data class FailedSubmitResult(
val errorCode: String,
val errorReason: String,
val correlationId: String,
val httpStatusCode: Int
)| Property | Type | Description |
|---|---|---|
errorCode | String | The error code indicating the type of failure. |
errorReason | String | A human-readable description of the error. |
correlationId | String | A unique identifier for this transaction attempt. Use this for support inquiries and debugging. |
httpStatusCode | Int | The HTTP status code associated with the failure. |
onPostAuthorisation = { result, paymentData ->
Log.d("GooglePay", "Non-3DS Google Pay payment result")
when (result) {
is MerchantSubmitResult -> {
// Success
Log.d("GooglePay", "✅ Payment successful!")
Log.d("GooglePay", "Merchant Transaction ID: ${result.merchantTransactionId}")
Log.d("GooglePay", "System Transaction ID: ${result.systemTransactionId}")
// Store transaction details
storeTransactionRecord(
TransactionRecord(
merchantTransactionId = result.merchantTransactionId,
systemTransactionId = result.systemTransactionId,
paymentMethod = "google-pay",
processingType = "non-3ds",
timestamp = System.currentTimeMillis()
)
)
// Redirect to success page
navigateToSuccess(result.merchantTransactionId)
}
is FailedSubmitResult -> {
// Failure
Log.e("GooglePay", "❌ Payment failed")
Log.e("GooglePay", "Error code: ${result.errorCode}")
Log.e("GooglePay", "Error reason: ${result.errorReason}")
Log.e("GooglePay", "Correlation ID: ${result.correlationId}")
// Handle payment failure
handlePaymentFailure(result)
}
}
}The onError callback is triggered when an error occurs during the Google Pay flow (before reaching authorisation).
| Parameter | Description |
|---|---|
errorBaseSdkException required | The exception that occurred during the payment flow. |
onError = { error ->
Log.e("GooglePay", "Google Pay error", error)
// Handle specific error types
val errorMessage = when (error) {
is GooglePayNotReadyException -> {
"Google Pay is not available on this device. Please try another payment method."
}
is GooglePayConfigurationValidationFailedException -> {
logCriticalError("Google Pay configuration error", error)
"Payment system configuration error. Please contact support."
}
is GooglePayLoadFailedException -> {
"Failed to load Google Pay. Please try again."
}
is GooglePayPaymentFailedException -> {
"Payment failed. Please try another payment method."
}
else -> {
"An error occurred. Please try again or use a different payment method."
}
}
showError(errorMessage)
// Re-enable payment options
hideLoadingSpinner()
enablePaymentOptions()
}The onCancel callback is triggered when the customer closes the Google Pay payment sheet without completing the payment.
This callback does not receive any parameters.
onCancel = {
Log.d("GooglePay", "Google Pay payment cancelled by user")
// Track cancellation for analytics
trackEvent("payment-cancelled", mapOf(
"paymentMethod" to "google-pay",
"timestamp" to System.currentTimeMillis()
))
// Show message to user
showMessage("Payment cancelled. Your order is still in your cart.")
// Reset UI state
hideLoadingSpinner()
enablePaymentOptions()
}