Skip to content

Implementation

Learn how to use the PayPal components in your iOS 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 SwiftUI. 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 SwiftUI.

Before you start

To use the PayPal components, you first need to:

Choose your implementation approach

iOS offers two ways to implement PayPal payments, depending on your requirements:

  • Simple PayPal: Use this approach when you need basic PayPal payments without vaulting features. Ideal for guest checkout, simple payments, and digital products.
  • PayPal with vaulting: Manually compose the PayPal button and consent components for vaulting support. This approach gives you the flexibility to offer one-click payments with saved PayPal accounts.

The component lifecycle is automatically managed by SwiftUI across both approaches.

Implement PayPal payments

Step 1: Initialise the SDK

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

import PXPCheckoutSDK

// Create session data (usually obtained from your backend)
let sessionData = SessionData(
    sessionId: "your-session-id",
    hmacKey: "your-hmac-key",
    encryptionKey: "your-encryption-key"
)

// Create transaction data
let transactionData = TransactionData(
    amount: 25.00,
    currency: "USD",
    entryType: .ecom,
    intent: TransactionIntentData(
        card: nil,
        paypal: .authorisation
    ),
    merchantTransactionId: "unique-transaction-id-\(UUID().uuidString)",
    merchantTransactionDate: { Date() }
)

// Create checkout configuration
let checkoutConfig = CheckoutConfig(
    environment: .test, // or .live
    session: sessionData,
    transactionData: transactionData,
    merchantShopperId: "shopper-123",
    ownerId: "owner-456"
)

// Initialise PxpCheckout SDK
let pxpCheckout = try PxpCheckout.initialize(config: checkoutConfig)
ParameterDescription
environment
Environment
required
The environment type.

Possible values:
  • .test: For testing.
  • .live: For live transactions.
session
SessionData
required
Details about the checkout session.
transactionData
TransactionData
required
Details about the transaction.
transactionData.amount
Decimal
required
The transaction amount (e.g., 25.00 for $25).
transactionData.currency
String
The currency code as a string (e.g., "USD", "EUR", "GBP").
transactionData.entryType
EntryType
required
The entry type.

Possible values:
  • .ecom
  • .moto
transactionData.intent
TransactionIntentData
required
The transaction intent data. Use TransactionIntentData(card: CardIntentType?, paypal: PayPalIntentType?).

PayPal intent values:
  • .authorisation
  • .purchase
transactionData.merchantTransactionId
String
required
A unique identifier for this transaction.
transactionData.merchantTransactionDate
() -> Date
required
A closure that returns the current date.
merchantShopperId
String
required
A unique identifier for this shopper.
ownerId
String
required
The identifier of the owner.

Step 2: Configure the component

Create the PayPal button component configuration with basic settings:

let config = PayPalButtonComponentConfig()
config.fundingSource = .paypal
config.payeeEmailAddress = "merchant@example.com"
config.paymentDescription = "Order #12345"
config.shippingPreference = .noShipping
config.userAction = .payNow
ParameterDescription
fundingSource
PayPalFundingSource
The payment method to support.

Possible values:
  • .paypal: Standard PayPal payments
  • .paylater: PayPal Pay Later financing
payeeEmailAddress
String?
Your merchant email address.
paymentDescription
String?
A description of the payment.
shippingPreference
PayPalShippingPreference?
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
PayPalUserAction?
The next step in the payment flow.

Possible values:
  • .payNow: Immediate payment capture.
  • .continueAction: Continue to PayPal for payment.

Step 3: Create and render the component

Create and render the component using SwiftUI:

import SwiftUI
import PXPCheckoutSDK

struct PayPalPaymentView: View {
    @State private var paypalComponent: BaseComponent?
    @State private var isLoading = true
    @State private var errorMessage: String?
    
    var body: some View {
        VStack(spacing: 16) {
            if isLoading {
                ProgressView("Initialising PayPal...")
            } else if let component = paypalComponent {
                component.buildContent()
                    .frame(height: 50)
            } else if let error = errorMessage {
                Text("Error: \(error)")
                    .foregroundColor(.red)
            }
        }
        .padding()
        .onAppear {
            createPayPalComponent()
        }
    }
    
    private func createPayPalComponent() {
        Task {
            do {
                let pxpCheckout = try createPxpCheckout()
                
                let config = PayPalButtonComponentConfig()
                config.fundingSource = .paypal
                
                let component = try pxpCheckout.create(
                    .paypalButton,
                    componentConfig: config
                )
                
                await MainActor.run {
                    paypalComponent = component
                    isLoading = false
                }
            } catch {
                await MainActor.run {
                    errorMessage = error.localizedDescription
                    isLoading = false
                }
            }
        }
    }
}

Step 4: Handle the payment result

Implement event handling callbacks to manage payment outcomes:

let config = PayPalButtonComponentConfig()
config.fundingSource = .paypal

// Payment success handler
config.onApprove = { approvalData in
    print("Payment successful - Order ID: \(approvalData.orderID)")
    print("Payer ID: \(approvalData.payerID)")
    
    // Navigate to success screen or update UI
    navigateToSuccessScreen(approvalData.orderID)
}

// Error handler
config.onError = { error in
    print("Payment error: \(error.errorMessage)")
    
    // Show error message to user
    showErrorDialog("Payment failed. Please try again.")
}

// Cancellation handler
config.onCancel = { error in
    print("Payment cancelled by user")
    
    // Show cancellation message
    showMessage("Payment was cancelled.")
}

Complete examples

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

import SwiftUI
import PXPCheckoutSDK

struct SimplePayPalView: View {
    @State private var pxpCheckout: PxpCheckout?
    @State private var paypalComponent: BaseComponent?
    @State private var isLoading = true
    @State private var paymentStatus: String?
    @State private var showSuccessAlert = false
    @State private var showErrorAlert = false
    
    var body: some View {
        NavigationView {
            VStack(spacing: 16) {
                Text("Complete your payment")
                    .font(.title)
                
                Text("Amount: $25.00")
                    .font(.title3)
                
                if isLoading {
                    ProgressView("Initialising PayPal...")
                } else if let component = paypalComponent {
                    component.buildContent()
                        .frame(height: 50)
                        .padding(.horizontal)
                }
                
                if let status = paymentStatus {
                    Text(status)
                        .foregroundColor(.secondary)
                        .padding()
                }
                
                Spacer()
            }
            .padding()
            .onAppear {
                createPayPalComponent()
            }
            .alert("Payment Successful", isPresented: $showSuccessAlert) {
                Button("OK") {
                    // Dismiss and navigate
                }
            } message: {
                Text(paymentStatus ?? "")
            }
            .alert("Payment Error", isPresented: $showErrorAlert) {
                Button("OK", role: .cancel) { }
            } message: {
                Text(paymentStatus ?? "")
            }
        }
    }
    
    private func createPayPalComponent() {
        Task {
            do {
                // Initialise PxpCheckout SDK
                let sessionData = SessionData(
                    sessionId: "your-session-id",
                    hmacKey: "your-hmac-key",
                    encryptionKey: "your-encryption-key"
                )
                
                let transactionData = TransactionData(
                    amount: 25.00,
                    currency: "USD",
                    entryType: .ecom,
                    intent: TransactionIntentData(
                        card: nil,
                        paypal: .authorisation
                    ),
                    merchantTransactionId: "tx-\(UUID().uuidString)",
                    merchantTransactionDate: { Date() }
                )
                
                let checkoutConfig = CheckoutConfig(
                    environment: .test,
                    session: sessionData,
                    transactionData: transactionData,
                    merchantShopperId: "shopper-123",
                    ownerId: "owner-456"
                )
                
                let pxpCheckout = try PxpCheckout.initialize(config: checkoutConfig)
                self.pxpCheckout = pxpCheckout
                
                // Create PayPal component
                let config = PayPalButtonComponentConfig()
                config.fundingSource = .paypal
                config.payeeEmailAddress = "merchant@example.com"
                config.paymentDescription = "Order #12345"
                
                // Button styling
                config.style = PayPalButtonStyleConfig(
                    color: .gold,
                    label: nil,
                    size: .collapsed,
                    edges: .softEdges
                )
                
                // Event handlers
                config.onApprove = { [self] approvalData in
                    await MainActor.run {
                        paymentStatus = "Payment successful! Order ID: \(approvalData.orderID)"
                        showSuccessAlert = true
                    }
                }
                
                config.onError = { [self] error in
                    await MainActor.run {
                        paymentStatus = "Payment failed: \(error.errorMessage)"
                        showErrorAlert = true
                    }
                }
                
                config.onCancel = { [self] _ in
                    await MainActor.run {
                        paymentStatus = "Payment was cancelled"
                    }
                }
                
                let component = try pxpCheckout.create(
                    .paypalButton,
                    componentConfig: config
                )
                
                await MainActor.run {
                    paypalComponent = component
                    isLoading = false
                }
            } catch {
                await MainActor.run {
                    paymentStatus = "Initialisation error: \(error.localizedDescription)"
                    isLoading = false
                }
            }
        }
    }
}

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.

let config = PayPalButtonComponentConfig()
config.fundingSource = .paypal
config.payeeEmailAddress = "merchant@example.com"
config.paymentDescription = "Premium Subscription"
config.shippingPreference = .noShipping
config.userAction = .payNow
config.locale = "en_US"

// Custom styling
config.style = PayPalButtonStyleConfig(
    color: .blue,
    label: .buyNow,
    size: .expanded,
    edges: .rounded,
    contentInsets: .uniform(12)
)

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.

config.onPreAuthorisation = {
    // Provide additional transaction data before authorisation
    return PayPalTransactionInitData(
        addressVerification: true,
        riskScreeningData: getRiskScreeningData()
    )
}

config.onOrderCreated = { submitResult in
    if let merchantResult = submitResult as? MerchantSubmitResult {
        print("Order created: \(merchantResult.systemTransactionId)")
        // Track order creation for analytics
        trackOrderCreation(merchantResult)
    }
}

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.

do {
    let paypalComponent = try pxpCheckout.create(
        .paypalButton,
        componentConfig: config
    )
    
    // Render component
    paypalComponent.buildContent()
        .frame(height: 50)
} catch {
    print("Failed to initialise PayPal component: \(error.localizedDescription)")
    
    // Show fallback UI or error message to user
    Text("Payment system temporarily unavailable. Please try again later.")
        .foregroundColor(.red)
}

Subscribe to webhooks

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