Skip to content

Implementation

Learn how to use the Google Pay component for Android in your project.

Overview

Every component follows the same basic two-step lifecycle:

  1. Create the component and configure it with your settings.
  2. Render the component using Jetpack Compose. This makes the component visible and interactive. Cleanup happens automatically when the Composable leaves composition.

Before you start

To use the Google Pay button component, you first need to:

  • Install the Android SDK.
  • Complete the Google Pay onboarding process in the Unity Portal. See Onboarding for details.
  • Configure your Google Pay merchant account and link it to the Unity Portal.

Step 1: Initialise the SDK

To get started, initialise the PXP Checkout SDK with your merchant credentials and transaction data.

import com.pxp.PxpCheckout
import com.pxp.checkout.models.*
import com.pxp.checkout.services.models.transaction.Shopper
import java.text.SimpleDateFormat
import java.util.*

class PaymentActivity : ComponentActivity() {

    private lateinit var pxpCheckout: PxpCheckout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Get session config from your backend API
        val sessionConfig = fetchSessionFromYourBackend()

        // Initialise PxpCheckout SDK
        pxpCheckout = PxpCheckout.builder()
            .withConfig(
                PxpSdkConfig(
                    environment = Environment.TEST,
                    session = sessionConfig,
                    ownerId = "your-owner-id",
                    ownerType = "MerchantGroup",
                    kountDisabled = false, // OPTIONAL: Set to true to disable Kount fraud detection
                    transactionData = TransactionData(
                        amount = 99.99,
                        currency = "GBP",
                        merchant = "your-merchant-id",
                        merchantTransactionId = UUID.randomUUID().toString(),
                        merchantTransactionDate = {
                            SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
                                .apply { timeZone = TimeZone.getTimeZone("UTC") }
                                .format(Date())
                        },
                        entryType = EntryType.Ecom,
                        intent = TransactionIntentData(
                            card = IntentType.Authorisation
                        )
                    ),
                    onGetShopper = {
                        // Return current shopper data dynamically
                        Shopper(
                            id = "shopper-${System.currentTimeMillis()}",
                            email = "customer@example.com",
                            firstName = "John",
                            lastName = "Doe"
                        )
                    },
                    onGetShippingAddress = {
                        // Return current shipping address dynamically (optional)
                        ShippingAddress(
                            addressLine1 = "123 Main Street",
                            city = "London",
                            postalCode = "SW1A 1AA",
                            countryCode = "GB"
                        )
                    }
                )
            )
            .withContext(this)
            .build()

        setContent {
            YourAppTheme {
                PaymentScreen(pxpCheckout = pxpCheckout)
            }
        }
    }

    private fun fetchSessionFromYourBackend(): SessionConfig {
        // Call your merchant backend API to create a session
        // Your backend should call PXP API to create a session
        return SessionConfig(
            sessionId = "session-123",
            hmacKey = "hmac-key",
            data = "session-data",
            encryptionKey = "encryption-key",
            locale = "en-GB"
        )
    }
}
ParameterDescription
environment
Environment
required
The environment type.

Possible values:
  • Environment.TEST: Sandbox.
  • Environment.LIVE: Live payments.
session
SessionConfig
required
Session configuration obtained from your backend.
session.sessionId
String
required
Unique session identifier.
session.hmacKey
String
required
HMAC key for session validation.
session.data
String
required
Session data payload.
session.encryptionKey
String
required
Encryption key for secure data transmission.
ownerId
String
required
The identifier of the owner.
ownerType
String
required
The type of owner. Use "MerchantGroup".
kountDisabled
Boolean
Whether to disable the Kount fraud detection service. Defaults to false (fraud detection enabled).
onGetShopper
() -> Shopper?
Callback function to provide shopper data dynamically. Returns Shopper object from com.pxp.checkout.services.models.transaction package with shopper information including ID, email, name, and contact details. Required when using consent tokens for storing payment methods.
onGetShippingAddress
() -> ShippingAddress?
Callback function to provide shipping address dynamically. Returns ShippingAddress object from com.pxp.checkout.models package with shipping address information. Optional.
transactionData
TransactionData
required
Details about the transaction.
transactionData.amount
Double
required
Transaction amount.
transactionData.currency
String (3 characters)
required
Currency code in ISO 4217 format (e.g., "GBP", "USD", "EUR").
transactionData.merchant
String
required
Your merchant identifier.
transactionData.merchantTransactionId
String
required
Your unique identifier for this transaction.
transactionData.merchantTransactionDate
() -> String
required
Function that returns the transaction date in ISO 8601 format.
transactionData.entryType
EntryType
Entry type. Use EntryType.Ecom for e-commerce transactions.
transactionData.intent
TransactionIntentData
Transaction intents for each payment method.

Possible values for card:
  • IntentType.Authorisation
  • IntentType.Purchase
  • IntentType.Verification
  • IntentType.EstimatedAuthorisation

Step 2: Configure the Google Pay component

Create the configuration for your Google Pay button with payment settings and event handlers.

The SDK automatically configures tokenizationSpecification and merchantInfo with the correct gateway, merchant ID, and merchant name from your session. You only need to provide allowedPaymentMethods with the card parameters and transactionInfo.

import com.pxp.checkout.components.googlepay.types.*
import com.pxp.checkout.services.kount.*
import com.pxp.checkout.models.MerchantSubmitResult
import com.pxp.checkout.models.FailedSubmitResult

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    
    // Button style
    style = GooglePayButtonStyle(
        type = GooglePayButtonType.PAY,
        theme = GooglePayButtonTheme.DARK,
        cornerRadius = 8
    )
    
    // Payment data request (REQUIRED)
    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",
            totalPriceStatus = TotalPriceStatus.FINAL,
            totalPrice = "99.99"
        )
    )
    
    // Pre-authorisation callback
    onPreAuthorisation = suspend { preAuthData ->
        Log.d("GooglePay", "Processing payment")
        
        // Return 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-001"
                    )
                ),
                fulfillments = listOf(
                    RiskScreeningFulfillment(
                        type = FulfillmentType.SHIPPED,
                        shipping = RiskScreeningShipping(
                            shippingMethod = ShippingMethod.STANDARD
                        ),
                        recipientPerson = RiskScreeningRecipientPerson(
                            phoneNumber = "+1234567890"
                        )
                    )
                )
            )
        )
    }
    
    // Handle successful payment
    onPostAuthorisation = { result, paymentData ->
        when (result) {
            is MerchantSubmitResult -> {
                Log.d("GooglePay", "Payment successful: ${result.systemTransactionId}")
                handlePaymentSuccess(result)
            }
            is FailedSubmitResult -> {
                Log.e("GooglePay", "Payment failed: ${result.errorReason}")
                handlePaymentFailure(result)
            }
        }
    }
    
    // Handle errors
    onError = { error ->
        Log.e("GooglePay", "Error: ${error.message}")
        showError(error.message)
    }
}

Step 3: Create and render the component

Create the Google Pay component and render it in your Compose UI.

import com.pxp.checkout.components.googlepay.GooglePayButtonComponent
import com.pxp.checkout.types.ComponentType

@Composable
fun PaymentScreen(pxpCheckout: PxpCheckout) {
    
    val googlePayComponent = remember {
        pxpCheckout.createComponent<GooglePayButtonComponent, GooglePayButtonComponentConfig>(
            type = ComponentType.GOOGLE_PAY_BUTTON,
            config = googlePayConfig
        )
    }
    
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "Complete your purchase",
            style = MaterialTheme.typography.headlineMedium,
            modifier = Modifier.padding(bottom = 16.dp)
        )
        
        // Render the Google Pay button
        googlePayComponent?.Content(
            modifier = Modifier
                .fillMaxWidth()
                .height(56.dp)
        )
    }
}

Complete example

Here's a complete working example that puts everything together:

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.lifecycleScope
import com.pxp.PxpCheckout
import com.pxp.checkout.components.googlepay.GooglePayButtonComponent
import com.pxp.checkout.components.googlepay.types.*
import com.pxp.checkout.models.*
import com.pxp.checkout.services.kount.*
import com.pxp.checkout.services.models.transaction.Shopper
import com.pxp.checkout.types.ComponentType
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*

class MainActivity : ComponentActivity() {

    private lateinit var pxpCheckout: PxpCheckout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleScope.launch {
            // Initialise SDK
            pxpCheckout = initializeSDK()

            setContent {
                MaterialTheme {
                    GooglePayScreen(pxpCheckout)
                }
            }
        }
    }

    private suspend fun initializeSDK(): PxpCheckout {
        val sessionConfig = fetchSessionFromYourBackend()

        return PxpCheckout.builder()
            .withConfig(
                PxpSdkConfig(
                    environment = Environment.TEST,
                    session = sessionConfig,
                    ownerId = "your-owner-id",
                    ownerType = "MerchantGroup",
                    kountDisabled = false,
                    transactionData = TransactionData(
                        amount = 99.99,
                        currency = "GBP",
                        merchant = "your-merchant-id",
                        merchantTransactionId = UUID.randomUUID().toString(),
                        merchantTransactionDate = {
                            SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
                                .apply { timeZone = TimeZone.getTimeZone("UTC") }
                                .format(Date())
                        },
                        entryType = EntryType.Ecom,
                        intent = TransactionIntentData(
                            card = IntentType.Authorisation
                        )
                    ),
                    onGetShopper = {
                        Shopper(
                            id = "shopper-${System.currentTimeMillis()}",
                            email = "customer@example.com",
                            firstName = "John",
                            lastName = "Doe"
                        )
                    },
                    onGetShippingAddress = {
                        ShippingAddress(
                            addressLine1 = "123 Main Street",
                            city = "London",
                            postalCode = "SW1A 1AA",
                            countryCode = "GB"
                        )
                    }
                )
            )
            .withContext(this)
            .build()
    }

    private suspend fun fetchSessionFromYourBackend(): SessionConfig {
        // Call your backend to fetch session
        return SessionConfig(
            sessionId = "session-123",
            hmacKey = "hmac-key",
            data = "session-data",
            encryptionKey = "encryption-key",
            locale = "en-GB"
        )
    }
}

@Composable
fun GooglePayScreen(pxpCheckout: PxpCheckout) {
    var showSuccess by remember { mutableStateOf(false) }
    var errorMessage by remember { mutableStateOf<String?>(null) }

    val googlePayConfig = remember {
        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",
                    totalPriceStatus = TotalPriceStatus.FINAL,
                    totalPrice = "99.99"
                )
            )

            onPreAuthorisation = suspend { preAuthData ->
                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"
                                )
                            )
                        )
                    )
                )
            }

            onPostAuthorisation = { result, paymentData ->
                when (result) {
                    is MerchantSubmitResult -> {
                        showSuccess = true
                    }
                    is FailedSubmitResult -> {
                        errorMessage = result.errorReason
                    }
                }
            }

            onError = { error ->
                errorMessage = error.message
            }
        }
    }

    val googlePayComponent = remember {
        pxpCheckout.createComponent<GooglePayButtonComponent, GooglePayButtonComponentConfig>(
            type = ComponentType.GOOGLE_PAY_BUTTON,
            config = googlePayConfig
        )
    }

    Scaffold { paddingValues ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            if (showSuccess) {
                Text(
                    text = "✓ Payment Successful!",
                    style = MaterialTheme.typography.headlineMedium,
                    color = MaterialTheme.colorScheme.primary
                )
            } else {
                Text(
                    text = "Complete your purchase",
                    style = MaterialTheme.typography.headlineMedium,
                    modifier = Modifier.padding(bottom = 24.dp)
                )

                googlePayComponent?.Content(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(56.dp)
                )

                errorMessage?.let { error ->
                    Text(
                        text = error,
                        color = MaterialTheme.colorScheme.error,
                        modifier = Modifier.padding(top = 16.dp)
                    )
                }
            }
        }
    }
}

Next steps

Now that you've implemented the basic Google Pay integration, you can: