Skip to content

Events

Implement callbacks to customise your PayPal payment flow for Android.

Overview

Components emit events based on user interaction or validation. You can use these to implement callback functions, which allow you 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.

Callbacks enable you to:

  • Validate business rules before payments proceed.
  • Display custom error, failure, or success messages.
  • Tailor user interfaces to match your brand's look and feel.
  • Integrate with your own systems for fraud detection or customer management.
  • Control exactly how your customers experience both successful and failed transactions.
  • Handle PayPal-specific requirements like shipping calculations and address validation.
  • Manage different funding sources (PayPal and Pay Later).
  • Customise the checkout experience based on customer preferences.

All events are optional and can be mixed and matched based on your business needs.

Supported events

The following table lists all events supported by the different PayPal components.

EventPayPal componentPre-built componentConsent componentToggle component
onSuccess
onError
onCancel
onShippingAddressChange
onShippingOptionsChange
onOrderCreated
onSubmitError
onScriptLoaded
onGetConsent
onToggleChanged
onLinkClick
onTriggerFieldValidation

Callbacks

onSuccess

This callback is triggered when the buyer approves the payment in the PayPal checkout flow. This is where you capture the funds and complete the transaction.

You can use it to:

  • Process the approved payment and complete the transaction.
  • Update inventory and order status in your system.
  • Send order confirmation emails or push notifications to customers.
  • Record successful transactions for business intelligence.
  • Navigate to a success screen in your app.

Event data

Event dataDescription
data
PaymentData
The payment approval data object from PayPal.
data.orderID
String
The unique PayPal order identifier for this transaction.
data.payerID
String
The PayPal payer identifier for the customer who approved the payment.
data.paymentID
String?
The PayPal payment identifier (optional, may be null).
data.billingToken
String?
The billing agreement token for vaulting (optional, may be null for one-time payments).
data.facilitatorAccessToken
String
The access token for the facilitator to complete the transaction.

Return value

This callback must return a string.

Example implementation

import org.json.JSONObject
import android.util.Log

val paypalConfig = PayPalComponentConfig(
    onSuccess = { data ->
        Log.d("PayPal", "Payment approved: $data")
        
        try {
            // Parse the payment data
            val jsonObject = JSONObject(data)
            val orderID = jsonObject.getString("orderID")
            val payerID = jsonObject.getString("payerID")
            val paymentID = jsonObject.optString("paymentID", null)
            
            // Update your system with the successful payment
            updateOrderStatus(
                orderId = orderID,
                status = "completed",
                paymentMethod = "paypal"
            )
            
            // Update inventory
            updateInventory(orderID)
            
            // Send confirmation notification
            sendPushNotification(
                title = "Payment Successful",
                body = "Your order $orderID has been confirmed"
            )
            
            // Track successful payment
            analytics.track("paypal_payment_completed", mapOf(
                "orderId" to orderID,
                "payerID" to payerID,
                "timestamp" to System.currentTimeMillis()
            ))
            
            // Navigate to success screen
            navController.navigate("payment_success/$orderID")
            
            // Return success status
            return@PayPalComponentConfig "success"
            
        } catch (e: Exception) {
            Log.e("PayPal", "Payment processing error", e)
            showErrorMessage("Payment processing failed. Please contact support.")
            return@PayPalComponentConfig "error"
        }
    }
)

onCancel

This callback is triggered when the buyer cancels the payment flow in the PayPal popup or navigates back without completing the payment.

You can use it to:

  • Track cancellation rates for conversion optimisation.
  • Show helpful messages or alternative payment options.
  • Save the customer's cart for later completion.
  • Trigger email campaigns for abandoned checkouts.

Event data

This callback receives no parameters.

Example implementation

val paypalConfig = PayPalComponentConfig(
    onCancel = {
        Log.d("PayPal", "Payment cancelled by user")
        
        // Track cancellation for analytics
        analytics.track("paypal_payment_cancelled", mapOf(
            "timestamp" to System.currentTimeMillis(),
            "cartValue" to getCurrentCartValue(),
            "stage" to "paypal_checkout"
        ))
        
        // Preserve cart for later
        saveCartForLater()
        
        // Show helpful message
        showSnackbar(
            message = "No worries! Your items are saved. You can complete your purchase anytime.",
            duration = SnackbarDuration.Long
        )
        
        // Offer alternatives after a short delay
        viewModelScope.launch {
            delay(2000)
            showAlternativePaymentOptions()
        }
        
        // Optional: Schedule abandoned cart notification
        scheduleAbandonedCartNotification(30) // 30 minutes delay
    }
)

onError

This callback is triggered when an error occurs during the PayPal payment process, such as network issues, invalid configuration, or payment processing failures.

You can use it to:

  • Log errors for debugging and monitoring.
  • Display user-friendly error messages.
  • Offer alternative payment methods.
  • Implement automatic retry for transient errors.

Event data

Event dataDescription
error
String
The error message or JSON containing details about what went wrong.

Example implementation

val paypalConfig = PayPalComponentConfig(
    onError = { error ->
        Log.e("PayPal", "Payment error: $error")
        
        // Log error for debugging
        crashlytics.log("PayPal payment error: $error")
        crashlytics.recordException(Exception("PayPal Error: $error"))
        
        // Handle different error types
        when {
            error.contains("INSTRUMENT_DECLINED") -> {
                showErrorDialog(
                    title = "Payment Declined",
                    message = "Your PayPal payment was declined. Please try a different payment method or contact PayPal support."
                )
            }
            error.contains("PAYER_ACTION_REQUIRED") -> {
                showErrorDialog(
                    title = "Action Required",
                    message = "Additional action required in PayPal. Please try again or complete any pending actions in your PayPal account."
                )
            }
            error.contains("UNPROCESSABLE_ENTITY") -> {
                showErrorDialog(
                    title = "Processing Error",
                    message = "There was an issue processing your payment. Please check your payment details and try again."
                )
            }
            error.contains("Network") || error.contains("timeout") -> {
                showErrorDialog(
                    title = "Connection Error",
                    message = "Network error. Please check your connection and try again.",
                    action = "Retry" to { retryPayment() }
                )
            }
            else -> {
                showErrorDialog(
                    title = "Payment Error",
                    message = "Payment failed. Please try again or use a different payment method."
                )
            }
        }
        
        // Show alternative payment methods
        showAlternativePaymentMethods()
        
        // Track error metrics
        analytics.track("paypal_error", mapOf(
            "errorMessage" to error,
            "timestamp" to System.currentTimeMillis()
        ))
    }
)

onOrderCreated

This callback is triggered when the PayPal order is successfully created but before the customer approves the payment.

You can use it to:

  • Store the order ID for tracking purposes.
  • Update order status in your system.
  • Log order creation events for analytics.
  • Validate order creation success.

Event data

Event dataDescription
data
OrderCreatedData
The order creation response object containing transaction details.
data.providerTransactionId
String
The PayPal order ID assigned by PayPal for this transaction.
data.transactionId
String
The PXP transaction ID for tracking within the PXP system.
data.correlationId
String
The correlation ID for tracking the transaction across systems.

Return value

This callback must return a string.

Example implementation

val paypalConfig = PayPalComponentConfig(
    onOrderCreated = { data ->
        Log.d("PayPal", "Order created successfully: $data")
        
        try {
            val jsonObject = JSONObject(data)
            val providerTransactionId = jsonObject.getString("providerTransactionId")
            val transactionId = jsonObject.getString("transactionId")
            val correlationId = jsonObject.optString("correlationId", "")
            
            // Store order information
            storeOrderInformation(
                paypalOrderId = providerTransactionId,
                pxpTransactionId = transactionId,
                correlationId = correlationId,
                status = "created",
                createdAt = System.currentTimeMillis()
            )
            
            // Update UI to show order created state
            updateOrderStatus("Order created, awaiting payment approval...")
            
            // Track order creation
            analytics.track("paypal_order_created", mapOf(
                "paypalOrderId" to providerTransactionId,
                "pxpTransactionId" to transactionId,
                "timestamp" to System.currentTimeMillis()
            ))
            
            // Optional: Start order timeout timer
            startOrderTimeoutTimer(providerTransactionId, 15) // 15 minute timeout
            
            // Return order created status
            return@PayPalComponentConfig "order_created"
            
        } catch (e: Exception) {
            Log.e("PayPal", "Failed to parse order creation data", e)
            return@PayPalComponentConfig "error"
        }
    }
)

onShippingAddressChange

This callback is triggered when the customer changes their shipping address in the PayPal checkout flow. Use this to calculate shipping costs and validate delivery availability.

You can use it to:

  • Calculate shipping costs based on the new address.
  • Validate if delivery is available to the location.
  • Update tax rates based on the shipping destination.
  • Check shipping restrictions for specific products.

Event data

Event dataDescription
data
ShippingAddressData
The shipping address change data object.
data.shippingAddress
Object
The new shipping address selected by the customer.
data.shippingAddress.recipientName
String
The name of the person receiving the shipment.
data.shippingAddress.addressLine1
String
The first line of the shipping address.
data.shippingAddress.addressLine2
String?
The second line of the shipping address (optional).
data.shippingAddress.city
String
The city for the shipping address.
data.shippingAddress.state
String
The state or region for the shipping address.
data.shippingAddress.postalCode
String
The postal code or ZIP code for the shipping address.
data.shippingAddress.countryCode
String
The two-letter ISO country code for the shipping address.

Return value

This callback must return a string. Return an empty string to allow the address change, or return a rejection string (e.g., "reject:COUNTRY_ERROR") to reject it.

Example implementation

val paypalConfig = PayPalComponentConfig(
    onShippingAddressChange = { data ->
        Log.d("PayPal", "Shipping address changed: $data")
        
        try {
            val jsonObject = JSONObject(data)
            val shippingAddress = jsonObject.optJSONObject("shippingAddress")
            
            if (shippingAddress != null) {
                val countryCode = shippingAddress.optString("countryCode", "")
                val state = shippingAddress.optString("state", "")
                val city = shippingAddress.optString("city", "")
                val postalCode = shippingAddress.optString("postalCode", "")
                
                // Validate if we can ship to this location
                if (!canShipToCountry(countryCode)) {
                    return@PayPalComponentConfig "reject:COUNTRY_ERROR"
                }
                
                // Check state restrictions
                if (hasStateRestrictions(state)) {
                    return@PayPalComponentConfig "reject:STATE_RESTRICTED"
                }
                
                // Calculate new shipping cost
                val shippingCost = calculateShipping(
                    country = countryCode,
                    state = state,
                    city = city,
                    postalCode = postalCode
                )
                
                // Calculate tax
                val taxAmount = calculateTax(shippingAddress, baseAmount)
                
                // Update order totals
                updateOrderTotals(
                    shippingCost = shippingCost,
                    taxAmount = taxAmount
                )
                
                Log.d("PayPal", "Shipping validated and costs updated")
                return@PayPalComponentConfig "" // Allow the change
            } else {
                return@PayPalComponentConfig "" // No address provided, allow
            }
        } catch (e: Exception) {
            Log.e("PayPal", "Failed to process address change", e)
            return@PayPalComponentConfig "" // Allow the change on error
        }
    }
)

onShippingOptionsChange

This callback is triggered when the customer selects a different shipping option in the PayPal checkout flow.

You can use it to:

  • Update the total cost based on the shipping method selection.
  • Show updated delivery dates for the selected method.
  • Apply shipping-specific business rules or discounts.
  • Track popular shipping method preferences.

Event data

Event dataDescription
data
ShippingOptionsData
The shipping option change data object.
data.selectedShippingOption
Object
The shipping option selected by the customer.
data.selectedShippingOption.id
String
The unique identifier for the selected shipping option.
data.selectedShippingOption.label
String
The display label for the selected shipping option (e.g., Standard Shipping, Express).
data.selectedShippingOption.type
String
The type of shipping method (e.g., SHIPPING, PICKUP).
data.selectedShippingOption.amount
Object
The cost details for the selected shipping option.
data.selectedShippingOption.amount.currencyCode
String
The three-letter ISO currency code (e.g., USD, EUR).
data.selectedShippingOption.amount.value
Double
The shipping cost amount in the specified currency.

Return value

This callback must return a string. Return an empty string to allow the shipping option change, or return a rejection string (e.g., "reject:METHOD_UNAVAILABLE") to reject it.

Example implementation

val paypalConfig = PayPalComponentConfig(
    onShippingOptionsChange = { data ->
        Log.d("PayPal", "Shipping option changed: $data")
        
        try {
            val jsonObject = JSONObject(data)
            val selectedOption = jsonObject.optJSONObject("selectedShippingOption")
            
            if (selectedOption != null) {
                val optionId = selectedOption.optString("id", "")
                val optionLabel = selectedOption.optString("label", "")
                val amount = selectedOption.optJSONObject("amount")
                val shippingCost = amount?.optDouble("value", 0.0) ?: 0.0
                
                // Track shipping method selection
                analytics.track("paypal_shipping_method_selected", mapOf(
                    "shippingMethod" to optionId,
                    "shippingLabel" to optionLabel,
                    "shippingCost" to shippingCost,
                    "orderValue" to baseAmount,
                    "timestamp" to System.currentTimeMillis()
                ))
                
                // Add insurance for expedited shipping
                val insurance = if (optionId == "expedited" && baseAmount > 50) 2.99 else 0.0
                
                // Calculate carbon offset for standard shipping
                val carbonOffset = if (optionId == "standard") 0.50 else 0.0
                
                // Update order totals
                updateOrderTotals(
                    shippingCost = shippingCost,
                    insurance = insurance,
                    carbonOffset = carbonOffset
                )
                
                Log.d("PayPal", "Shipping option updated: $optionLabel")
            }
            return@PayPalComponentConfig "" // Allow the change
        } catch (e: Exception) {
            Log.e("PayPal", "Failed to process shipping option change", e)
            return@PayPalComponentConfig "" // Allow the change on error
        }
    }
)

onSubmitError

This callback is triggered when there's an error during the order creation or submission process on the PXP side.

You can use it to:

  • Handle PXP-specific errors and validation failures.
  • Display detailed error messages to users.
  • Log submission errors for debugging.
  • Implement retry logic for failed submissions.

Event data

Event dataDescription
error
String
The error message describing the submission failure.

Example implementation

val paypalConfig = PayPalComponentConfig(
    onSubmitError = { error ->
        Log.e("PayPal", "Submission error: $error")
        
        // Log error for debugging
        crashlytics.log("PayPal submission error: $error")
        
        // Handle specific error types
        when {
            error.contains("VALIDATION_ERROR") -> {
                showErrorDialog(
                    title = "Validation Error",
                    message = "Please check your payment details and try again."
                )
            }
            error.contains("INSUFFICIENT_FUNDS") -> {
                showErrorDialog(
                    title = "Insufficient Funds",
                    message = "Insufficient funds in your PayPal account. Please add funds or use a different payment method."
                )
            }
            error.contains("MERCHANT_NOT_ELIGIBLE") -> {
                showErrorDialog(
                    title = "Service Unavailable",
                    message = "PayPal payments are temporarily unavailable. Please try a different payment method."
                )
            }
            else -> {
                showErrorDialog(
                    title = "Submission Error",
                    message = "Payment processing failed. Please try again or contact support."
                )
            }
        }
        
        // Offer alternative payment methods
        showAlternativePaymentMethods()
        
        // Track submission errors
        analytics.track("paypal_submission_error", mapOf(
            "error" to error,
            "timestamp" to System.currentTimeMillis()
        ))
    }
)

onScriptLoaded

This callback is triggered when the PayPal SDK script has been successfully loaded and is ready to use.

You can use it to:

  • Initialise PayPal-related features that depend on the SDK.
  • Show PayPal buttons that were hidden during loading.
  • Track script loading performance.
  • Set up PayPal-specific configurations.

Event data

This callback receives no parameters.

Example implementation

val paypalConfig = PayPalComponentConfig(
    onScriptLoaded = {
        Log.d("PayPal", "PayPal SDK script loaded successfully")
        
        // Track script loading
        analytics.track("paypal_script_loaded", mapOf(
            "timestamp" to System.currentTimeMillis(),
            "loadTime" to getPerformanceMetric("paypal_sdk_load")
        ))
        
        // Hide loading indicator
        hidePayPalLoadingIndicator()
        
        // Show PayPal button
        showPayPalButton()
        
        // Initialise PayPal messaging if needed
        initializePayPalMessaging()
    }
)

onGetConsent

This callback is triggered to get user consent for vaulting (saving) their PayPal account for one-click payments.

You can use it to:

  • Check if user agreed to save their PayPal account.
  • Integrate with consent components.
  • Track consent preferences.
  • Comply with payment method storage regulations.

Event data

This callback receives no parameters.

Example implementation

val consentComponent = createConsentComponent()

val paypalConfig = PayPalComponentConfig(
    enableOneClickPayment = true,
    onGetConsent = {
        // Get consent from component
        val isConsentGranted = consentComponent.getValue() as? Boolean ?: false
        
        // Log consent status
        Log.d("PayPal", "Consent status: $isConsentGranted")
        
        // Track consent
        analytics.track("paypal_consent_status", mapOf(
            "granted" to isConsentGranted,
            "timestamp" to System.currentTimeMillis()
        ))
        
        isConsentGranted
    },
    consentComponent = consentComponent
)

Complete example

Here's a complete example with all event callbacks:

val paypalConfig = PayPalComponentConfig(
    renderType = "standalone",
    fundingSources = "paypal",
    
    onSuccess = { data ->
        val jsonObject = JSONObject(data)
        val orderID = jsonObject.getString("orderID")
        processPaymentSuccess(orderID)
        navController.navigate("success/$orderID")
        return@PayPalComponentConfig "success"
    },
    
    onError = { error ->
        Log.e("PayPal", "Error: $error")
        showErrorDialog(error)
    },
    
    onCancel = {
        Log.d("PayPal", "Cancelled")
        showCancelMessage()
    },
    
    onOrderCreated = { data ->
        val jsonObject = JSONObject(data)
        val orderID = jsonObject.getString("providerTransactionId")
        trackOrderCreation(orderID)
        return@PayPalComponentConfig "order_created"
    },
    
    onShippingAddressChange = { data ->
        validateAndUpdateShipping(data)
        return@PayPalComponentConfig ""
    },
    
    onShippingOptionsChange = { data ->
        updateShippingCosts(data)
        return@PayPalComponentConfig ""
    },
    
    onSubmitError = { error ->
        Log.e("PayPal", "Submit error: $error")
        handleSubmitError(error)
    },
    
    onScriptLoaded = {
        Log.d("PayPal", "Script loaded")
        hideLoadingIndicator()
    },
    
    onGetConsent = {
        consentComponent.getValue() as? Boolean ?: false
    }
)