Implement callbacks to customise your PayPal payment flow for iOS.
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 3D Secure and risk screening.
- Manage different funding sources (PayPal, 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.
The following table lists all events supported by the different PayPal components.
| Event | PayPal button component | Consent component |
|---|---|---|
onApprove | ||
onError | ||
onCancel | ||
onClick | ||
onOrderCreated | ||
onSubmitError | ||
onPreAuthorisation | ||
onGetConsent |
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 the inventory and order status in your system.
- Send order confirmation emails or push notifications to customers.
- Navigate to a success screen in your app.
| Event data | Description |
|---|---|
approvalDataPayPalApprovalData | The payment approval data object from PayPal. |
approvalData.orderIDString | The unique PayPal order identifier for this transaction. |
approvalData.payerIDString | The PayPal payer identifier for the customer who approved the payment. |
let config = PayPalButtonComponentConfig()
config.onApprove = { approvalData in
print("Payment approved: Order ID \(approvalData.orderID)")
// Update your system with the successful payment
updateOrderStatus(
orderId: approvalData.orderID,
status: "completed",
paymentMethod: "paypal"
)
// Update inventory
updateInventory(approvalData.orderID)
// Send confirmation notification
sendPushNotification(
title: "Payment Successful",
body: "Your order \(approvalData.orderID) has been confirmed"
)
// Track successful payment
Analytics.track("paypal_payment_completed", properties: [
"orderId": approvalData.orderID,
"payerID": approvalData.payerID,
"timestamp": Date().timeIntervalSince1970
])
// Navigate to success screen
navigateToSuccessScreen(approvalData.orderID)
}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 | Description |
|---|---|
errorBaseSdkException | The error object containing cancellation details. |
let config = PayPalButtonComponentConfig()
config.onCancel = { error in
print("Payment cancelled by user: \(error.errorMessage)")
// Track cancellation for analytics
Analytics.track("paypal_payment_cancelled", properties: [
"timestamp": Date().timeIntervalSince1970,
"cartValue": getCurrentCartValue(),
"stage": "paypal_checkout"
])
// Preserve cart for later
saveCartForLater()
// Show helpful message
showMessage(
"No worries! Your items are saved. You can complete your purchase anytime.",
duration: 5.0
)
// Offer alternatives after a short delay
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
showAlternativePaymentOptions()
}
// Optional: Schedule abandoned cart notification
scheduleAbandonedCartNotification(delayMinutes: 30)
}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 | Description |
|---|---|
errorBaseSdkException | The error object containing details about what went wrong. |
let config = PayPalButtonComponentConfig()
config.onError = { error in
print("Payment error: \(error.errorMessage)")
// Log error for debugging
Crashlytics.crashlytics().log("PayPal payment error: \(error.errorMessage)")
Crashlytics.crashlytics().record(error: error)
// Handle different error types
let errorMessage: String
let errorCode = error.errorCode
switch errorCode {
case "INSTRUMENT_DECLINED":
errorMessage = "Your PayPal payment was declined. Please try a different payment method or contact PayPal support."
case "PAYER_ACTION_REQUIRED":
errorMessage = "Additional action required in PayPal. Please try again or complete any pending actions in your PayPal account."
case "UNPROCESSABLE_ENTITY":
errorMessage = "There was an issue processing your payment. Please check your payment details and try again."
case let code where code.contains("Network") || code.contains("timeout"):
errorMessage = "Network error. Please check your connection and try again."
default:
errorMessage = "Payment failed. Please try again or use a different payment method."
}
showErrorDialog(
title: "Payment Error",
message: errorMessage
)
// Show alternative payment methods
showAlternativePaymentMethods()
// Track error metrics
Analytics.track("paypal_error", properties: [
"errorCode": errorCode,
"errorMessage": error.errorMessage,
"timestamp": Date().timeIntervalSince1970
])
}This callback is triggered when the PayPal button is clicked, before the payment flow starts.
You can use it to:
- Trigger analytics tracking.
- Perform pre-payment validation.
- Update UI state to show loading indicators.
- Log user interactions.
This callback receives no parameters.
let config = PayPalButtonComponentConfig()
config.onClick = {
print("PayPal button clicked")
// Track button click
Analytics.track("paypal_button_clicked", properties: [
"timestamp": Date().timeIntervalSince1970,
"cartValue": getCurrentCartValue()
])
// Show loading indicator
showLoadingIndicator()
// Perform pre-payment validation
validateCartBeforePayment()
}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 | Description |
|---|---|
submitResultBaseSubmitResult | The order creation response object containing transaction details. |
submitResult.merchantTransactionIdString | Your unique transaction identifier (available after casting to MerchantSubmitResult). |
submitResult.systemTransactionIdString | The PXP transaction ID for tracking within the PXP system (available after casting to MerchantSubmitResult). |
let config = PayPalButtonComponentConfig()
config.onOrderCreated = { submitResult in
print("Order created successfully")
// Cast to MerchantSubmitResult to access transaction IDs
if let merchantResult = submitResult as? MerchantSubmitResult {
print("- Merchant TX ID: \(merchantResult.merchantTransactionId)")
print("- System TX ID: \(merchantResult.systemTransactionId)")
// Store order information
storeOrderInformation(
pxpTransactionId: merchantResult.systemTransactionId,
merchantTransactionId: merchantResult.merchantTransactionId,
status: "created"
)
// Track order creation
Analytics.track("paypal_order_created", properties: [
"pxpTransactionId": merchantResult.systemTransactionId,
"merchantTransactionId": merchantResult.merchantTransactionId,
"timestamp": Date().timeIntervalSince1970
])
}
// Update UI to show order created state
updateOrderStatus("Order created, awaiting payment approval...")
}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 | Description |
|---|---|
errorBaseSdkException | The error object describing the submission failure. |
let config = PayPalButtonComponentConfig()
config.onSubmitError = { error in
print("Submission error: \(error.errorMessage)")
// Log error for debugging
Crashlytics.crashlytics().log("PayPal submission error: \(error.errorMessage)")
// Handle specific error types
let errorMessage: String
let errorCode = error.errorCode
switch errorCode {
case "VALIDATION_ERROR":
errorMessage = "Please check your payment details and try again."
case "INSUFFICIENT_FUNDS":
errorMessage = "Insufficient funds in your PayPal account. Please add funds or use a different payment method."
case "MERCHANT_NOT_ELIGIBLE":
errorMessage = "PayPal payments are temporarily unavailable. Please try a different payment method."
default:
errorMessage = "Payment processing failed. Please try again or contact support."
}
showErrorDialog(
title: "Submission Error",
message: errorMessage
)
// Offer alternative payment methods
showAlternativePaymentMethods()
// Track submission errors
Analytics.track("paypal_submission_error", properties: [
"errorCode": errorCode,
"error": error.errorMessage,
"timestamp": Date().timeIntervalSince1970
])
}This callback is triggered before payment authorisation to provide additional transaction data for PayPal payments.
You can use it to:
- Include address verification details.
- Supply risk screening data with transaction items.
- Provide device session information for fraud prevention.
This callback receives no parameters but returns optional transaction data.
let config = PayPalButtonComponentConfig()
config.onPreAuthorisation = {
print("Pre-authorisation callback triggered")
// Return additional transaction data
return PayPalTransactionInitData(
addressVerification: AddressVerification(
countryCode: "US",
houseNumberOrName: "123",
postalCode: "12345"
),
riskScreeningData: RiskScreeningData(
performRiskScreening: true,
excludeDeviceData: false,
deviceSessionId: "device-session-\(UUID().uuidString)",
items: [
RiskScreeningItem(
price: 25.00,
quantity: 1,
category: "electronics",
sku: "PROD-001"
)
]
)
)
}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.
This callback receives no parameters and returns a Boolean indicating consent status.
// Option 1: Using consent component
let consentComponent = try pxpCheckout.create(
.paypalConsent,
componentConfig: PayPalConsentComponentConfig(
label: "Save my PayPal account"
)
)
let config = PayPalButtonComponentConfig()
config.paypalConsentComponent = consentComponent as? PayPalConsentComponent
// Option 2: Using custom consent logic
config.onGetConsent = {
// Get consent from your custom mechanism
let isConsentGranted = UserDefaults.standard.bool(forKey: "paypal_consent")
// Log consent status
print("Consent status: \(isConsentGranted)")
// Track consent
Analytics.track("paypal_consent_status", properties: [
"granted": isConsentGranted,
"timestamp": Date().timeIntervalSince1970
])
return isConsentGranted
}Here's a complete example with all event callbacks:
let config = PayPalButtonComponentConfig()
config.fundingSource = .paypal
// Click handler
config.onClick = {
print("PayPal button clicked")
showLoadingIndicator()
}
// Pre-authorisation
config.onPreAuthorisation = {
return PayPalTransactionInitData(
riskScreeningData: RiskScreeningData(
performRiskScreening: true,
excludeDeviceData: false,
deviceSessionId: "device-\(UUID().uuidString)",
items: []
)
)
}
// Order created
config.onOrderCreated = { submitResult in
if let merchantResult = submitResult as? MerchantSubmitResult {
print("Order created: \(merchantResult.systemTransactionId)")
trackOrderCreation(merchantResult.systemTransactionId)
}
}
// Payment approved
config.onApprove = { approvalData in
print("Payment approved: \(approvalData.orderID)")
processPaymentSuccess(approvalData.orderID)
navigateToSuccessScreen(approvalData.orderID)
}
// Payment cancelled
config.onCancel = { error in
print("Payment cancelled")
hideLoadingIndicator()
showCancelMessage()
}
// Payment error
config.onError = { error in
print("Payment error: \(error.errorMessage)")
hideLoadingIndicator()
showErrorDialog(error.errorMessage)
}
// Submission error
config.onSubmitError = { error in
print("Submit error: \(error.errorMessage)")
hideLoadingIndicator()
handleSubmitError(error)
}
// Get consent
config.onGetConsent = {
return UserDefaults.standard.bool(forKey: "paypal_consent")
}
// Create component
let paypalComponent = try pxpCheckout.create(
.paypalButton,
componentConfig: config
)