Skip to content

Data validation

Learn about built-in validation and error handling for payout components.

Overview

The payout components include comprehensive validation to ensure data integrity and compliance with PayPal and Venmo requirements. All built-in validation is performed before executing payouts. If validation fails, the SDK will throw a specific exception with detailed error information.

You can handle these errors through the onError callback and display appropriate messages to your customers.

Built-in validation

By default, the payout components validate that:

  • Required fields are provided (amount, currency, recipient wallet details).
  • Amount is a valid positive number greater than zero.
  • Currency codes are valid 3-letter ISO 4217 codes.
  • Email addresses are properly formatted.
  • Phone numbers contain only numeric characters (Venmo).
  • Recipient types match the provided receiver format.
  • Field lengths don't exceed maximum limits.
  • Venmo payouts use USD currency (the only supported currency for Venmo).

Error codes reference

SDK configuration errors

Error code Exception Description Resolution
SDK1000PaypalConfigRequiredExceptionPayPal configuration is required.Ensure paypalConfig is provided in SDK initialisation.

Amount validation errors

Error code Exception Description Resolution
SDK0810PaypalPayoutAmountInvalidExceptionAmount must be a valid number.Provide a valid numeric amount.
SDK0811PaypalPayoutAmountNotPositiveExceptionAmount must be a positive number greater than 0.Ensure amount is greater than zero.
SDK0812PaypalPayoutAmountRequiredExceptionAmount is required.Provide an amount in transactionData.amount.

Currency validation errors

Error code Exception Description Resolution
SDK0813PaypalPayoutCurrencyRequiredExceptionCurrency code must be a non-empty string.Provide a currency code in transactionData.currency.
SDK0814PaypalPayoutCurrencyLengthInvalidExceptionCurrency code must be a 3-letter ISO 4217 code.Use a valid 3-letter code like USD, EUR, GBP.
SDK0815PaypalPayoutCurrencyCodeInvalidExceptionInvalid currency code.Use a valid ISO 4217 currency code.

PayPal receiver validation errors

Error code Exception Description Resolution
SDK0803PaypalPayoutReceiverRequiredExceptionReceiver value is required.Provide a PayPal email or Payer ID.
SDK0804PaypalPayoutReceiverTypeInvalidExceptionInvalid receiver type.Use Email, Phone, PaypalId, or UserHandle.
SDK0805PaypalPayoutReceiverTypeEmailOnlyExceptionReceiver type must be Email.PayPal wallet requires Email as receiver type.
SDK0806PaypalPayoutWalletInvalidExceptionInvalid wallet value.Use Paypal for PayPal payouts.
SDK0807PaypalPayoutWalletRequiresEmailExceptionReceiver type must be Email when wallet is Paypal.Ensure receiver type is Email.
SDK0808PaypalPayoutEmailInvalidExceptionInvalid email format.Provide a valid email address.
SDK0809PaypalPayoutPayerIdRequiredExceptionPayPal Payer ID is required.Provide a PayPal Payer ID or email.
SDK0816PaypalPayoutReceiverTypeRequiredExceptionReceiver type is required.Specify the receiver type (e.g., Email, PaypalId).
SDK0818PaypalPayoutFieldLengthExceededExceptionField exceeds maximum length.Reduce the field length to within limits.

Venmo receiver validation errors

Error code Exception Description Resolution
SDK0900VenmoPayoutWalletInvalidExceptionVenmo wallet is required.Provide venmoWallet configuration.
SDK0901VenmoPayoutReceiverRequiredExceptionReceiver value is required.Provide a Venmo receiver (email, phone, or handle).
SDK0902VenmoPayoutRecipientTypeRequiredExceptionVenmo recipient type is required.Specify recipientType as Email, Phone, or UserHandle.
SDK0903VenmoPayoutRecipientTypeInvalidExceptionInvalid recipient type.Use Email, Phone, or UserHandle.
SDK0904VenmoPayoutPhoneInvalidExceptionInvalid phone format.Phone number must contain only numeric characters.
SDK0905VenmoPayoutCurrencyInvalidExceptionVenmo only supports USD currency.Use USD for Venmo payouts.

Payout submission errors

Error code Exception Description Resolution
SDK1001PayoutRecipientWalletRequiredExceptionRecipient wallet is required.Specify recipientWallet as Paypal or Venmo.
SDK1002PayoutReceiverAndRecipientTypeRequiredExceptionReceiver and recipient type are required.Provide both receiver value and recipient type.
SDK1003UnsupportedPayoutRecipientWalletExceptionUnsupported recipient wallet.Use Paypal or Venmo.
SDK1004PayoutNoteTooLongExceptionPayout note exceeds maximum length.Notes longer than 4000 characters will be automatically truncated with a console warning.

Error handling

Basic error handling

Handle validation errors through the onError callback:

const submitConfig = {
  recipientWallet: "Paypal",
  
  onError: (error) => {
    console.error("Payout error:", error.ErrorCode, error.message);
    
    // Display user-friendly message
    showErrorMessage(error.message);
  }
};

Comprehensive error handling

Implement detailed error handling based on error codes:

const submitConfig = {
  recipientWallet: "Paypal",
  
  onError: (error) => {
    console.error("Payout error:", error);
    
    let userMessage: string;
    let action: string = "";
    
    switch (error.ErrorCode) {
      // Amount errors
      case "SDK0810":
        userMessage = "Invalid withdrawal amount.";
        action = "Please enter a valid number.";
        break;
      case "SDK0811":
        userMessage = "Withdrawal amount must be greater than zero.";
        action = "Please enter a positive amount.";
        break;
      case "SDK0812":
        userMessage = "Withdrawal amount is missing.";
        action = "Please contact support.";
        break;
        
      // Currency errors
      case "SDK0813":
      case "SDK0814":
      case "SDK0815":
        userMessage = "Invalid currency configuration.";
        action = "Please contact support.";
        break;
        
      // PayPal receiver errors
      case "SDK0803":
      case "SDK0809":
        userMessage = "PayPal account information is missing.";
        action = "Please link your PayPal account.";
        break;
      case "SDK0808":
        userMessage = "Invalid PayPal email address.";
        action = "Please update your PayPal email.";
        break;
      case "SDK0818":
        userMessage = "Account information exceeds maximum length.";
        action = "Please contact support.";
        break;
        
      // Venmo receiver errors
      case "SDK0901":
        userMessage = "Venmo account information is missing.";
        action = "Please link your Venmo account.";
        break;
      case "SDK0903":
        userMessage = "Invalid Venmo recipient type.";
        action = "Please contact support.";
        break;
      case "SDK0904":
        userMessage = "Invalid phone number format.";
        action = "Please update your Venmo phone number.";
        break;
      case "SDK0905":
        userMessage = "Venmo only supports USD withdrawals.";
        action = "Please select a different payout method.";
        break;
        
      // Payout submission errors
      case "SDK1001":
      case "SDK1002":
      case "SDK1003":
        userMessage = "Invalid payout configuration.";
        action = "Please contact support.";
        break;
      case "SDK1004":
        userMessage = "Payout note is too long.";
        action = "Notes longer than 4000 characters will be truncated.";
        break;
        
      // Configuration errors
      case "SDK1000":
        userMessage = "Payout is not configured correctly.";
        action = "Please contact support.";
        break;
        
      default:
        userMessage = "An error occurred during withdrawal.";
        action = "Please try again or contact support.";
    }
    
    // Display error to user
    showErrorDialog({
      title: "Withdrawal Error",
      message: userMessage,
      action: action,
      errorCode: error.ErrorCode
    });
    
    // Log for debugging
    logError("payout_validation_error", {
      errorCode: error.ErrorCode,
      errorMessage: error.message,
      timestamp: new Date().toISOString()
    });
  }
};

Custom validation

Pre-payout validation

Run validation before the payout is executed to catch issues early:

const submitConfig = {
  recipientWallet: "Paypal",
  
  onPrePayoutSubmit: async () => {
    try {
      // 1. Validate withdrawal limits
      const limitsCheck = await validateWithdrawalLimits({
        userId: getCurrentUserId(),
        amount: getPayoutAmount(),
        currency: getPayoutCurrency()
      });
      
      if (!limitsCheck.valid) {
        showError(`Withdrawal limit exceeded. Maximum: ${limitsCheck.maxAmount}`);
        return { isApproved: false };
      }
      
      // 2. Verify sufficient balance
      const balanceCheck = await verifyBalance({
        userId: getCurrentUserId(),
        amount: getPayoutAmount()
      });
      
      if (!balanceCheck.sufficient) {
        showError("Insufficient balance for this withdrawal.");
        return { isApproved: false };
      }
      
      // 3. Compliance check
      const complianceCheck = await performComplianceCheck({
        userId: getCurrentUserId(),
        amount: getPayoutAmount(),
        recipientType: getRecipientType()
      });
      
      if (!complianceCheck.passed) {
        showError("This withdrawal requires additional verification.");
        return { isApproved: false };
      }
      
      // 4. Fraud prevention
      const fraudCheck = await checkFraudIndicators({
        userId: getCurrentUserId(),
        amount: getPayoutAmount(),
        ipAddress: getClientIP(),
        deviceFingerprint: getDeviceFingerprint()
      });
      
      if (fraudCheck.riskLevel === "HIGH") {
        showError("This withdrawal has been flagged for review.");
        return { isApproved: false };
      }
      
      // All validations passed
      return { isApproved: true };
      
    } catch (error) {
      console.error("Pre-payout validation failed:", error);
      showError("Unable to validate withdrawal. Please try again.");
      return { isApproved: false };
    }
  }
};

Validate withdrawal limits

Check if the payout amount is within allowed limits:

async function validateWithdrawalLimits(userId: string, amount: number, currency: string) {
  // Get user's withdrawal limits
  const limits = await getUserWithdrawalLimits(userId);
  
  // Check daily limit
  const todayWithdrawals = await getTodayWithdrawals(userId);
  const dailyTotal = todayWithdrawals.reduce((sum, w) => sum + w.amount, 0);
  
  if (dailyTotal + amount > limits.dailyLimit) {
    return {
      valid: false,
      reason: "daily_limit_exceeded",
      remaining: limits.dailyLimit - dailyTotal
    };
  }
  
  // Check monthly limit
  const monthlyWithdrawals = await getMonthlyWithdrawals(userId);
  const monthlyTotal = monthlyWithdrawals.reduce((sum, w) => sum + w.amount, 0);
  
  if (monthlyTotal + amount > limits.monthlyLimit) {
    return {
      valid: false,
      reason: "monthly_limit_exceeded",
      remaining: limits.monthlyLimit - monthlyTotal
    };
  }
  
  // Check minimum withdrawal amount
  if (amount < limits.minimumWithdrawal) {
    return {
      valid: false,
      reason: "below_minimum",
      minimum: limits.minimumWithdrawal
    };
  }
  
  // Check maximum single withdrawal
  if (amount > limits.maximumSingleWithdrawal) {
    return {
      valid: false,
      reason: "exceeds_maximum",
      maximum: limits.maximumSingleWithdrawal
    };
  }
  
  return { valid: true };
}

Validate recipient account

Verify the recipient account is valid and active:

async function validateRecipientAccount(walletType: string, receiver: string) {
  if (walletType === "Paypal") {
    // Validate PayPal email format
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(receiver)) {
      return {
        valid: false,
        reason: "invalid_email_format"
      };
    }
    
    // Check if account is verified (if you have this capability)
    const accountStatus = await checkPayPalAccountStatus(receiver);
    if (accountStatus.restricted) {
      return {
        valid: false,
        reason: "account_restricted"
      };
    }
  }
  
  if (walletType === "Venmo") {
    // Validate based on recipient type
    const recipientType = getVenmoRecipientType();
    
    if (recipientType === "Phone") {
      // Phone must be numeric
      const phoneRegex = /^\+?[0-9]+$/;
      if (!phoneRegex.test(receiver)) {
        return {
          valid: false,
          reason: "invalid_phone_format"
        };
      }
    }
    
    if (recipientType === "Email") {
      const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      if (!emailRegex.test(receiver)) {
        return {
          valid: false,
          reason: "invalid_email_format"
        };
      }
    }
  }
  
  return { valid: true };
}

Calculate fraud risk score

Assess the risk level of a payout request:

async function calculatePayoutRiskScore(payoutData: PayoutData) {
  const factors = {
    // Check velocity - multiple payouts in short time
    velocityScore: await checkPayoutVelocity(payoutData.userId),
    
    // Check if payout destination is new
    destinationScore: await checkDestinationHistory(payoutData.userId, payoutData.receiver),
    
    // Check amount patterns
    amountScore: await analyzeAmountPatterns(payoutData.userId, payoutData.amount),
    
    // Check device/location consistency
    deviceScore: await checkDeviceConsistency(payoutData.userId, payoutData.deviceData),
    
    // Check time patterns
    timeScore: await checkTimePatterns(payoutData.userId)
  };
  
  // Calculate weighted average
  const weights = {
    velocityScore: 0.25,
    destinationScore: 0.20,
    amountScore: 0.20,
    deviceScore: 0.20,
    timeScore: 0.15
  };
  
  const totalScore = Object.entries(factors).reduce((sum, [key, score]) => {
    return sum + (score * weights[key as keyof typeof weights]);
  }, 0);
  
  return {
    score: totalScore,
    riskLevel: totalScore > 0.8 ? "HIGH" : totalScore > 0.5 ? "MEDIUM" : "LOW",
    factors: factors,
    requiresReview: totalScore > 0.7
  };
}

Validation best practices

Client-side validation

Always validate on the client side before submission:

function validatePayoutBeforeSubmit() {
  const errors: string[] = [];
  
  // Validate amount
  const amount = getPayoutAmount();
  if (!amount || amount <= 0) {
    errors.push("Please enter a valid withdrawal amount.");
  }
  
  // Validate recipient is selected
  const recipientWallet = getSelectedWallet();
  if (!recipientWallet) {
    errors.push("Please select a payout method.");
  }
  
  // Validate wallet-specific requirements
  if (recipientWallet === "Venmo" && getCurrency() !== "USD") {
    errors.push("Venmo only supports USD withdrawals.");
  }
  
  if (errors.length > 0) {
    showValidationErrors(errors);
    return false;
  }
  
  return true;
}

Display meaningful error messages

Map technical errors to user-friendly messages:

const errorMessages: Record<string, { title: string; message: string; action: string }> = {
  "SDK0810": {
    title: "Invalid Amount",
    message: "The withdrawal amount is not valid.",
    action: "Please enter a valid number."
  },
  "SDK0811": {
    title: "Invalid Amount",
    message: "The withdrawal amount must be greater than zero.",
    action: "Please enter a positive amount."
  },
  "SDK0808": {
    title: "Invalid Email",
    message: "The PayPal email address is not valid.",
    action: "Please check your PayPal email and try again."
  },
  "SDK0904": {
    title: "Invalid Phone",
    message: "The phone number format is not valid.",
    action: "Please enter a valid phone number with only digits."
  },
  "SDK0905": {
    title: "Currency Not Supported",
    message: "Venmo only supports USD withdrawals.",
    action: "Please use PayPal for non-USD withdrawals."
  },
  "SDK1004": {
    title: "Note Too Long",
    message: "The payout note exceeds the maximum length.",
    action: "Notes longer than 4000 characters will be truncated."
  }
};

function getErrorMessage(errorCode: string) {
  return errorMessages[errorCode] || {
    title: "Error",
    message: "An unexpected error occurred.",
    action: "Please try again or contact support."
  };
}

Log errors for debugging

Always log errors for troubleshooting:

function logPayoutError(error: any, context: Record<string, any>) {
  const errorLog = {
    timestamp: new Date().toISOString(),
    errorCode: error.ErrorCode,
    errorMessage: error.message,
    userId: context.userId,
    payoutAmount: context.amount,
    payoutCurrency: context.currency,
    recipientWallet: context.recipientWallet,
    userAgent: navigator.userAgent,
    url: window.location.href
  };
  
  // Send to logging service
  sendToLoggingService("payout_error", errorLog);
  
  // Console log for development
  console.error("Payout error:", errorLog);
}