{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","admonition","br","details","required"]},"type":"markdown"},"seo":{"title":"Confirm payment flow","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":"confirm-payment-flow","__idx":0},"children":["Confirm payment flow"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Authorise a payment, then capture it before it expires on Android."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The confirm payment flow is designed for scenarios where you need to authorise payment first, then capture it after additional confirmation steps, making it ideal for complex orders, inventory checks, or when manual review is required."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If the funds aren't captured within the appropriate time limit (29 days), then the authorisation expires."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"payment-flow","__idx":2},"children":["Payment flow"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The PayPal confirm payment flow consists of six key steps with authorisation and capture separation."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1-submission","__idx":3},"children":["Step 1: Submission"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The customer taps the PayPal button, which triggers the payment flow. The SDK validates the PayPal configuration and transaction data before proceeding to order creation. If validation fails, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," is triggered."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2-order-creation","__idx":4},"children":["Step 2: Order creation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The SDK creates a PayPal order using the provided transaction details. This involves sending the payment amount, currency, merchant information, and any additional order details to PayPal's API for authorisation. If order creation fails, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," is triggered."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-3-paypal-approval","__idx":5},"children":["Step 3: PayPal approval"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The customer is redirected to PayPal (via WebView) where they log in and approve the payment authorisation. PayPal handles all authentication and payment method selection within their secure environment."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This step has three associated callbacks:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]},": Proceeds with payment authorisation if the customer successfully approves it."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onCancel"]},": Cancels the transaction if the customer cancels the payment."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]},":  Receives error data if any error occurs during the approval process."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-4-return-to-merchant","__idx":6},"children":["Step 4: Return to merchant"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["After PayPal approval, the customer returns to your app with the authorised payment. The funds are authorised but not yet captured, giving you the opportunity to show order confirmation. This happens within your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback handler where you typically navigate to a confirmation screen."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-5-order-confirmation","__idx":7},"children":["Step 5: Order confirmation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The customer reviews their final order details on your confirmation screen. This is where you can perform final inventory checks, calculate shipping, or apply additional discounts."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-6-payment-capture","__idx":8},"children":["Step 6: Payment capture"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Once the customer confirms their order, you capture the authorised payment. This is when the funds are actually transferred from the customer's account."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your capture API call will return a success or failure response, which you handle in your backend code."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"implementation","__idx":9},"children":["Implementation"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"before-you-start","__idx":10},"children":["Before you start"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To use the PayPal confirm payment flow in your Android application:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Ensure you have a valid PayPal Business account with API credentials."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Configure your PayPal merchant account to accept the currencies you need."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Set up your merchant configuration in the Unity Portal (API credentials, payment methods, risk settings)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Prepare order confirmation screens for the authorisation-to-capture flow."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Install and configure the PXP Checkout SDK for Android."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1-configure-your-sdk-for-authorisation","__idx":11},"children":["Step 1: Configure your SDK for authorisation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set up your SDK configuration with transaction information for a PayPal authorisation. The SDK uses ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IntentType.Authorisation"]}," for authorisation requests, which PayPal maps to its ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authorize"]}," intent. For capturing funds, use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IntentType.Purchase"]},", which maps to PayPal's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["capture"]}," intent."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Intent Mapping:"]}," The SDK uses ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IntentType.Authorisation"]}," for authorisation requests, which PayPal maps to its \"authorize\" intent. For capturing funds, use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IntentType.Purchase"]},", which maps to PayPal's \"capture\" intent."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import com.pxp.checkout.PxpCheckout\nimport com.pxp.checkout.models.Environment\nimport com.pxp.checkout.models.OwnerType\nimport com.pxp.checkout.models.TransactionData\nimport com.pxp.checkout.models.EntryType\nimport com.pxp.checkout.models.IntentType\nimport com.pxp.checkout.models.CurrencyType\nimport com.pxp.checkout.models.Shopper\nimport com.pxp.checkout.models.ShippingAddress\n\n// FIRST INTENT: Authorisation\nval authPxpCheckout = PxpCheckout.builder()\n    .withConfig(\n        PxpCheckoutConfig(\n            environment = Environment.TEST,\n            session = sessionData,\n            ownerId = \"Unity\",\n            ownerType = OwnerType.MERCHANT_GROUP,\n            transactionData = TransactionData(\n                amount = 2500.0, // Amount in cents ($25.00)\n                currency = \"USD\",\n                entryType = EntryType.Ecom,\n                intent = IntentType.Authorisation, // FIRST INTENT - for authorisation\n                merchantTransactionId = \"auth-${System.currentTimeMillis()}\",\n                merchantTransactionDate = { System.currentTimeMillis() }\n            ),\n            onGetShopper = {\n                Shopper(\n                    id = \"Shopper_01\",\n                    email = \"customer@example.com\",\n                    firstName = \"John\",\n                    lastName = \"Doe\"\n                )\n            },\n            onGetShippingAddress = {\n                ShippingAddress(\n                    addressLine1 = \"123 Main Street\",\n                    city = \"New York\",\n                    state = \"NY\",\n                    postalCode = \"10001\",\n                    countryCode = \"US\"\n                )\n            }\n        )\n    )\n    .withContext(context)\n    .build()\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2-implement-authorisation-callbacks","__idx":12},"children":["Step 2: Implement authorisation callbacks"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement the required callbacks for the PayPal confirm payment flow."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import com.pxp.checkout.components.paypal.PayPalComponentConfig\nimport com.pxp.checkout.components.paypal.types.ShippingPreference\nimport com.pxp.checkout.components.paypal.types.UserAction\nimport org.json.JSONObject\nimport android.util.Log\nimport kotlinx.coroutines.launch\n\nval paypalConfig = PayPalComponentConfig(\n    // Required PayPal configuration\n    payeeEmailAddress = \"merchant@example.com\",\n    paymentDescription = \"Product Purchase\",\n    shippingPreference = ShippingPreference.NoShipping.toString(),\n    userAction = UserAction.Continue.toString(), // For authorisation + confirmation flow\n    renderType = \"standalone\",\n    fundingSources = \"paypal\",\n\n    // REQUIRED: Handle successful payment authorisation\n    onSuccess = { data ->\n        Log.d(\"PayPal\", \"Payment authorised: $data\")\n        \n        viewModelScope.launch {\n            try {\n                // Parse authorisation data\n                val jsonObject = JSONObject(data)\n                val orderID = jsonObject.getString(\"orderID\")\n                val payerID = jsonObject.getString(\"payerID\")\n                \n                // Store authorisation details\n                val authResult = repository.storePayPalAuthorization(\n                    orderID = orderID,\n                    payerID = payerID,\n                    merchantTransactionId = transactionId,\n                    status = \"authorized\"\n                )\n                \n                if (authResult.isSuccess) {\n                    Log.d(\"PayPal\", \"Authorisation stored successfully\")\n                    \n                    // Save to preferences for confirmation screen\n                    saveAuthorizationData(\n                        orderID = orderID,\n                        payerID = payerID,\n                        authorizedAmount = transactionData.amount,\n                        currency = transactionData.currency.toString()\n                    )\n                    \n                    // Navigate to confirmation screen instead of completing payment\n                    navController.navigate(\"order_confirmation/$orderID\")\n                } else {\n                    throw Exception(authResult.error ?: \"Authorisation storage failed\")\n                }\n            } catch (e: Exception) {\n                Log.e(\"PayPal\", \"Authorisation processing error\", e)\n                showError(\"Authorisation failed. Please try again.\")\n            }\n        }\n    },\n\n    // REQUIRED: Handle payment errors\n    onError = { error ->\n        Log.e(\"PayPal\", \"Payment error: $error\")\n        showError(\"Authorisation failed. Please try again.\")\n    },\n\n    // OPTIONAL: Handle payment cancellation\n    onCancel = {\n        Log.d(\"PayPal\", \"Payment cancelled by user\")\n        showMessage(\"Payment was cancelled. Your cart is still saved.\")\n    }\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-3-render-the-authorisation-component","__idx":13},"children":["Step 3: Render the authorisation component"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create and render the PayPal component for the authorisation step."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import androidx.compose.runtime.*\nimport androidx.compose.ui.Modifier\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport com.pxp.checkout.types.ComponentType\n\n@Composable\nfun PayPalAuthorizationScreen(\n    authPxpCheckout: PxpCheckout,\n    paypalConfig: PayPalComponentConfig\n) {\n    val paypalComponent = remember {\n        authPxpCheckout.createComponent(\n            type = ComponentType.PAYPAL,\n            config = paypalConfig\n        )\n    }\n    \n    authPxpCheckout.buildComponentView(\n        component = paypalComponent,\n        modifier = Modifier.fillMaxWidth()\n    )\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-4-handle-order-confirmation-screen","__idx":14},"children":["Step 4: Handle order confirmation screen"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create a separate flow for handling the order confirmation and proceeding with the final capture."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import androidx.compose.foundation.layout.*\nimport androidx.compose.material3.*\nimport androidx.compose.runtime.*\nimport androidx.compose.ui.unit.dp\n\n@Composable\nfun OrderConfirmationScreen(\n    orderID: String,\n    viewModel: PaymentViewModel\n) {\n    var showLoadingSpinner by remember { mutableStateOf(false) }\n    var showSuccessDialog by remember { mutableStateOf(false) }\n    var showErrorDialog by remember { mutableStateOf(false) }\n    var errorMessage by remember { mutableStateOf<String?>(null) }\n    \n    // Retrieve authorisation data\n    val authData = remember { viewModel.getAuthorizationData(orderID) }\n    \n    Column(\n        modifier = Modifier\n            .fillMaxSize()\n            .padding(16.dp),\n        verticalArrangement = Arrangement.spacedBy(16.dp)\n    ) {\n        Text(\n            text = \"Confirm Your Order\",\n            style = MaterialTheme.typography.headlineMedium\n        )\n        \n        // Display order details\n        Card(\n            modifier = Modifier.fillMaxWidth()\n        ) {\n            Column(modifier = Modifier.padding(16.dp)) {\n                Text(\"Order ID: $orderID\")\n                Text(\"Amount: $${authData.authorizedAmount / 100.0}\")\n                Text(\"Currency: ${authData.currency}\")\n            }\n        }\n        \n        // Confirm button\n        Button(\n            onClick = {\n                showLoadingSpinner = true\n                viewModel.captureAuthorizedPayment(\n                    orderID = orderID,\n                    onSuccess = {\n                        showLoadingSpinner = false\n                        showSuccessDialog = true\n                    },\n                    onError = { error ->\n                        showLoadingSpinner = false\n                        errorMessage = error\n                        showErrorDialog = true\n                    }\n                )\n            },\n            modifier = Modifier.fillMaxWidth(),\n            enabled = !showLoadingSpinner\n        ) {\n            if (showLoadingSpinner) {\n                CircularProgressIndicator(\n                    modifier = Modifier.size(24.dp),\n                    color = MaterialTheme.colorScheme.onPrimary\n                )\n            } else {\n                Text(\"Confirm and Pay\")\n            }\n        }\n    }\n    \n    // Success dialog\n    if (showSuccessDialog) {\n        AlertDialog(\n            onDismissRequest = { },\n            title = { Text(\"Payment Successful\") },\n            text = { Text(\"Your payment has been captured successfully!\") },\n            confirmButton = {\n                Button(onClick = {\n                    showSuccessDialog = false\n                    // Navigate to success screen\n                }) {\n                    Text(\"OK\")\n                }\n            }\n        )\n    }\n    \n    // Error dialog\n    if (showErrorDialog) {\n        AlertDialog(\n            onDismissRequest = { },\n            title = { Text(\"Payment Error\") },\n            text = { Text(errorMessage ?: \"An error occurred\") },\n            confirmButton = {\n                Button(onClick = { showErrorDialog = false }) {\n                    Text(\"OK\")\n                }\n            }\n        )\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-5-implement-payment-capture","__idx":15},"children":["Step 5: Implement payment capture"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement the capture logic in your ViewModel or repository."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class PaymentViewModel : ViewModel() {\n    \n    suspend fun captureAuthorizedPayment(\n        orderID: String,\n        onSuccess: (CaptureResult) -> Unit,\n        onError: (String) -> Unit\n    ) {\n        viewModelScope.launch {\n            try {\n                // Retrieve authorisation data\n                val authData = getAuthorizationData(orderID)\n                \n                // Perform final checks (inventory, pricing, etc.)\n                val orderValid = validateOrder(orderID)\n                if (!orderValid) {\n                    throw Exception(\"Order validation failed\")\n                }\n                \n                // Calculate the final amount (may include shipping, taxes, discounts)\n                val finalAmount = calculateFinalAmount(orderID)\n                \n                // Create new SDK configuration for capture\n                val capturePxpCheckout = PxpCheckout.builder()\n                    .withConfig(\n                        PxpCheckoutConfig(\n                            environment = Environment.TEST,\n                            session = sessionData,\n                            ownerId = \"Unity\",\n                            ownerType = OwnerType.MERCHANT_GROUP,\n                            transactionData = TransactionData(\n                                amount = finalAmount.toDouble(), // Final amount\n                                currency = authData.currency,\n                                entryType = EntryType.Ecom,\n                                intent = IntentType.Purchase, // SECOND INTENT - for capture\n                                merchantTransactionId = \"capture-${System.currentTimeMillis()}\",\n                                merchantTransactionDate = { System.currentTimeMillis() },\n                                parentTransactionId = authData.merchantTransactionId // Link to authorisation\n                            ),\n                            onGetShopper = {\n                                Shopper(\n                                    id = \"Shopper_01\",\n                                    email = \"customer@example.com\",\n                                    firstName = \"John\",\n                                    lastName = \"Doe\"\n                                )\n                            },\n                            onGetShippingAddress = {\n                                ShippingAddress(\n                                    addressLine1 = \"123 Main Street\",\n                                    city = \"New York\",\n                                    state = \"NY\",\n                                    postalCode = \"10001\",\n                                    countryCode = \"US\"\n                                )\n                            }\n                        )\n                    )\n                    .withContext(getApplication())\n                    .build()\n                \n                // Execute the capture\n                val captureResult = repository.capturePayPalPayment(\n                    orderID = authData.orderID,\n                    payerID = authData.payerID,\n                    captureAmount = finalAmount\n                )\n                \n                if (captureResult.status == \"COMPLETED\") {\n                    Log.d(\"PayPal\", \"Payment captured successfully\")\n                    \n                    // Store capture confirmation\n                    saveCaptureData(\n                        captureID = captureResult.captureID,\n                        transactionId = captureResult.transactionId,\n                        amount = captureResult.amount,\n                        status = \"completed\"\n                    )\n                    \n                    onSuccess(captureResult)\n                } else {\n                    throw Exception(\"Payment capture failed: ${captureResult.status}\")\n                }\n                \n            } catch (e: Exception) {\n                Log.e(\"PayPal\", \"Capture process failed\", e)\n                handleCaptureError(e, onError)\n            }\n        }\n    }\n    \n    private fun handleCaptureError(error: Exception, onError: (String) -> Unit) {\n        val errorMessage = when {\n            error.message?.contains(\"AUTHORIZATION_EXPIRED\") == true -> {\n                \"Payment authorisation has expired. Please start the payment process again.\"\n            }\n            error.message?.contains(\"INSUFFICIENT_FUNDS\") == true -> {\n                \"Insufficient funds for final payment amount. Please try a different payment method.\"\n            }\n            error.message?.contains(\"CAPTURE_DECLINED\") == true -> {\n                \"Payment capture was declined. Please contact your bank or try a different payment method.\"\n            }\n            error.message?.contains(\"INVALID_AUTHORIZATION\") == true -> {\n                \"Authorisation is no longer valid. Please restart the payment process.\"\n            }\n            else -> {\n                \"Payment capture failed. Please contact support or try again.\"\n            }\n        }\n        onError(errorMessage)\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-6-handle-common-scenarios","__idx":16},"children":["Step 6: Handle common scenarios"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"inventory-validation","__idx":17},"children":["Inventory validation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Validate inventory between authorisation and capture."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"suspend fun validateInventoryForCapture(orderID: String): Boolean {\n    return try {\n        val inventoryCheck = repository.reserveInventory(\n            orderID = orderID,\n            items = getOrderItems(orderID),\n            reservationDuration = 3600 // 1 hour reservation\n        )\n        \n        if (inventoryCheck.success) {\n            Log.d(\"PayPal\", \"Inventory reserved for capture\")\n            true\n        } else {\n            Log.w(\"PayPal\", \"Inventory not available: ${inventoryCheck.message}\")\n            showError(\"Some items are no longer available. Please review your order.\")\n            false\n        }\n    } catch (e: Exception) {\n        Log.e(\"PayPal\", \"Inventory check failed\", e)\n        false\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"shipping-calculation","__idx":18},"children":["Shipping calculation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Calculate final shipping costs during confirmation."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"suspend fun calculateShippingAndTax(\n    orderID: String,\n    shippingAddress: ShippingAddress\n): FinalCalculation {\n    return try {\n        val shippingResult = repository.calculateFinalShipping(\n            orderID = orderID,\n            shippingAddress = shippingAddress,\n            items = getOrderItems(orderID)\n        )\n        \n        if (shippingResult.success) {\n            // Show final total including shipping\n            FinalCalculation(\n                subtotal = shippingResult.subtotal,\n                shippingCost = shippingResult.shippingCost,\n                tax = shippingResult.tax,\n                total = shippingResult.total\n            )\n        } else {\n            throw Exception(\"Shipping calculation failed\")\n        }\n    } catch (e: Exception) {\n        Log.e(\"PayPal\", \"Shipping calculation error\", e)\n        throw e\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"example","__idx":19},"children":["Example"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following example shows a complete PayPal confirm payment implementation with two separate intents."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"phase-1-authorisation-checkout-screen","__idx":20},"children":["Phase 1: Authorisation (checkout screen)"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import androidx.compose.foundation.layout.*\nimport androidx.compose.material3.*\nimport androidx.compose.runtime.*\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.navigation.NavController\nimport com.pxp.checkout.PxpCheckout\nimport com.pxp.checkout.models.PxpCheckoutConfig\nimport com.pxp.checkout.models.TransactionData\nimport com.pxp.checkout.models.EntryType\nimport com.pxp.checkout.models.IntentType\nimport com.pxp.checkout.components.paypal.PayPalComponentConfig\nimport com.pxp.checkout.components.paypal.types.ShippingPreference\nimport com.pxp.checkout.components.paypal.types.UserAction\nimport com.pxp.checkout.components.paypal.types.PayPalButtonStyle\nimport com.pxp.checkout.types.ComponentType\nimport org.json.JSONObject\nimport android.util.Log\nimport kotlinx.coroutines.launch\n\n@Composable\nfun PayPalAuthorizationScreen(\n    viewModel: PaymentViewModel,\n    navController: NavController\n) {\n    var showLoadingSpinner by remember { mutableStateOf(false) }\n    \n    // FIRST INTENT: Authorisation\n    val authPxpCheckout = remember {\n        PxpCheckout.builder()\n            .withConfig(\n                PxpCheckoutConfig(\n                    transactionData = TransactionData(\n                        amount = 2500.0,\n                        currency = \"USD\",\n                        entryType = EntryType.Ecom,\n                        intent = IntentType.Authorisation, // FIRST INTENT - for authorisation\n                        merchantTransactionId = \"auth-${System.currentTimeMillis()}\",\n                        merchantTransactionDate = { System.currentTimeMillis() }\n                    )\n                )\n            )\n            .withContext(LocalContext.current)\n            .build()\n    }\n    \n    val paypalConfig = remember {\n        PayPalComponentConfig(\n            // PayPal configuration for authorisation flow\n            payeeEmailAddress = \"merchant@example.com\",\n            paymentDescription = \"Product Purchase - Review Order\",\n            shippingPreference = ShippingPreference.NoShipping.toString(),\n            userAction = UserAction.Continue.toString(), // Authorisation + confirmation flow\n            renderType = \"standalone\",\n            fundingSources = \"paypal\",\n            \n            // Styling\n            style = PayPalButtonStyle(\n                layout = \"vertical\",\n                color = \"gold\",\n                shape = \"rect\",\n                label = \"paypal\"\n            ),\n\n            // Step 1: Handle payment authorisation\n            onSuccess = { data ->\n                Log.d(\"PayPal\", \"Processing PayPal authorisation\")\n                showLoadingSpinner = true\n                \n                viewModelScope.launch {\n                    try {\n                        val jsonObject = JSONObject(data)\n                        val orderID = jsonObject.getString(\"orderID\")\n                        val payerID = jsonObject.getString(\"payerID\")\n                        \n                        Log.d(\"PayPal\", \"Order ID: $orderID\")\n                        Log.d(\"PayPal\", \"Authorised Amount: $${2500 / 100.0}\")\n                        \n                        // Store authorisation data for capture step\n                        viewModel.saveAuthorizationData(\n                            orderID = orderID,\n                            payerID = payerID,\n                            merchantTransactionId = \"auth-${System.currentTimeMillis()}\",\n                            authorizedAmount = 2500,\n                            currency = \"USD\"\n                        )\n                        \n                        showLoadingSpinner = false\n                        \n                        // Navigate to confirmation screen\n                        navController.navigate(\"order_confirmation/$orderID\")\n                        \n                    } catch (e: Exception) {\n                        Log.e(\"PayPal\", \"Authorisation failed\", e)\n                        showLoadingSpinner = false\n                        showError(\"Authorisation failed: ${e.message}\")\n                    }\n                }\n            },\n\n            onCancel = {\n                Log.d(\"PayPal\", \"PayPal authorisation cancelled by user\")\n                showMessage(\"Payment was cancelled. Your cart is still saved.\")\n            },\n\n            onError = { error ->\n                Log.e(\"PayPal\", \"PayPal authorisation error: $error\")\n                showLoadingSpinner = false\n                showError(\"Authorisation failed. Please try again.\")\n            }\n        )\n    }\n    \n    val paypalComponent = remember(paypalConfig) {\n        authPxpCheckout.createComponent(\n            type = ComponentType.PAYPAL,\n            config = paypalConfig\n        )\n    }\n\n    Column(\n        modifier = Modifier\n            .fillMaxSize()\n            .padding(16.dp),\n        verticalArrangement = Arrangement.spacedBy(16.dp)\n    ) {\n        Text(\n            text = \"Authorise payment\",\n            style = MaterialTheme.typography.headlineMedium\n        )\n        \n        Text(\n            text = \"Amount: $25.00\",\n            style = MaterialTheme.typography.titleMedium\n        )\n        \n        // Mount the authorisation component\n        authPxpCheckout.buildComponentView(\n            component = paypalComponent,\n            modifier = Modifier.fillMaxWidth()\n        )\n        \n        if (showLoadingSpinner) {\n            CircularProgressIndicator()\n        }\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"phase-2-capture-confirmation-screen","__idx":21},"children":["Phase 2: Capture (confirmation screen)"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import androidx.compose.foundation.layout.*\nimport androidx.compose.material3.*\nimport androidx.compose.runtime.*\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.navigation.NavController\nimport com.pxp.checkout.PxpCheckout\nimport com.pxp.checkout.models.PxpCheckoutConfig\nimport com.pxp.checkout.models.TransactionData\nimport com.pxp.checkout.models.EntryType\nimport com.pxp.checkout.models.IntentType\nimport android.util.Log\nimport kotlinx.coroutines.launch\n\n@Composable\nfun PayPalCaptureScreen(\n    orderID: String,\n    viewModel: PaymentViewModel,\n    navController: NavController\n) {\n    var showLoadingSpinner by remember { mutableStateOf(false) }\n    var showSuccessDialog by remember { mutableStateOf(false) }\n    var showErrorDialog by remember { mutableStateOf(false) }\n    var errorMessage by remember { mutableStateOf<String?>(null) }\n    \n    val authData = remember { viewModel.getAuthorizationData(orderID) }\n    \n    // SECOND INTENT: Capture\n    suspend fun captureAuthorizedPayment() {\n        try {\n            showLoadingSpinner = true\n            \n            // Calculate final amount (may be different due to shipping, taxes, etc.)\n            val finalAmount = viewModel.calculateFinalAmount(orderID) // e.g., 2750 ($27.50 with shipping)\n            \n            // Create NEW SDK configuration for capture\n            val capturePxpCheckout = PxpCheckout.builder()\n                .withConfig(\n                    PxpCheckoutConfig(\n                        transactionData = TransactionData(\n                            amount = finalAmount.toDouble(), // Final amount\n                            currency = authData.currency,\n                            entryType = EntryType.Ecom,\n                            intent = IntentType.Purchase, // SECOND INTENT - for capture\n                            merchantTransactionId = \"capture-${System.currentTimeMillis()}\",\n                            merchantTransactionDate = { System.currentTimeMillis() },\n                            parentTransactionId = authData.merchantTransactionId // Link to authorisation\n                        )\n                    )\n                )\n                .withContext(LocalContext.current)\n                .build()\n            \n            // Execute the capture\n            val captureResult = viewModel.repository.capturePayPalAuthorization(\n                authorizationOrderID = authData.orderID,\n                payerID = authData.payerID,\n                captureAmount = finalAmount\n            )\n            \n            showLoadingSpinner = false\n            \n            if (captureResult.status == \"COMPLETED\") {\n                Log.d(\"PayPal\", \"Payment captured successfully\")\n                Log.d(\"PayPal\", \"Captured Amount: $${captureResult.amount / 100.0}\")\n                \n                // Store capture confirmation\n                viewModel.saveCaptureData(\n                    captureID = captureResult.captureID,\n                    transactionId = captureResult.transactionId,\n                    amount = captureResult.amount,\n                    status = \"completed\"\n                )\n                \n                showSuccessDialog = true\n            } else {\n                throw Exception(\"Capture failed: ${captureResult.status}\")\n            }\n            \n        } catch (e: Exception) {\n            Log.e(\"PayPal\", \"Capture process failed\", e)\n            showLoadingSpinner = false\n            \n            errorMessage = when {\n                e.message?.contains(\"AUTHORIZATION_EXPIRED\") == true -> {\n                    \"Authorisation expired. Please restart payment.\"\n                }\n                else -> {\n                    \"Payment capture failed. Please contact support.\"\n                }\n            }\n            showErrorDialog = true\n        }\n    }\n    \n    Column(\n        modifier = Modifier\n            .fillMaxSize()\n            .padding(16.dp),\n        verticalArrangement = Arrangement.spacedBy(16.dp)\n    ) {\n        Text(\n            text = \"Confirm Your Order\",\n            style = MaterialTheme.typography.headlineMedium\n        )\n        \n        Card(modifier = Modifier.fillMaxWidth()) {\n            Column(modifier = Modifier.padding(16.dp)) {\n                Text(\"Order ID: $orderID\")\n                Text(\"Authorised: $${authData.authorizedAmount / 100.0}\")\n            }\n        }\n        \n        Button(\n            onClick = { \n                viewModelScope.launch { \n                    captureAuthorizedPayment() \n                } \n            },\n            modifier = Modifier.fillMaxWidth(),\n            enabled = !showLoadingSpinner\n        ) {\n            if (showLoadingSpinner) {\n                CircularProgressIndicator(modifier = Modifier.size(24.dp))\n            } else {\n                Text(\"Confirm and Pay\")\n            }\n        }\n    }\n    \n    // Success/Error dialogs...\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"callback-data","__idx":22},"children":["Callback data"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This section describes the data received by the different callbacks as part of the PayPal confirm payment flow."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"onsuccess","__idx":23},"children":["onSuccess"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback receives payment approval data when the customer successfully approves the payment in PayPal. The approval data includes the PayPal order ID and payer information needed to capture the payment."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"orderID\": \"7YH53119ML8957234\",\n  \"payerID\": \"ABCDEFGHIJKLM\",\n  \"paymentID\": \"PAYID-ABCDEFG\",\n  \"billingToken\": null,\n  \"facilitatorAccessToken\": \"A21AAFExi...\"\n}\n","lang":"json"},"children":[]},{"$$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":["orderID"]},{"$$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":["The unique PayPal order ID that identifies this payment."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["payerID"]},{"$$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":["The unique PayPal payer ID that identifies the customer who approved the payment."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["paymentID"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The PayPal payment ID for this transaction."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["billingToken"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The billing agreement token if applicable, otherwise ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["null"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["facilitatorAccessToken"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The PayPal facilitator access token for processing the payment."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's an example of what to do with this data:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onSuccess = { data ->\n    Log.d(\"PayPal\", \"Payment approved: $data\")\n    \n    try {\n        // Parse the payment data\n        val jsonObject = JSONObject(data)\n        val orderID = jsonObject.getString(\"orderID\")\n        val payerID = jsonObject.getString(\"payerID\")\n        \n        // Capture the payment immediately for pay now flow\n        viewModelScope.launch {\n            val captureResponse = repository.capturePayPalPayment(\n                orderID = orderID,\n                payerID = payerID,\n                merchantTransactionId = generateTransactionId(),\n                timestamp = System.currentTimeMillis()\n            )\n            \n            if (captureResponse.status == \"COMPLETED\") {\n                // Payment captured successfully\n                Log.d(\"PayPal\", \"Payment captured: ${captureResponse.id}\")\n                \n                // Store transaction record\n                database.insertTransaction(\n                    Transaction(\n                        paypalOrderId = orderID,\n                        paypalPayerId = payerID,\n                        transactionId = captureResponse.id,\n                        amount = captureResponse.amount,\n                        currency = captureResponse.currency,\n                        status = \"completed\",\n                        timestamp = System.currentTimeMillis()\n                    )\n                )\n                \n                // Navigate to success\n                navController.navigate(\"success/$orderID\")\n            } else {\n                throw Exception(\"Payment capture failed: ${captureResponse.status}\")\n            }\n        }\n    } catch (e: Exception) {\n        Log.e(\"PayPal\", \"Payment capture error\", e)\n        showError(\"Payment processing failed. Please contact support.\")\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"onerror","__idx":24},"children":["onError"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," callback receives error information when PayPal payments fail. PayPal errors include specific error names and details to help with troubleshooting."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"name\": \"VALIDATION_ERROR\",\n  \"message\": \"Invalid payment method\",\n  \"details\": [{\n    \"issue\": \"INSTRUMENT_DECLINED\",\n    \"description\": \"The instrument presented was either declined by the processor or bank, or it can't be used for this payment.\"\n  }]\n}\n","lang":"json"},"children":[]},{"$$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":["name"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The error name.",{"$$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":["VALIDATION_ERROR"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["INSTRUMENT_DECLINED"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PAYER_ACTION_REQUIRED"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UNPROCESSABLE_ENTITY"]}]}]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["message"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["A human-readable error message."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's an example of how to handle PayPal errors:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onError = { error ->\n    Log.e(\"PayPal\", \"Payment error: $error\")\n    \n    // Handle specific error types\n    when {\n        error.contains(\"VALIDATION_ERROR\") -> {\n            showErrorDialog(\n                title = \"Validation Error\",\n                message = \"Payment information is invalid. Please try again.\"\n            )\n        }\n        error.contains(\"INSTRUMENT_DECLINED\") -> {\n            showErrorDialog(\n                title = \"Payment Declined\",\n                message = \"Your PayPal payment method was declined. Please try a different payment method.\"\n            )\n        }\n        error.contains(\"PAYER_ACTION_REQUIRED\") -> {\n            showErrorDialog(\n                title = \"Action Required\",\n                message = \"Additional verification required. Please complete the process in PayPal.\"\n            )\n        }\n        error.contains(\"UNPROCESSABLE_ENTITY\") -> {\n            showErrorDialog(\n                title = \"Processing Error\",\n                message = \"This payment cannot be processed. Please contact support.\"\n            )\n        }\n        error.contains(\"INTERNAL_SERVICE_ERROR\") -> {\n            showErrorDialog(\n                title = \"Service Error\",\n                message = \"PayPal service temporarily unavailable. Please try again later.\"\n            )\n        }\n        else -> {\n            showErrorDialog(\n                title = \"Payment Error\",\n                message = \"Payment failed. Please try again or contact support.\"\n            )\n        }\n    }\n    \n    // Log error details for monitoring\n    analytics.track(\"paypal_payment_error\", mapOf(\n        \"errorMessage\" to error,\n        \"timestamp\" to System.currentTimeMillis(),\n        \"paymentMethod\" to \"paypal\"\n    ))\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"oncancel","__idx":25},"children":["onCancel"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onCancel"]}," callback receives no data when the customer cancels the PayPal payment process."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's an example of how to handle cancellations:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"onCancel = {\n    Log.d(\"PayPal\", \"Payment cancelled by user\")\n    \n    // Log cancellation for analytics\n    analytics.track(\"paypal_payment_cancelled\", mapOf(\n        \"timestamp\" to System.currentTimeMillis(),\n        \"paymentMethod\" to \"paypal\"\n    ))\n    \n    // Show user-friendly message\n    showSnackbar(\"Payment was cancelled. Your cart items are still saved.\")\n    \n    // Optional: Offer alternative payment methods\n    showAlternativePaymentOptions()\n}\n","lang":"kotlin"},"children":[]}]},"headings":[{"value":"Confirm payment flow","id":"confirm-payment-flow","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Payment flow","id":"payment-flow","depth":2},{"value":"Step 1: Submission","id":"step-1-submission","depth":3},{"value":"Step 2: Order creation","id":"step-2-order-creation","depth":3},{"value":"Step 3: PayPal approval","id":"step-3-paypal-approval","depth":3},{"value":"Step 4: Return to merchant","id":"step-4-return-to-merchant","depth":3},{"value":"Step 5: Order confirmation","id":"step-5-order-confirmation","depth":3},{"value":"Step 6: Payment capture","id":"step-6-payment-capture","depth":3},{"value":"Implementation","id":"implementation","depth":2},{"value":"Before you start","id":"before-you-start","depth":3},{"value":"Step 1: Configure your SDK for authorisation","id":"step-1-configure-your-sdk-for-authorisation","depth":3},{"value":"Step 2: Implement authorisation callbacks","id":"step-2-implement-authorisation-callbacks","depth":3},{"value":"Step 3: Render the authorisation component","id":"step-3-render-the-authorisation-component","depth":3},{"value":"Step 4: Handle order confirmation screen","id":"step-4-handle-order-confirmation-screen","depth":3},{"value":"Step 5: Implement payment capture","id":"step-5-implement-payment-capture","depth":3},{"value":"Step 6: Handle common scenarios","id":"step-6-handle-common-scenarios","depth":3},{"value":"Inventory validation","id":"inventory-validation","depth":4},{"value":"Shipping calculation","id":"shipping-calculation","depth":4},{"value":"Example","id":"example","depth":3},{"value":"Phase 1: Authorisation (checkout screen)","id":"phase-1-authorisation-checkout-screen","depth":4},{"value":"Phase 2: Capture (confirmation screen)","id":"phase-2-capture-confirmation-screen","depth":4},{"value":"Callback data","id":"callback-data","depth":3},{"value":"onSuccess","id":"onsuccess","depth":4},{"value":"onError","id":"onerror","depth":4},{"value":"onCancel","id":"oncancel","depth":4}],"frontmatter":{"seo":{"title":"Confirm payment flow"}},"lastModified":"2026-02-26T12:14:32.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/components/android/paypal/confirm-payment","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}