Skip to content

About configuration

Learn about how to configure PayPal payout components for iOS.

Overview

The PayPal iOS SDK provides configurable components for integrating PayPal payouts into your iOS application. Each component is built with SwiftUI and offers comprehensive configuration options for styling, behaviour, and event handling.

Configuration structure

All PayPal payout components follow a consistent configuration pattern:

// Payout submission component
let submissionConfig = PayoutSubmissionComponentConfig(
    submitText: "Withdraw to PayPal",
    submitAccessibilityLabel: "Withdraw funds to PayPal"
)

// Styling
submissionConfig.styles = ButtonStateStyles(
    base: FieldStyle(
        color: .white,
        backgroundColor: Color(red: 0, green: 0.44, blue: 0.73)
    )
)

// Event handlers
submissionConfig.onPostPayout = { result in
    // Handle payout completion
}

Environment and PayPal credentials are configured at SDK initialisation via CheckoutConfig and PayPalConfig. The payout execution mode (proceedPayoutWithSdk) is configured via PayPalConfig.

Basic configuration

Each component can be customised with configuration properties:

// Payout submission component
let submissionConfig = PayoutSubmissionComponentConfig(
    submitText: "Withdraw to PayPal",
    submitAccessibilityLabel: "Withdraw funds to PayPal"
)

// Payout amount component (display only)
let amountConfig = PayoutAmountComponentConfig(
    label: "Payout Amount",
    accessibilityLabel: "Payout amount"
)

// PayPal payout receiver component (display only)
let receiverConfig = PayPalPayoutReceiverComponentConfig(
    label: "PayPal Account",
    accessibilityLabel: "PayPal account email"
)

Component property reference

Each component supports the following configuration properties:

PayoutSubmissionComponentConfig

PropertyDescription
recipientTypePayoutRecipientTypeThe recipient type. Default: .email.
walletPayPalPayoutWalletTypeThe wallet type. Default: .paypal.
submitTextString?Custom text for the submit button. Default: "Withdraw with PayPal".
submitAccessibilityLabelString?Accessibility label for the button. Default: "Withdraw with PayPal".
stylesButtonStateStyles?Custom button styles for different states.
onClick(() -> Void)?Called when the button is clicked (before validation).
onPrePayoutSubmit(() async -> PrePayoutSubmitResult?)?Called for merchant approval before payout (SDK-managed mode only).
onPostPayout((MerchantSubmitResult) -> Void)?Called after payout completes (SDK-managed mode only).
onCancel(() -> Void)?Called when the payout is cancelled.
onError((BaseSdkException) -> Void)?Called when an error occurs. Parameter: error - Exception with errorCode and errorMessage properties.

PayoutAmountComponentConfig

PropertyDescription
labelString?Label text displayed above the amount field.
placeholderString?Placeholder text shown when amount is empty.
guideTextString?Helper text displayed below the amount field.
accessibilityLabelString?Accessibility label for screen readers.
stylesFieldStyle?Custom styling for the container.
inputStylesFieldInputStateStyles?Custom styling for the amount text.
labelStylesFieldLabelStateStyles?Custom styling for the label text.

PayPalPayoutReceiverComponentConfig

PropertyDescription
labelString?Label text displayed above the email field.
placeholderString?Placeholder text shown when field is empty.
guideTextString?Helper text displayed below the email field.
accessibilityLabelString?Accessibility label for screen readers.
applyMaskBoolWhether to mask the email address. Default: true.
showMaskToggleBoolWhether to show a toggle to reveal/hide email. Default: true.
receiverTypePayoutRecipientTypeThe recipient type. Default: .email.
stylesFieldStyle?Custom styling for the container.
inputStylesFieldInputStateStyles?Custom styling for the email text.
labelStylesFieldLabelStateStyles?Custom styling for the label text.
validationsPayPalPayoutReceiverValidationResource?Custom validation error messages.

Error callback type handling: While the onError callback signature accepts Error, the SDK always passes a BaseSdkException instance at runtime, allowing access to .errorCode and .errorMessage properties.

Advanced configuration

For more complex implementations, you can configure styling, callbacks, and additional features:

let submissionConfig = PayoutSubmissionComponentConfig(
    submitText: "Withdraw to PayPal",
    submitAccessibilityLabel: "Withdraw funds to PayPal",
    
    // Custom button styling
    styles: ButtonStateStyles(
        base: FieldStyle(
            color: .white,
            fontSize: 16,
            fontWeight: .semibold,
            backgroundColor: Color(red: 0, green: 0.44, blue: 0.73),
            cornerRadius: 8,
            padding: EdgeInsets(top: 14, leading: 24, bottom: 14, trailing: 24)
        ),
        disabled: FieldStyle(
            backgroundColor: Color(.systemGray5),
            opacity: 0.6
        ),
        loading: FieldStyle(
            backgroundColor: Color(red: 0, green: 0.37, blue: 0.65),
            opacity: 0.9
        )
    ),
    
    // Event handlers
    onClick: {
        print("Submit button clicked")
    },
    
    onPrePayoutSubmit: {
        return await showApprovalDialog()
    },
    
    onPostPayout: { result in
        showSuccessMessage(result.merchantTransactionId)
    },
    
    onError: { error in
        handlePayoutError(error)
    }
)

Styling components

Default styling

All components come with PayPal-branded default styling:

  • Submission button: PayPal blue with collapsed size.
  • Amount display: Read-only field with label.
  • Receiver display: Read-only field with email masking.

Custom styling

Each component offers comprehensive styling options:

  • Colours: Customise all colour properties including backgrounds, text, and states.
  • Typography: Control font sizes, weights, and text styles.
  • Layout: Configure spacing, padding, dimensions, and positioning.
  • Shapes: Adjust corner radius and border styles.
// Custom button styling with states
let buttonStyles = ButtonStateStyles(
    base: FieldStyle(
        color: .white,
        fontSize: 18,
        fontWeight: .bold,
        backgroundColor: Color(red: 0.2, green: 0.7, blue: 0.3),
        borderColor: Color(red: 0.2, green: 0.7, blue: 0.3),
        borderWidth: 0,
        cornerRadius: 12,
        padding: EdgeInsets(top: 16, leading: 32, bottom: 16, trailing: 32),
        opacity: 1.0
    ),
    disabled: FieldStyle(
        color: Color(.systemGray2),
        backgroundColor: Color(.systemGray5),
        opacity: 0.5
    ),
    loading: FieldStyle(
        color: .white,
        backgroundColor: Color(red: 0.15, green: 0.55, blue: 0.25),
        opacity: 0.9
    )
)

let submissionConfig = PayoutSubmissionComponentConfig(
    submitText: "Withdraw to PayPal",
    styles: buttonStyles
)

Field styling for display components

The display components (PayoutAmountComponent, PayPalPayoutReceiverComponent) support field-specific styling:

let amountConfig = PayoutAmountComponentConfig(
    label: "Payout Amount",
    placeholder: "$0.00",
    guideText: "Amount to be sent to your PayPal account",
    accessibilityLabel: "Payout amount",
    styles: FieldStyle(
        backgroundColor: Color(.systemGray6),
        cornerRadius: 12,
        padding: EdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20)
    ),
    inputStyles: FieldInputStateStyles(
        base: FieldStyle(
            color: Color(red: 0.2, green: 0.7, blue: 0.3),
            fontSize: 32,
            fontWeight: .bold,
            textAlignment: .center
        )
    ),
    labelStyles: FieldLabelStateStyles(
        base: FieldStyle(
            color: .secondary,
            fontSize: 14,
            fontWeight: .medium
        )
    )
)

Event handling

All components provide event handlers for user interactions and lifecycle events.

Common event patterns:

  • Click handlers: Called when the button is tapped.
  • Success handlers: Called when operations complete successfully.
  • Error handlers: Called when errors occur.
  • Cancellation handlers: Called when the user cancels the flow.
  • Approval handlers: Called for merchant approval before payout execution.
let submissionConfig = PayoutSubmissionComponentConfig(
    submitText: "Withdraw to PayPal",
    
    // Click handling
    onClick: {
        print("Button clicked")
        showLoadingIndicator()
    },
    
    // Merchant approval (SDK-managed mode)
    onPrePayoutSubmit: {
        let approved = await showApprovalDialog(
            amount: 100.00,
            currency: "USD"
        )
        
        guard approved else { return nil }
        
        return PrePayoutSubmitResult(isApproved: true)
    },
    
    // Success handling
    onPostPayout: { result in
        print("Payout completed: \(result.merchantTransactionId)")
        navigateToSuccessScreen()
    },
    
    // Error handling
    onError: { error in
        print("Payout error: \(error.errorMessage)")
        showErrorDialog(error.errorMessage)
    },
    
    // Cancellation handling
    onCancel: {
        print("User cancelled payout")
        showCancelMessage()
    }
)

Component types

The payout SDK provides components for displaying payout information and executing transactions:

Display components

Use PayoutAmountComponent and PayPalPayoutReceiverComponent to show payout details to users:

// Create amount display
let amountConfig = PayoutAmountComponentConfig(
    label: "Amount"
)
let amountComponent = try pxpCheckout.create(
    .payoutAmount,
    componentConfig: amountConfig
)

// Create receiver display
let receiverConfig = PayPalPayoutReceiverComponentConfig(
    label: "PayPal Account",
    applyMask: true,
    showMaskToggle: true
)
let receiverComponent = try pxpCheckout.create(
    .paypalPayoutReceiver,
    componentConfig: receiverConfig
)

Submission component

Use PayoutSubmissionComponent to provide a button for users to execute the payout:

// Configure SDK with stored credentials
let paypalConfig = PayPalConfig(
    payout: PayPalPayoutConfig(
        paypalWallet: PayPalWallet(
            email: "user@example.com",
            payerId: "PAYERID123ABC",
            proceedPayoutWithSdk: true
        )
    )
)

let submissionConfig = PayoutSubmissionComponentConfig(
    submitText: "Withdraw to PayPal",
    onPostPayout: { result in
        print("Payout completed: \(result.merchantTransactionId)")
    }
)
let submitComponent = try pxpCheckout.create(
    .payoutSubmission,
    componentConfig: submissionConfig
)

Payout execution modes

Configure how payouts are executed via PayPalConfig. The proceedPayoutWithSdk parameter controls whether the SDK or your backend manages payout execution.

SDK-managed payouts

The SDK executes the payout after merchant approval:

let paypalConfig = PayPalConfig(
    payout: PayPalPayoutConfig(
        paypalWallet: PayPalWallet(
            email: "user@example.com",      // From your backend
            payerId: "PAYERID123ABC",       // From your backend
            proceedPayoutWithSdk: true      // SDK manages payout
        )
    )
)

With SDK-managed payouts, implement the onPrePayoutSubmit and onPostPayout callbacks.

Backend-managed payouts (default)

Your backend handles payout execution:

let paypalConfig = PayPalConfig(
    payout: PayPalPayoutConfig(
        paypalWallet: PayPalWallet(
            email: "user@example.com",      // From your backend
            payerId: "PAYERID123ABC",       // From your backend
            proceedPayoutWithSdk: false     // Backend manages payout (default)
        )
    )
)

With backend-managed payouts, your iOS app notifies the backend when the user requests a payout, then your backend executes the payout via the Unity API.

Default behaviour: proceedPayoutWithSdk defaults to false. When false:

  • SDK doessn't execute the payout
  • onPrePayoutSubmit and onPostPayout callbacks aren't triggered.
  • Your backend must handle payout execution.
  • The iOS app notifies the backend when the user initiates a payout.

Best practices

Configure for your brand

Customise the styling to match your app's design:

// Define brand colours
struct BrandColors {
    static let primary = Color(red: 0, green: 0.44, blue: 0.73)
    static let success = Color(red: 0.2, green: 0.7, blue: 0.3)
    static let surface = Color(red: 0.97, green: 0.98, blue: 0.98)
    static let onSurface = Color(red: 0.13, green: 0.15, blue: 0.16)
}

// Apply to components
let submissionConfig = PayoutSubmissionComponentConfig(
    submitText: "Withdraw to PayPal",
    styles: ButtonStateStyles(
        base: FieldStyle(
            color: .white,
            backgroundColor: BrandColors.primary,
            cornerRadius: 8
        )
    )
)

Handle all events

Implement comprehensive event handling:

let submissionConfig = PayoutSubmissionComponentConfig(
    submitText: "Withdraw to PayPal",
    onClick: { handleClick() },
    onPrePayoutSubmit: { await handleApproval() },
    onPostPayout: { handleSuccess($0) },
    onCancel: { handleCancel() },
    onError: { handleError($0) }
)

For more information about events, see Events.

Test different configurations

Test your components in various scenarios:

  • Light and dark mode.
  • Different screen sizes (iPhone, iPad).
  • Various payout amounts.
  • Error conditions.
  • Network failures.

Complete configuration example

Here's a comprehensive example showing all configuration options for a complete payout flow:

import SwiftUI
import PXPCheckoutSDK

// Initialise SDK
let sessionData = SessionData(
    sessionId: "your-session-id",
    hmacKey: "your-hmac-key",
    encryptionKey: "your-encryption-key",
    allowedFundingTypes: nil
)

let transactionData = TransactionData(
    amount: Decimal(100.00),
    currency: "USD",
    entryType: .ecom,
    intent: TransactionIntentData(card: nil, paypal: .payout),
    merchantTransactionId: "payout-\(UUID().uuidString)",
    merchantTransactionDate: { Date() }
)

let paypalConfig = PayPalConfig(
    payout: PayPalPayoutConfig(
        paypalWallet: PayPalWallet(
            email: "user@example.com",      // From your backend
            payerId: "PAYERID123ABC",       // From your backend
            proceedPayoutWithSdk: true
        )
    )
)

let checkoutConfig = CheckoutConfig(
    environment: .test,
    session: sessionData,
    transactionData: transactionData,
    merchantShopperId: "user-123",
    ownerId: "merchant-456",
    paypalConfig: paypalConfig,
    analyticsEvent: { event in
        print("Analytics: \(event.eventName)")
    }
)

let pxpCheckout = try PxpCheckout.initialize(config: checkoutConfig)

// Create amount display component
let amountConfig = PayoutAmountComponentConfig(
    label: "Payout Amount"
)
let amountComponent = try pxpCheckout.create(.payoutAmount, componentConfig: amountConfig)

// Create receiver display component  
let receiverConfig = PayPalPayoutReceiverComponentConfig(
    label: "PayPal Account",
    applyMask: true,
    showMaskToggle: true
)
let receiverComponent = try pxpCheckout.create(.paypalPayoutReceiver, componentConfig: receiverConfig)

// Create submission component with full configuration
let submissionConfig = PayoutSubmissionComponentConfig(
    recipientType: .email,
    wallet: .paypal,
    submitText: "Withdraw to PayPal",
    submitAccessibilityLabel: "Withdraw funds to PayPal",
    
    // Custom styling
    styles: ButtonStateStyles(
        base: FieldStyle(
            color: .white,
            fontSize: 16,
            fontWeight: .semibold,
            backgroundColor: Color(red: 0, green: 0.44, blue: 0.73),
            borderColor: Color(red: 0, green: 0.44, blue: 0.73),
            borderWidth: 0,
            cornerRadius: 8,
            padding: EdgeInsets(top: 14, leading: 24, bottom: 14, trailing: 24),
            opacity: 1.0
        ),
        disabled: FieldStyle(
            color: Color(.systemGray),
            backgroundColor: Color(.systemGray5),
            borderColor: Color(.systemGray5),
            opacity: 0.6
        ),
        loading: FieldStyle(
            color: .white,
            backgroundColor: Color(red: 0, green: 0.37, blue: 0.65),
            opacity: 0.9
        )
    ),
    
    // Event handlers
    onClick: {
        print("Withdraw button clicked")
        Analytics.track("payout_initiated")
    },
    
    onPrePayoutSubmit: {
        print("Approval requested")
        
        // Show confirmation dialog
        let approved = await showPayoutApprovalDialog(
            amount: 100.00,
            currency: "USD"
        )
        
        guard approved else {
            Analytics.track("payout_approval_rejected")
            return nil
        }
        
        Analytics.track("payout_approval_granted")
        
        return PrePayoutSubmitResult(isApproved: true)
    },
    
    onPostPayout: { result in
        print("Payout successful!")
        print("Merchant TX ID: \(result.merchantTransactionId)")
        print("System TX ID: \(result.systemTransactionId)")
        
        Analytics.track("payout_completed", properties: [
            "transactionId": result.merchantTransactionId
        ])
        
        navigateToSuccessScreen(result.merchantTransactionId)
    },
    
    onCancel: {
        print("User cancelled payout")
        Analytics.track("payout_cancelled")
        showCancelMessage()
    },
    
    onError: { error in
        print("Payout error: \(error.errorCode) - \(error.errorMessage)")
        
        Analytics.track("payout_error", properties: [
            "errorCode": error.errorCode,
            "errorMessage": error.errorMessage
        ])
        
        showErrorDialog(error.errorMessage)
    }
)

// Create submission component
let submitComponent = try pxpCheckout.create(
    .payoutSubmission,
    componentConfig: submissionConfig
)

// Render in SwiftUI
VStack(spacing: 16) {
    amountComponent.buildContent()
    receiverComponent.buildContent()
    submitComponent.buildContent()
}

Next steps

Now that you understand component configuration fundamentals, dive into the detailed documentation for each component: