{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading"]},"type":"markdown"},"seo":{"title":"Data validation","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":"data-validation","__idx":0},"children":["Data validation"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Learn about built-in validation and implement additional scenarios for Android."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The PayPal component includes comprehensive validation to ensure data integrity and compliance with PayPal's requirements. All built-in validation is performed before creating orders. If it fails, the SDK will trigger the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSubmitError"]}," callback with detailed error information."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can also easily build custom validation, depending on your business needs."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"built-in-validation","__idx":2},"children":["Built-in validation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["By default, the PayPal component validates that:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Fields marked as required are provided."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Maximum length constraints are respected."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["All email, currency code, country code, and date fields are formatted properly."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Valid values are provided for every enum."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"error-codes","__idx":3},"children":["Error codes"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The PayPal component returns structured error codes for different validation failures:"]},{"$$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":{"width":"35%","data-label":"Error code"},"children":["Error code "]},{"$$mdtype":"Tag","name":"th","attributes":{"width":"65%","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":["REQUIRED_FIELD"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["At least one required field is missing."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MAX_LENGTH_EXCEEDED"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["At least one field exceeds its maximum length."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["INVALID_LENGTH"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["At least one field has the incorrect length."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["INVALID_EMAIL_FORMAT"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The email format is invalid."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["INVALID_DATE_FORMAT"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The date format is invalid. It should be in ISO 8601 date format."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["INVALID_ENUM_VALUE"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The enum value is invalid."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["INVALID_SHIPPING_PREFERENCE"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["There's a shipping preference mismatch."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NO_SELECTION_MADE"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No shipping option is selected."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MULTIPLE_SELECTIONS_NOT_ALLOWED"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Multiple shipping options are selected."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CURRENCY_CODE_INVALID"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["There's a currency code inconsistency. For example, due to different currencies in the same request."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"validation-example","__idx":4},"children":["Validation example"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import android.util.Log\n\nval paypalConfig = PayPalComponentConfig(\n    // ... configuration\n    onSubmitError = { error ->\n        Log.e(\"PayPal\", \"Validation error: $error\")\n        \n        // Handle specific validation errors\n        when {\n            error.contains(\"payeeEmailAddress\") -> {\n                showError(\"Invalid email address format\")\n            }\n            error.contains(\"currencyCode\") -> {\n                showError(\"Invalid currency code\")\n            }\n            error.contains(\"REQUIRED_FIELD\") -> {\n                showError(\"Please fill in all required fields\")\n            }\n            error.contains(\"MAX_LENGTH_EXCEEDED\") -> {\n                showError(\"Some fields exceed maximum length\")\n            }\n            else -> {\n                showError(\"Validation failed: $error\")\n            }\n        }\n        \n        // Log for debugging\n        crashlytics.log(\"PayPal validation error: $error\")\n    }\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"custom-validation","__idx":5},"children":["Custom validation"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"pre-authorisation-validation","__idx":6},"children":["Pre-authorisation validation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Run a validation before the PayPal authorisation to catch issues early and prevent failed payments."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import kotlinx.coroutines.launch\n\nval paypalConfig = PayPalComponentConfig(\n    onSuccess = { data ->\n        viewModelScope.launch {\n            try {\n                // 1. Business logic validation\n                val orderValidation = validateOrder(\n                    cartItems = getCartItems(),\n                    customerLocation = getCustomerLocation(),\n                    paymentAmount = getOrderTotal()\n                )\n                \n                if (!orderValidation.isValid) {\n                    throw ValidationException(orderValidation.reason)\n                }\n                \n                // 2. Security validation\n                val securityCheck = performSecurityValidation(\n                    customerIP = getClientIP(),\n                    deviceFingerprint = getDeviceFingerprint(),\n                    paymentHistory = getCustomerPaymentHistory()\n                )\n                \n                if (securityCheck.riskLevel == RiskLevel.HIGH) {\n                    // Require additional verification\n                    val verified = requestAdditionalVerification()\n                    if (!verified) {\n                        throw SecurityException(\"Additional verification required\")\n                    }\n                }\n                \n                // 3. Inventory validation\n                val inventoryCheck = validateInventory(getCartItems())\n                if (!inventoryCheck.allAvailable) {\n                    throw InventoryException(\"Some items are no longer available\")\n                }\n                \n                // 4. Regulatory compliance\n                val complianceCheck = validateCompliance(\n                    customerCountry = getCustomerCountry(),\n                    orderAmount = getOrderTotal(),\n                    productTypes = getProductTypes()\n                )\n                \n                if (!complianceCheck.compliant) {\n                    throw ComplianceException(\"Order does not meet regulatory requirements\")\n                }\n                \n                // If all validations pass, proceed with payment processing\n                processPayPalPayment(data)\n                \n            } catch (e: Exception) {\n                Log.e(\"PayPal\", \"Validation failed\", e)\n                showError(e.message ?: \"Validation failed\")\n            }\n        }\n    }\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"confirmation-screen-validation","__idx":7},"children":["Confirmation screen validation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Run validation on the confirmation screen before capturing funds, to ensure order integrity and prevent capture failures."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"suspend fun confirmAndCaptureOrder(orderID: String) {\n    try {\n        // 1. Re-validate order (things might have changed)\n        val currentOrderState = validateCurrentOrderState(orderID)\n        if (!currentOrderState.isValid) {\n            throw ValidationException(\"Order state has changed since authorisation\")\n        }\n        \n        // 2. Final inventory check\n        val finalInventoryCheck = reserveInventory(orderID)\n        if (!finalInventoryCheck.success) {\n            throw InventoryException(\"Inventory no longer available\")\n        }\n        \n        // 3. Calculate final amounts (shipping, taxes, fees)\n        val finalCalculation = calculateFinalAmounts(orderID)\n        \n        // 4. Validate amount changes are within acceptable limits\n        val authData = getAuthorizationData(orderID)\n        val amountDifference = Math.abs(finalCalculation.total - authData.authorizedAmount)\n        val maxAllowedDifference = authData.authorizedAmount * 0.15 // 15% tolerance\n        \n        if (amountDifference > maxAllowedDifference) {\n            throw ValidationException(\"Final amount differs too much from authorised amount\")\n        }\n        \n        // 5. Capture the payment\n        captureAuthorizedPayment(orderID, finalCalculation.total)\n        \n    } catch (e: Exception) {\n        handleCaptureValidationError(e)\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"validate-geographic-restrictions","__idx":8},"children":["Validate geographic restrictions"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check in real-time if any cart items are restricted in the customer's country to prevent compliance violations."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"data class GeographicValidationResult(\n    val isValid: Boolean,\n    val restrictedItems: List<CartItem>\n)\n\nfun validateGeographicRestrictions(\n    customerCountry: String,\n    cartItems: List<CartItem>\n): GeographicValidationResult {\n    val restrictedItems = cartItems.filter { item -> \n        item.restrictions?.countries?.contains(customerCountry) == true\n    }\n    \n    return GeographicValidationResult(\n        isValid = restrictedItems.isEmpty(),\n        restrictedItems = restrictedItems\n    )\n}\n\n// Usage in PayPal component\nval paypalConfig = PayPalComponentConfig(\n    onSuccess = { data ->\n        viewModelScope.launch {\n            val validation = validateGeographicRestrictions(\n                customerCountry = getCustomerCountry(),\n                cartItems = getCartItems()\n            )\n            \n            if (!validation.isValid) {\n                showError(\n                    \"The following items cannot be shipped to your country: \" +\n                    validation.restrictedItems.joinToString(\", \") { it.name }\n                )\n                return@launch\n            }\n            \n            processPayPalPayment(data)\n        }\n    }\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"calculate-a-risk-score","__idx":9},"children":["Calculate a risk score"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Calculate a comprehensive fraud risk score based on multiple behavioural and historical factors."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"data class RiskFactors(\n    val velocityScore: Double,\n    val locationScore: Double,\n    val deviceScore: Double,\n    val historyScore: Double\n)\n\ndata class FraudRiskResult(\n    val score: Double,\n    val riskLevel: RiskLevel,\n    val factors: RiskFactors\n)\n\nenum class RiskLevel {\n    LOW, MEDIUM, HIGH\n}\n\nsuspend fun calculateFraudScore(transactionData: TransactionData): FraudRiskResult {\n    val factors = RiskFactors(\n        velocityScore = checkPaymentVelocity(transactionData.customerEmail),\n        locationScore = validateLocation(transactionData.ipAddress),\n        deviceScore = analyzeDeviceFingerprint(transactionData.deviceData),\n        historyScore = analyzePaymentHistory(transactionData.customerId)\n    )\n    \n    val totalScore = (factors.velocityScore + factors.locationScore + \n                     factors.deviceScore + factors.historyScore) / 4.0\n    \n    val riskLevel = when {\n        totalScore > 0.8 -> RiskLevel.HIGH\n        totalScore > 0.5 -> RiskLevel.MEDIUM\n        else -> RiskLevel.LOW\n    }\n    \n    return FraudRiskResult(\n        score = totalScore,\n        riskLevel = riskLevel,\n        factors = factors\n    )\n}\n\n// Usage in PayPal component\nval paypalConfig = PayPalComponentConfig(\n    onSuccess = { data ->\n        viewModelScope.launch {\n            val riskResult = calculateFraudScore(\n                TransactionData(\n                    customerEmail = getCurrentCustomerEmail(),\n                    ipAddress = getClientIP(),\n                    deviceData = getDeviceData(),\n                    customerId = getCurrentCustomerId()\n                )\n            )\n            \n            when (riskResult.riskLevel) {\n                RiskLevel.HIGH -> {\n                    Log.w(\"PayPal\", \"High risk transaction detected\")\n                    // Require additional verification\n                    if (!requestAdditionalVerification()) {\n                        showError(\"Additional verification required\")\n                        return@launch\n                    }\n                }\n                RiskLevel.MEDIUM -> {\n                    Log.i(\"PayPal\", \"Medium risk transaction\")\n                    // Optional: Add extra monitoring\n                    flagTransactionForReview(data)\n                }\n                RiskLevel.LOW -> {\n                    Log.d(\"PayPal\", \"Low risk transaction\")\n                }\n            }\n            \n            processPayPalPayment(data)\n        }\n    }\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"shipping-address-validation","__idx":10},"children":["Shipping address validation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Validate shipping addresses in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onShippingAddressChange"]}," callback."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"import org.json.JSONObject\n\nval paypalConfig = PayPalComponentConfig(\n    onShippingAddressChange = { data ->\n        try {\n            val jsonObject = JSONObject(data)\n            val shippingAddress = jsonObject.optJSONObject(\"shippingAddress\")\n            \n            if (shippingAddress != null) {\n                val countryCode = shippingAddress.optString(\"countryCode\", \"\")\n                val postalCode = shippingAddress.optString(\"postalCode\", \"\")\n                val city = shippingAddress.optString(\"city\", \"\")\n                val state = shippingAddress.optString(\"state\", \"\")\n                \n                // Validate country\n                if (!isSupportedCountry(countryCode)) {\n                    return@PayPalComponentConfig \"reject:COUNTRY_NOT_SUPPORTED\"\n                }\n                \n                // Validate postal code format\n                if (!isValidPostalCode(postalCode, countryCode)) {\n                    return@PayPalComponentConfig \"reject:INVALID_POSTAL_CODE\"\n                }\n                \n                // Check PO Box restrictions\n                val addressLine1 = shippingAddress.optString(\"addressLine1\", \"\")\n                if (containsPOBox(addressLine1) && !allowPOBox()) {\n                    return@PayPalComponentConfig \"reject:PO_BOX_NOT_ALLOWED\"\n                }\n                \n                // Validate state for US addresses\n                if (countryCode == \"US\" && !isValidUSState(state)) {\n                    return@PayPalComponentConfig \"reject:INVALID_STATE\"\n                }\n                \n                Log.d(\"PayPal\", \"Address validation passed\")\n                null // Allow the change\n            } else {\n                null\n            }\n        } catch (e: Exception) {\n            Log.e(\"PayPal\", \"Address validation error\", e)\n            null // Allow on error\n        }\n    }\n)\n\n// Helper functions\nfun isSupportedCountry(countryCode: String): Boolean {\n    val supportedCountries = setOf(\"US\", \"GB\", \"CA\", \"AU\", \"DE\", \"FR\", \"IT\", \"ES\")\n    return countryCode in supportedCountries\n}\n\nfun isValidPostalCode(postalCode: String, countryCode: String): Boolean {\n    return when (countryCode) {\n        \"US\" -> postalCode.matches(Regex(\"^\\\\d{5}(-\\\\d{4})?$\"))\n        \"GB\" -> postalCode.matches(Regex(\"^[A-Z]{1,2}\\\\d[A-Z\\\\d]? ?\\\\d[A-Z]{2}$\"))\n        \"CA\" -> postalCode.matches(Regex(\"^[A-Z]\\\\d[A-Z] ?\\\\d[A-Z]\\\\d$\"))\n        else -> postalCode.isNotEmpty()\n    }\n}\n\nfun containsPOBox(address: String): Boolean {\n    val poBoxPatterns = listOf(\n        \"P\\\\.?O\\\\.? Box\",\n        \"PO Box\",\n        \"Post Office Box\"\n    )\n    return poBoxPatterns.any { pattern ->\n        address.contains(Regex(pattern, RegexOption.IGNORE_CASE))\n    }\n}\n\nfun isValidUSState(state: String): Boolean {\n    val validStates = setOf(\n        \"AL\", \"AK\", \"AZ\", \"AR\", \"CA\", \"CO\", \"CT\", \"DE\", \"FL\", \"GA\",\n        \"HI\", \"ID\", \"IL\", \"IN\", \"IA\", \"KS\", \"KY\", \"LA\", \"ME\", \"MD\",\n        \"MA\", \"MI\", \"MN\", \"MS\", \"MO\", \"MT\", \"NE\", \"NV\", \"NH\", \"NJ\",\n        \"NM\", \"NY\", \"NC\", \"ND\", \"OH\", \"OK\", \"OR\", \"PA\", \"RI\", \"SC\",\n        \"SD\", \"TN\", \"TX\", \"UT\", \"VT\", \"VA\", \"WA\", \"WV\", \"WI\", \"WY\"\n    )\n    return state.uppercase() in validStates\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"amount-validation","__idx":11},"children":["Amount validation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Validate transaction amounts to prevent errors and fraud."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"data class AmountValidationResult(\n    val isValid: Boolean,\n    val errors: List<String>\n)\n\nfun validateTransactionAmount(\n    amount: Int,\n    currency: String,\n    customerType: String\n): AmountValidationResult {\n    val errors = mutableListOf<String>()\n    \n    // Minimum amount check\n    val minimumAmount = when (currency) {\n        \"USD\", \"CAD\", \"AUD\" -> 100 // $1.00\n        \"EUR\", \"GBP\" -> 50  // €0.50 or £0.50\n        else -> 100\n    }\n    \n    if (amount < minimumAmount) {\n        errors.add(\"Amount is below minimum of ${minimumAmount / 100.0} $currency\")\n    }\n    \n    // Maximum amount check\n    val maximumAmount = when (customerType) {\n        \"new\" -> 50000 // $500.00 for new customers\n        \"verified\" -> 100000 // $1000.00 for verified\n        \"vip\" -> Int.MAX_VALUE // No limit for VIP\n        else -> 50000\n    }\n    \n    if (amount > maximumAmount) {\n        errors.add(\"Amount exceeds maximum of ${maximumAmount / 100.0} $currency for $customerType customers\")\n    }\n    \n    // Check for suspicious amounts (e.g., exactly $9999.99)\n    if (amount == 999999) {\n        errors.add(\"Suspicious transaction amount detected\")\n    }\n    \n    return AmountValidationResult(\n        isValid = errors.isEmpty(),\n        errors = errors\n    )\n}\n\n// Usage\nval paypalConfig = PayPalComponentConfig(\n    onSuccess = { data ->\n        viewModelScope.launch {\n            val amountValidation = validateTransactionAmount(\n                amount = transactionData.amount,\n                currency = transactionData.currency.toString(),\n                customerType = getCustomerType()\n            )\n            \n            if (!amountValidation.isValid) {\n                showError(amountValidation.errors.joinToString(\", \"))\n                return@launch\n            }\n            \n            processPayPalPayment(data)\n        }\n    }\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"validation-best-practices","__idx":12},"children":["Validation best practices"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Validate early:"]}," Perform validation before showing the PayPal button to prevent user frustration."]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Provide clear feedback:"]}," Show specific, actionable error messages to help users correct issues."]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Log validation errors:"]}," Track validation failures for debugging and improvement."]}]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"fun logValidationError(field: String, error: String, value: Any?) {\n    val errorData = mapOf(\n        \"field\" to field,\n        \"error\" to error,\n        \"value\" to value.toString(),\n        \"timestamp\" to System.currentTimeMillis()\n    )\n    \n    analytics.track(\"validation_error\", errorData)\n    crashlytics.log(\"Validation error: $field - $error\")\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"ol","attributes":{"start":4},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Handle edge cases:"]}," Consider unusual but valid inputs (e.g., international address formats)."]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Test thoroughly:"]}," Test validation with various valid and invalid inputs across different devices and Android versions."]}]}]}]},"headings":[{"value":"Data validation","id":"data-validation","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Built-in validation","id":"built-in-validation","depth":2},{"value":"Error codes","id":"error-codes","depth":3},{"value":"Validation example","id":"validation-example","depth":4},{"value":"Custom validation","id":"custom-validation","depth":2},{"value":"Pre-authorisation validation","id":"pre-authorisation-validation","depth":3},{"value":"Confirmation screen validation","id":"confirmation-screen-validation","depth":3},{"value":"Validate geographic restrictions","id":"validate-geographic-restrictions","depth":3},{"value":"Calculate a risk score","id":"calculate-a-risk-score","depth":3},{"value":"Shipping address validation","id":"shipping-address-validation","depth":3},{"value":"Amount validation","id":"amount-validation","depth":3},{"value":"Validation best practices","id":"validation-best-practices","depth":2}],"frontmatter":{"seo":{"title":"Data validation"}},"lastModified":"2026-06-12T11:56:36.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/components/android/paypal/data-validation","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}