Skip to content

Implementation

Learn how to use the PayPal components in your Android project.

Overview

Every component follows the same basic three-step lifecycle:

  1. Create the component and optionally add your own configuration.
  2. Render the component using Jetpack Compose. This is what makes the component visible and interactive.
  3. Dispose the component. This is a clean-up step that clears up resources and is handled automatically by Compose.

Before you start

To use the PayPal components, you first need to:

Choose your implementation approach

Android offers three ways to implement PayPal payments, depending on your requirements:

  • Simple PayPal: Use this approach when you need basic PayPal payments without one-click or vaulting features. Ideal for guest checkout, simple payments, and digital products.
  • Pre-built PayPal Use the pre-configured composite component that includes the basic PayPal component and the toggle component for one-click payments. This approach offers a quick integration path with built-in vaulting support.
  • Custom composition Manually compose the PayPal, toggle, and consent components for maximum control over layout and behaviour. This approach gives you the most flexibility for custom UX requirements.

The component lifecycle is automatically managed by Jetpack Compose across all three approaches. However, you can manually dispose of resources if needed:

DisposableEffect(paypalComponent) {
    onDispose {
        // Component resources are automatically cleaned up
        Log.d("PayPal", "Component disposed")
    }
}

Implement PayPal payments

Step 1: Initialise the SDK

To get started, initialise the Checkout SDK in your Android application.

import com.pxp.checkout.PxpCheckout
import com.pxp.checkout.models.PxpCheckoutConfig
import com.pxp.checkout.models.Environment
import com.pxp.checkout.models.OwnerType
import com.pxp.checkout.models.TransactionData
import com.pxp.checkout.models.EntryType
import com.pxp.checkout.models.IntentType
import java.util.UUID

val pxpCheckout = PxpCheckout.builder()
    .withConfig(
        PxpCheckoutConfig(
            environment = Environment.TEST,
            session = sessionData,
            ownerId = "Unity",
            ownerType = OwnerType.MERCHANT_GROUP,
            merchantShopperId = "Shopper_01",
            transactionData = TransactionData(
                currency = "USD",
                amount = 2500.0, // Amount in cents ($25.00)
                entryType = EntryType.Ecom,
                intent = IntentType.Purchase,
                merchantTransactionId = UUID.randomUUID().toString(),
                merchantTransactionDate = { System.currentTimeMillis() }
            )
        )
    )
    .withContext(context)
    .build()
ParameterDescription
environment
Environment
required
The environment type.

Possible values:
  • Environment.TEST: For sandbox.
  • Environment.LIVE: For production.
session
SessionData
required
Details about the checkout session.
ownerId
String
required
The identifier of the owner related to the ownerType.
ownerType
OwnerType
required
The type of owner.

Possible values:
  • OwnerType.MERCHANT_GROUP
  • OwnerType.MERCHANT Coming soon
  • OwnerType.SITE Coming soon
merchantShopperId
String
required
A unique identifier for this shopper.
transactionData
TransactionData
required
Details about the transaction.
transactionData.currency
String
The currency code associated with the transaction (e.g., USD, EUR).
transactionData.amount
Double
required
The transaction amount in the smallest currency unit (e.g., cents for USD).
transactionData.entryType
EntryType
required
The entry type.

Possible values:
  • EntryType.Ecom
  • EntryType.MOTO
transactionData.intent
IntentType
required
The transaction intent.

Possible values:
  • IntentType.Authorisation
  • IntentType.Purchase
  • IntentType.Verification
  • IntentType.EstimatedAuthorisation
  • IntentType.Payout
transactionData.merchantTransactionId
String
required
A unique identifier for this transaction.
transactionData.merchantTransactionDate
() -> Long
required
A function that returns the current timestamp in milliseconds.

Step 2: Configure the component

Create the PayPal component configuration with basic settings:

import com.pxp.checkout.components.paypal.PayPalComponentConfig
import com.pxp.checkout.components.paypal.types.*

val paypalConfig = PayPalComponentConfig(
    payeeEmailAddress = "merchant@example.com",
    paymentDescription = "Order #12345",
    shippingPreference = ShippingPreference.NoShipping.toString(),
    userAction = UserAction.PayNow.toString(),
    renderType = "standalone",
    fundingSources = "paypal", // String for standalone mode
    enableOneClickPayment = false // No vaulting
)
ParameterDescription
payeeEmailAddress
String?
Your email address.
paymentDescription
String?
A description of the payment.
shippingPreference
String
required
The shipping details to use.

Possible values:
  • NoShipping: No shipping address required.
  • GetFromFile: Get shipping address from PayPal account.
  • SetProvidedAddress: Use provided shipping address.
userAction
String
required
The next step in the payment flow.

Possible values:
  • PayNow: Immediate payment capture.
  • Continue: Continue to PayPal for payment.
renderType
String
required
The type of button to render.

Possible values:
  • standalone: A single button. Choose this when there is only one payment method.
  • setOfButtons: Multiple buttons. Choose this when there are multiple payment methods.
fundingSources
Any?
required
The payment method(s) to support. The type depends on the renderType:
  • String for standalone mode (e.g., paypal)
  • List<String> for setOfButtons mode (e.g., listOf("paypal", "paylater"))


Possible values:
  • paypal: Standard PayPal payments.
  • paylater: PayPal Pay Later financing.
shippingAddress
ShippingAddress?
Details about the shipping address. Provide this only when the shippingPreference is SetProvidedAddress.
shippingOptions
List<ShippingOption>?
Details about the shipping options. Provide this only when the shippingPreference is GetFromFile.

Step 3: Create and render the component

Create and render the component using Jetpack Compose:

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.pxp.checkout.types.ComponentType

@Composable
fun PayPalPaymentScreen() {
    val paypalComponent = remember {
        pxpCheckout.createComponent(
            type = ComponentType.PAYPAL,
            config = paypalConfig
        )
    }
    
    // Render the PayPal button
    pxpCheckout.buildComponentView(
        component = paypalComponent,
        modifier = Modifier.fillMaxWidth()
    )
}

Step 4: Handle the payment result

Implement event handling callbacks to manage payment outcomes:

val paypalConfig = PayPalComponentConfig(
    // ... previous config
    onSuccess = { data ->
        // Payment was successful
        Log.d("PayPal", "Payment successful: $data")
        
        // Parse the payment data
        val jsonObject = JSONObject(data)
        val orderID = jsonObject.getString("orderID")
        val payerID = jsonObject.getString("payerID")
        
        // Navigate to success screen or update UI
        navigateToSuccessScreen(orderID)
    },
    
    onError = { error ->
        // Payment failed
        Log.e("PayPal", "Payment error: $error")
        
        // Show error message to user
        showErrorDialog("Payment failed. Please try again.")
    },
    
    onCancel = {
        // User cancelled the payment
        Log.d("PayPal", "Payment cancelled by user")
        
        // Show cancellation message
        showMessage("Payment was cancelled.")
    }
)

Complete examples

Here's a complete working example with the PayPal component:

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.Modifier
import androidx.compose.ui.unit.dp
import com.pxp.checkout.PxpCheckout
import com.pxp.checkout.components.paypal.PayPalComponentConfig
import com.pxp.checkout.components.paypal.types.*
import com.pxp.checkout.types.ComponentType
import org.json.JSONObject

class SimplePayPalActivity : ComponentActivity() {
    
    private lateinit var pxpCheckout: PxpCheckout
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Initialise SDK
        pxpCheckout = PxpCheckout.builder()
            .withConfig(sdkConfig)
            .withContext(this)
            .build()
        
        setContent {
            MaterialTheme {
                SimplePayPalScreen()
            }
        }
    }
    
    @Composable
    fun SimplePayPalScreen() {
        var paymentStatus by remember { mutableStateOf<String?>(null) }
        var showSuccessDialog by remember { mutableStateOf(false) }
        var showErrorDialog by remember { mutableStateOf(false) }
        
        val paypalConfig = remember {
            PayPalComponentConfig(
                renderType = "standalone",
                payeeEmailAddress = "merchant@example.com",
                paymentDescription = "Order #12345",
                shippingPreference = "NoShipping",
                userAction = "PayNow",
                fundingSources = "paypal",
                enableOneClickPayment = false,
                style = PayPalButtonStyle(
                    layout = "vertical",
                    color = "gold",
                    shape = "rect",
                    label = "paypal",
                    height = 45
                ),
                onSuccess = { data ->
                    val jsonObject = JSONObject(data)
                    val orderID = jsonObject.getString("orderID")
                    paymentStatus = "Payment successful! Order ID: $orderID"
                    showSuccessDialog = true
                },
                onError = { error ->
                    paymentStatus = "Payment failed: $error"
                    showErrorDialog = true
                },
                onCancel = {
                    paymentStatus = "Payment was cancelled"
                }
            )
        }
        
        val paypalComponent = remember {
            pxpCheckout.createComponent(
                type = ComponentType.PAYPAL,
                config = paypalConfig
            )
        }
        
        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colorScheme.background
        ) {
            Column(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(16.dp),
                verticalArrangement = Arrangement.spacedBy(16.dp)
            ) {
                Text(
                    text = "Complete your payment",
                    style = MaterialTheme.typography.headlineMedium
                )
                
                Text(
                    text = "Amount: $25.00",
                    style = MaterialTheme.typography.titleMedium
                )
                
                // PayPal button
                pxpCheckout.buildComponentView(
                    component = paypalComponent,
                    modifier = Modifier.fillMaxWidth()
                )
                
                // Status message
                paymentStatus?.let { status ->
                    Text(
                        text = status,
                        style = MaterialTheme.typography.bodyMedium
                    )
                }
            }
        }
        
        // Success dialog
        if (showSuccessDialog) {
            AlertDialog(
                onDismissRequest = { showSuccessDialog = false },
                title = { Text("Payment Successful") },
                text = { Text(paymentStatus ?: "") },
                confirmButton = {
                    Button(onClick = { 
                        showSuccessDialog = false
                        finish()
                    }) {
                        Text("OK")
                    }
                }
            )
        }
        
        // Error dialog
        if (showErrorDialog) {
            AlertDialog(
                onDismissRequest = { showErrorDialog = false },
                title = { Text("Payment Error") },
                text = { Text(paymentStatus ?: "") },
                confirmButton = {
                    Button(onClick = { showErrorDialog = false }) {
                        Text("OK")
                    }
                }
            )
        }
    }
}

What's next?

Customise the look and feel

You can configure the appearance and behaviour of the PayPal component to fit your brand. We've documented all configurable parameters in the Configuration section.

val paypalConfig = PayPalComponentConfig(
    renderType = "standalone",
    payeeEmailAddress = "merchant@example.com",
    paymentDescription = "Premium Subscription",
    shippingPreference = "NoShipping",
    userAction = "PayNow",
    fundingSources = "paypal",
    locale = "en-US",
    style = PayPalButtonStyle(
        layout = "horizontal",
        color = "blue",
        shape = "pill",
        label = "buynow",
        height = 45,
        borderRadius = 4
    ),
    queryParams = PayPalQueryParams(
        buyerCountry = "US",
        debug = false
    )
)

Add more event handling

The PayPal component emits events based on user interaction or validation. As seen in the steps above, you can implement callback functions to handle these events. For more information about all the available events, see the Events page.

val paypalConfig = PayPalComponentConfig(
    onShippingAddressChange = { data ->
        // Validate shipping address
        val isValid = validateShippingAddress(data)
        if (isValid) null else "reject:INVALID_ADDRESS"
    },
    onShippingOptionsChange = { data ->
        // Handle shipping option changes
        updateShippingCosts(data)
        null
    }
)

Add error handling

Error handling is crucial for payment components because they deal with sensitive financial data and complex validation rules. For more details about error handling, see the Troubleshooting page.

try {
    val paypalComponent = pxpCheckout.createComponent(
        type = ComponentType.PAYPAL,
        config = paypalConfig
    )
    
    pxpCheckout.buildComponentView(
        component = paypalComponent,
        modifier = Modifier.fillMaxWidth()
    )
} catch (e: Exception) {
    Log.e("PayPal", "Failed to initialise PayPal component", e)
    
    // Show fallback UI or error message to user
    Text(
        text = "Payment system temporarily unavailable. Please try again later.",
        color = MaterialTheme.colorScheme.error
    )
}

Subscribe to webhooks

To get real-time updates about PayPal transactions, you can subscribe to the PayPal webhooks in the Unity Portal.