Learn about validation requirements for PayPal payout data in your Android app.
The PayPal Android SDK validates payout data at multiple stages to ensure successful transactions. Understanding these validation rules helps you prevent errors and provide better user experiences.
Validation occurs at three key stages:
- SDK initialisation: Validates transaction data and configuration.
- Component creation: Validates component-specific configuration.
- Payout submission: Validates wallet details and payout parameters before sending to the backend.
| Rule | Description | Error |
|---|---|---|
| Amount required | Amount must be provided. | Validation error. |
| Positive value | Amount must be greater than zero. | PO02: "Transaction amount should be greater than 0." |
| Numeric value | Amount must be a valid number. | Validation error. |
// Valid amounts
transactionData = TransactionData(
amount = 100.0, // Valid
amount = 0.01, // Valid: minimum positive value
amount = 999999.99 // Valid
)
// Invalid amounts
transactionData = TransactionData(
amount = 0.0, // Invalid: must be > 0
amount = -50.0 // Invalid: cannot be negative
)| Rule | Description | Error |
|---|---|---|
| Currency required | Currency must be provided. | Validation error. |
| Format | Must be a valid 3-letter ISO currency code. | PO03: "Invalid currency code". |
| Supported | Must be supported by PayPal. | Validation error. |
// Valid currencies
transactionData = TransactionData(
currency = "USD", // Valid
currency = "EUR", // Valid
currency = "GBP" // Valid
)
// Invalid currencies
transactionData = TransactionData(
currency = "", // Invalid: empty
currency = "US", // Invalid: not 3 letters
currency = "DOLLAR" // Invalid: not ISO code
)| Rule | Description | Error |
|---|---|---|
| Entry type required | Entry type must be provided. | Error during initialisation. |
| Value | Must be EntryType.Ecom for payouts. | Error during initialisation. |
// Valid entry type for payouts
transactionData = TransactionData(
entryType = EntryType.Ecom // Required for payouts
)
// Invalid entry types
transactionData = TransactionData(
entryType = EntryType.Moto // Not supported for payouts
)| Rule | Description | Error |
|---|---|---|
| Intent required | Intent must be provided. | Error during initialisation. |
| Value | Must be TransactionIntentData(paypal = IntentType.Payout) for payouts. | Error during initialisation. |
// Valid intent for payouts
transactionData = TransactionData(
intent = TransactionIntentData(paypal = IntentType.Payout) // Required for payouts
)
// Invalid intents
transactionData = TransactionData(
intent = TransactionIntentData(paypal = IntentType.Purchase) // Not for payouts
intent = TransactionIntentData(paypal = IntentType.Authorisation) // Not for payouts
)| Rule | Description | Error |
|---|---|---|
| Email required | PayPal email must be provided for withdrawal flow. | PO04: "Receiver cannot be empty". |
| PayerId required | PayPal payer ID must be provided for withdrawal flow. | PO04: "Payer ID is required for PayPal wallet payout". |
| Email format | Email must be valid format (max 127 characters). | PO04: "Invalid email format". |
// Valid PayPal wallet (withdrawal flow)
paypalConfig = PaypalConfig(
payout = PayoutConfig(
proceedPayoutWithSdk = true,
paypalWallet = PayPalPayOutWalletConfig(
email = "customer@example.com", // Required
payerId = "PAYER_ID_XXX" // Required
)
)
)
// Invalid PayPal wallet
paypalConfig = PaypalConfig(
payout = PayoutConfig(
proceedPayoutWithSdk = true,
paypalWallet = PayPalPayOutWalletConfig(
email = "customer@example.com",
payerId = "" // Invalid: empty payer ID
)
)
)| Rule | Description | Error |
|---|---|---|
| Supported values | Only "Paypal" is currently supported (case-sensitive). | PO04: "Invalid recipient wallet. Only 'Paypal' is supported." |
| Default value | Empty/blank values default to "Paypal". | N/A |
// Valid recipient wallet
PayoutSubmissionComponentConfig(
recipientWallet = "Paypal" // Valid (case-sensitive)
)
PayoutSubmissionComponentConfig(
recipientWallet = "" // Valid: empty/blank defaults to "Paypal"
)
// Invalid recipient wallet
PayoutSubmissionComponentConfig(
recipientWallet = "Venmo" // Not supported on Android
)
PayoutSubmissionComponentConfig(
recipientWallet = "paypal" // Invalid: case-sensitive (must be "Paypal")
)| Error code | Description | Solution |
|---|---|---|
PO02 | Transaction amount should be greater than 0. | Provide a positive amount value. |
PO03 | Invalid currency code. | Use a valid 3-letter ISO currency code. |
PO04 | Invalid recipient. | Ensure paypalWallet.email and paypalWallet.payerId are provided correctly. |
PO07 | Invalid merchant transaction date. | Use ISO 8601 format (e.g., 2025-10-28T10:00:00Z). |
Validate data before SDK initialisation:
fun validatePayoutData(amount: Double, currency: String): ValidationResult {
return when {
amount <= 0 -> ValidationResult(
isValid = false,
message = "Amount must be greater than zero"
)
currency.length != 3 -> ValidationResult(
isValid = false,
message = "Currency must be 3-letter ISO code"
)
else -> ValidationResult(isValid = true)
}
}
// Use validation before initialisation
val validation = validatePayoutData(amount, currency)
if (!validation.isValid) {
showError(validation.message)
return
}
// Proceed with SDK initialisation
val pxpCheckout = PxpCheckout.builder()
.withConfig(config)
.build()Show user-friendly error messages:
onError = { error ->
val userMessage = when (error.errorCode) {
"PO02" -> "The payout amount must be greater than zero."
"PO03" -> "Please specify a valid currency."
"PO04" -> "Please verify your PayPal account information."
"PO07" -> "Invalid transaction date."
else -> "An error occurred: ${error.errorReason}"
}
showError(userMessage)
}Implement comprehensive error logging:
onError = { error ->
// Log for debugging
Log.e("Payout", """
Validation error occurred:
Code: ${error.errorCode}
Reason: ${error.errorReason}
HTTP Status: ${error.httpStatusCode}
Correlation ID: ${error.correlationId}
""".trimIndent())
// Track in analytics
trackEvent("payout_validation_error", mapOf(
"errorCode" to error.errorCode,
"errorReason" to error.errorReason
))
// Show user-friendly message
showError(getUserFriendlyMessage(error))
}Perform custom validation before payout:
onPrePayoutSubmit = {
// Validate balance
val balance = getUserBalance()
if (balance < payoutAmount) {
showError("Insufficient balance. Available: $$balance")
return@PayoutSubmissionComponentConfig PrePayoutSubmitResult(isApproved = false)
}
// Validate daily limit
val dailyTotal = getTodayPayoutTotal()
if (dailyTotal + payoutAmount > DAILY_LIMIT) {
showError("Daily payout limit exceeded")
return@PayoutSubmissionComponentConfig PrePayoutSubmitResult(isApproved = false)
}
// Validate minimum payout
if (payoutAmount < MINIMUM_PAYOUT) {
showError("Minimum payout amount is $$MINIMUM_PAYOUT")
return@PayoutSubmissionComponentConfig PrePayoutSubmitResult(isApproved = false)
}
// All validations passed
PrePayoutSubmitResult(isApproved = true)
}Implement your own business rules:
data class PayoutValidationRules(
val minimumAmount: Double = 10.0,
val maximumAmount: Double = 10000.0,
val dailyLimit: Double = 5000.0,
val requiredVerificationLevel: Int = 2
)
fun validatePayout(
amount: Double,
customerVerificationLevel: Int,
todayTotal: Double
): ValidationResult {
val rules = PayoutValidationRules()
return when {
amount < rules.minimumAmount -> ValidationResult(
isValid = false,
message = "Minimum payout is $${rules.minimumAmount}"
)
amount > rules.maximumAmount -> ValidationResult(
isValid = false,
message = "Maximum payout is $${rules.maximumAmount}"
)
todayTotal + amount > rules.dailyLimit -> ValidationResult(
isValid = false,
message = "Daily limit of $${rules.dailyLimit} would be exceeded"
)
customerVerificationLevel < rules.requiredVerificationLevel -> ValidationResult(
isValid = false,
message = "Account verification required for payouts"
)
else -> ValidationResult(isValid = true)
}
}