Basic concepts

One of the features of the MoneyHash Android SDK is providing a single state for each step in the payment flow. The state along with stateDetails guide the actions and methods required to proceed and complete the flow.

SDK States Table

StateActionIntent Type
MethodSelectionThe MethodSelection state contains an IntentMethods object with available payment methods. You can render these methods natively with custom styles. After the user selects a method, use proceedWithMethod to proceed.Payment, Payout
FormFieldsRender form fields received in FormFields state, including card fields, billing, and shipping fields. Submit them using submitForm. For more information on card fields, refer to Card Form Fields.Payment, Payout
UrlToRenderUse renderForm to let MoneyHash handle the current stage of the payment/payout flow. After completing the process, MoneyHash will return the intent details or an error.Payment, Payout, CardToken
SavedCardCVVCollect CVV using the schema from stateDetails.cvvField, then use submitCardCVV to proceed with the payment.Payment
IntentFormUse renderForm to let MoneyHash handle the current stage of the payment/payout flow. After completing the process, MoneyHash will return the intent details or an error.Payment, Payout
IntentProcessedDisplay a success confirmation UI with the intent details.Payment, Payout
TransactionFailedDisplay a failure UI with the intent details.Payment, Payout
TransactionWaitingUserActionDisplay a pending actions confirmation UI with the intent details and any externalActionMessage if provided in TransactionData.Payment, Payout
ExpiredDisplay an expired intent UI.Payment, Payout,
CardToken
ClosedDisplay a closed intent UI.Payment, Payout, CardToken
CardIntentSuccessfulDisplay a success UI for the created card token.CardToken
CardIntentFailedDisplay a failure UI for the created card token.CardToken

States Handling

When handling the FormFields state in MoneyHash, you will deal with two primary tasks:

  1. Handling Billing or Shipping Data if billingFields or shippingFields are present and not null.
  2. Handling Card Form if the tokenizeCardInfo is present in the state object and not null.

1. Handling Billing or Shipping Data

  • Rendering Input Fields:

    Use the InputField data in billingFields or shippingFields to render the form fields. Each field has properties like label, name, isRequired, and maxLength that can be used to guide the form's construction.

Example of how to render billing and shipping fields:

if (intentState is IntentStateDetails.FormFields) {
    // Rendering billing fields
    intentState.billingFields?.forEach { field ->
        println("Billing Field: ${field.label}, Required: ${field.isRequired}")
        // Use this information to dynamically render input components
        // Example: Create EditText programmatically using the field data
    }

    // Rendering shipping fields
    intentState.shippingFields?.forEach { field ->
        println("Shipping Field: ${field.label}, Required: ${field.isRequired}")
        // Use this information to dynamically render input components
    }
}
  • Collecting User Input:

    Collect the user input from the form fields and store it in a map for both billing and shipping data. Use each field's name attribute as the key.

Example of collecting billing and shipping data:

val billingData: Map<String, String> = mapOf(
    "firstName" to "John",
    "lastName" to "Doe",
    "email" to "[email protected]"
)

val shippingData: Map<String, String> = mapOf(
    "addressLine1" to "123 Main St",
    "city" to "Anytown",
    "country" to "US"
)

2. Handling Card Form

For the card form, use the tokenizeCardInfo property to handle card data input securely.

3. Submit Form

After collecting the necessary billing, shipping, and card data, the next step is to submit this data using the submitForm method provided by the MoneyHash SDK.

The submitForm method allows you to send the collected information to proceed with the payment or payout process.

import com.moneyhash.sdk.android.core.MoneyHashSDKBuilder

val moneyHashSDK = MoneyHashSDKBuilder
    .setPublicKey("your_public_key")  // Set your public API key here
    .build()

fun submitPayment(intentState: IntentStateDetails) {
    try {
        var billingData: Map<String, String>? = null
        var shippingData: Map<String, String>? = null

        if (intentState is IntentStateDetails.FormFields) {
            // Prepare billing data based on the input fields
            billingData = intentState.billingFields?.associate { field ->
                field.name to "user_input_value" // Replace with actual input values
            }

            // Prepare shipping data based on the input fields
            shippingData = intentState.shippingFields?.associate { field ->
                field.name to "user_input_value" // Replace with actual input values
            }
        }

        // Optionally collect card data if needed
        val cardData: VaultData? = null // Assume card data is collected from card form if tokenizeCardInfo is present

        // Submit the form data
        val intentDetails = moneyHashSDK.submitForm(
            intentId = "your_intent_id",
            selectedMethod = "selected_method_id",
            billingData = billingData,   // Optional
            shippingData = shippingData, // Optional
            cardData = cardData,         // Optional
            saveCard = true              // Set to true to save the card (optional)
        )

        // Handle success
        println("Form submitted successfully: $intentDetails")
    } catch (throwable: Throwable) {
        // Handle error
        println("Error submitting form: ${throwable.message}")
    }
}

In this example:

  • Billing and shipping data are extracted from the fields provided in the FormFields state.
  • The submitForm method sends the data along with the selected payment method and optionally the card data to complete the payment.

The UrlToRender state occurs when you need to render a URL as part of the payment or payout flow. The UrlToRender case in the IntentStateDetails sealed class provides two key properties:

  • url: The URL that needs to be rendered.
  • renderStrategy: A suggestion on how the URL should be rendered (e.g., IFRAME, POPUP_IFRAME, or REDIRECT), using the RenderStrategy enum.

In this state, you should use the renderForm method to handle the payment or payout flow. This method takes care of rendering the URL based on the intent and manages the interaction flow. Once the process is complete (successfully or with an error), it returns the corresponding IntentDetails or throws an exception.

Steps to Handle the UrlToRender State

  1. Invoke the renderForm Method:

    Call the renderForm method with the necessary intentId, intentType, and optional embedStyle to proceed with rendering the form and handling the current stage of the payment or payout flow.

    Example of handling the UrlToRender state:

            val launcher = rememberLauncherForActivityResult(
                IntentContract()
            ) { result ->
                viewModel.setResult(result)
            }
    
            if (intentState is IntentStateDetails.UrlToRender) {
                val intentId = "your_intent_id"
                val intentType = IntentType.Payment // or IntentType.Payout
    
                try {
                    moneyHash.renderForm(
                        intentId = intentId,
                        intentType = intentType,
                        launcher = launcher
                    )
                } catch (throwable: Throwable) {
                    println(throwable)
                }
            }
    
  2. Completion Handling:

    • On Success: The renderForm method returns the IntentDetails object via the ActivityResultLauncher.
    • On Error: If an error occurs during the process, handle it appropriately to display an error message or take corrective action.

The SavedCardCVV state occurs when a saved card requires the user to input their CVV to proceed with the payment. In this state, you will collect the CVV from the user and submit it using the submitCardCVV method.

The SavedCardCVV case in the IntentStateDetails sealed class provides two key properties:

  • cvvField: An InputField object that describes the CVV field, including its label, validation requirements, and other metadata.
  • cardTokenData: Optional information about the saved card for which the CVV is being collected, represented by CardTokenData.

Steps to Handle the SavedCardCVV State

  1. Render the CVV Input Field:

    • Use the cvvField property from the SavedCardCVV state to render the input field for the CVV.
    • Ensure you apply the field validation based on the rules provided in the cvvField.
  2. Retrieve Card Details and CVV Field Information from the State:

    Example of Retrieving Card Details and CVV Field Information:

    if (intentState is IntentStateDetails.SavedCardCVV) {
        // Access card details
        val cardDetails = intentState.cardTokenData
        if (cardDetails != null) {
            val last4 = cardDetails.last4 ?: ""
            val brand = cardDetails.brand ?: "Unknown"
            val expiryMonth = cardDetails.expiryMonth ?: ""
            val expiryYear = cardDetails.expiryYear ?: ""
            val cardHolderName = cardDetails.cardHolderName ?: ""
    
            // Display card information to the user
            println("Using saved card ending with $last4 ($brand) expiring on $expiryMonth/$expiryYear")
            // Optionally, update your UI with this information
        } else {
            println("No card details available.")
        }
    
  3. Collect the CVV Value:

    After the user inputs their CVV, collect the value and validate it based on the constraints provided in cvvField.

  4. Submit the CVV Using submitCardCVV:

    Once you have the CVV from the user, use the submitCardCVV method to submit the CVV and proceed with the payment.

    if (intentState is IntentStateDetails.SavedCardCVV) {
        val cvv = "collected_cvv_here"
    
      	try {
          	val intentDetails = moneyHashSDK.submitCardCVV(
                intentId = "your_intent_id",
                cvv = cvv
            )
            println("Payment processed successfully: $intentDetails")
            // Handle success, e.g., navigate to a confirmation screen
        } catch (throwable: Throwable) { 
          	// Handle error
            println("Error during CVV submission: ${e.message}")
        }
    }
    
  5. Completion Handling:

    • On Success: If the CVV is submitted successfully, the submitCardCVV method returns an IntentDetails object, containing information about the current intent state.
    • On Error: If an error occurs during the CVV submission, handle the exception appropriately by displaying an error message or prompting the user to retry.

The IntentForm state occurs when MoneyHash needs to handle the current stage of the payment or payout flow via the embedded form. In this state, you will use the renderForm method to render the form and handle the completion of the process through the provided ActivityResultLauncher.

The IntentForm case in the IntentStateDetails sealed class indicates that a form is required for the user to enter necessary details to proceed with the intent.

Steps to Handle the IntentForm State

  1. Render the MoneyHash Form:

    Use the renderForm method to render the form within your app, passing the required parameters such as intentId, intentType, and optionally, embedStyle to customize the form's appearance.

  2. Handle Completion or Error:

    The form will guide the user through the payment or payout process. After the user completes the form, MoneyHash will return the IntentDetails via the ActivityResultLauncher.

Example of Handling the IntentForm State

 val launcher = rememberLauncherForActivityResult(
      IntentContract()
 ) { result ->
   viewModel.setResult(result)
}

if (intentState is IntentStateDetails.IntentForm) {
    val intentId = "your_intent_id"
    val intentType = IntentType.Payment // or IntentType.Payout
    val embedStyle: EmbedStyle? = null // Optional: Customize the form's appearance

    moneyHashSDK.renderForm(
        intentId = intentId,
        intentType = intentType,
        embedStyle = embedStyle,
        launcher = launcher
    )
}

In this example:

  • Rendering the Form: The renderForm method is called with the necessary parameters to display the form to the user.
  • Handling Success: If the form is completed successfully, the IntentDetails object is returned via the ActivityResultLauncher, and you can handle the success accordingly.
  • Handling Errors: If an error occurs during form rendering or submission, it is handled in the ActivityResultLauncher callback.

💡

Tip: You can customize the form's appearance by providing an EmbedStyle object, allowing for a more tailored user interface during the form rendering process.


Other Available MoneyHash SDK Methods

In addition to the essential steps and methods previously described, the MoneyHash Android SDK provides other methods to customize the user experience. These additional methods are presented and described below.


In the MoneyHash SDK for Android, you can reset the selected payment method for a specific intent using the resetSelectedMethod method. This allows your customers to go back and choose a different payment method if needed. It can be used in the following scenarios:

  • Offering a button to let the customer return and select a new payment method after they have already selected one.
  • Allowing the customer to retry and choose a different payment method after a failed transaction.

Example of Resetting the Selected Method

// Assume you have an instance of MoneyHashSDK
val moneyHashSDK: MoneyHashSDK = // initialize your SDK instance

// Reset the selected method
fun resetSelectedMethod() {
    try {
        val intentId = "your_intent_id"
        val intentType = IntentType.Payment // or IntentType.Payout

        // Reset the selected method
        val methodsResult: MethodsResult = moneyHashSDK.resetSelectedMethod(
            intentId = intentId,
            intentType = intentType
      	)

        // Handle the result
        val intentDetails = methodsResult.intentDetails
        val intentMethods = methodsResult.intentMethods

        // You can now render available payment methods again for the user to select a different one.
        println("Intent details: $intentDetails")
        println("Available methods: ${intentMethods?.paymentMethods}")

    } catch (throwable: Throwable) {
        // Handle error
        println("Error resetting selected method: ${e.message}")
    }
}

By using this method, you can offer more flexibility to your users during the payment flow, letting them go back and change their payment method even after selection.


In the MoneyHash SDK for Android, you can delete a customer's saved card using the deleteSavedCard method. This is useful when managing a list of customer-saved cards, allowing them to remove a card they no longer wish to keep on file.

Example of Deleting a Saved Card

// Assume you have an instance of MoneyHashSDK
val moneyHashSDK: MoneyHashSDK = // initialize your SDK instance

fun deleteSavedCard() {
  	try {
        val cardTokenId = "your_card_token_id" // The ID of the saved card to be deleted
        val intentSecret = "your_intent_secret" // The intent secret for verification

        // Call the method to delete the saved card
        moneyHashSDK.deleteSavedCard(
            cardTokenId = cardTokenId,
            intentSecret = intentSecret
          )

        println("Card deleted successfully.")

        // Handle any post-deletion logic, like refreshing the card list or showing a confirmation message
   } catch (throwable: Throwable) {
        // Handle error
        println("Error deleting saved card: ${e.message}")
   }
}

By using this method, you can allow users to manage their saved cards within your app, providing the option to delete cards as needed.


In the MoneyHash SDK for Android, you can update the fees associated with an intent using the updateFees method. This method requires the intentId and a list of FeeItem objects, allowing you to adjust the fees at the intent level.

Please note that fees cannot be updated for intents that already have transactions.

Example of Updating Fees

// Assume you have an instance of MoneyHashSDK
val moneyHashSDK: MoneyHashSDK = // initialize your SDK instance

fun updateFees() {
  try {
      val intentId = "your_intent_id" // The ID of the intent to update the fees
      val fees: List<FeeItem> = listOf(
          FeeItem(
              title = mapOf(
                  Language.ENGLISH to "Service Fee",
                  Language.ARABIC to "رسوم الخدمة",
                  Language.FRENCH to "Frais de service"
              ),
              value = "10",
              discount = null
          ),
          FeeItem(
              title = mapOf(
                  Language.ENGLISH to "Handling Fee",
                  Language.ARABIC to "رسوم المناولة",
                  Language.FRENCH to "Frais de manutention"
              ),
              value = "15",
              discount = null
          )
      )

      // Call the method to update the fees
      val updatedFees: FeesData? = moneyHashSDK.updateFees(intentId = intentId, fees = fees)

      if (updatedFees != null) {
       	 println("Fees updated successfully: ${updatedFees.amount}")
      } else {
       	 println("Fees updated successfully.")
      }

      // Handle any post-update logic, like refreshing the fee display
    } catch (throwable: Throwable) {
     	  // Handle error
      	println("Error updating fees: ${e.message}")
    }
}

This method enables you to modify the fees associated with an intent while following the necessary restrictions regarding existing transactions.


In the MoneyHash SDK for Android, you can update the discount for an intent using the updateDiscount method. This method allows you to pass the intentId and a DiscountItem object to adjust the discount on an intent level.

Please note the following restrictions when updating a discount:

  • Discounts can't be updated for intents that have transactions.
  • Can't update discount when the intent has product items that have a discount.
  • Can't update discount when the intent has fees that have a discount.
  • Discount value must not be more than the intent amount.

Example of Updating a Discount

// Assume you have an instance of MoneyHashSDK
val moneyHashSDK: MoneyHashSDK = // initialize your SDK instance

fun updateDiscount() {
  	try {
        val intentId = "your_intent_id" // The ID of the intent to update the discount
        val discount = DiscountItem(
          	title = mapOf(
                Language.ENGLISH to "Promo Code",
                Language.ARABIC to "رمز العرض",
                Language.FRENCH to "Code Promo"
            ),
            type = DiscountType.AMOUNT, // DiscountType.AMOUNT or DiscountType.PERCENTAGE
            value = "10" // Discount value
        	)

        // Call the method to update the discount
        val updatedDiscount: DiscountData? = moneyHashSDK.updateDiscount(
            intentId = intentId,
            discount = discount
        	)

        if (updatedDiscount != null) {
          	println("Discount updated successfully: ${updatedDiscount.amount}")
        } else {
          	println("Discount updated successfully.")
        }

    } catch (throwable: Throwable) {
        // Handle error
        println("Error updating discount: ${e.message}")
    }
}

This method allows you to apply or update a discount on an intent, adhering to the defined conditions and limitations.


In the MoneyHash SDK for Android, you can set the locale to handle localization for different languages by calling the setLocale method and passing the desired SDKLocale enum value.

Example of Setting Locale

// Assume you have an instance of MoneyHashSDK
val moneyHashSDK: MoneyHashSDK = // initialize your SDK instance

// Set the locale to Arabic
moneyHashSDK.setLocale(SDKLocale.ARABIC)
println("Locale set to Arabic successfully")

You can choose from the following languages:

  • SDKLocale.ARABIC
  • SDKLocale.ENGLISH
  • SDKLocale.FRENCH

This allows the SDK to present text and messages in the selected language, enhancing the user experience for a multilingual audience.


To authenticate and make use of the MoneyHash SDK, you need to set your public API key by calling the setPublicKey method. This should be done early in your application's initialization process.

Example of Setting Public Key

// Initialize the SDK using the builder
val sdkBuilder = MoneyHashSDKBuilder()
sdkBuilder.setPublicKey("your_public_api_key")
val moneyHashSDK = sdkBuilder.build()

println("Public key set successfully")

Make sure to replace "your_public_api_key" with your actual public API key.


You can adjust the SDK's log level using the setLogLevel method. The LogLevel enum defines the possible levels of logging, allowing you to control the verbosity of the logs.

Example of Setting Log Level

// Assume you have an instance of MoneyHashSDK
val moneyHashSDK: MoneyHashSDK = // initialize your SDK instance

// Set the log level to 'DEBUG'
moneyHashSDK.setLogLevel(LogLevel.DEBUG)
println("Log level set to DEBUG successfully")

You can set the log level to any of the following options:

  • LogLevel.VERBOSE
  • LogLevel.DEBUG
  • LogLevel.INFO
  • LogLevel.WARN
  • LogLevel.ERROR
  • LogLevel.ASSERT

This helps manage the SDK's logging behavior, which can be useful for debugging and monitoring purposes.


Customization

With MoneyHash's Android SDK, you can customize the appearance of the embedded form, including the submit button, input fields, and loader. To do so, you can pass an EmbedStyle object when calling the renderForm() method, allowing you to modify styles according to your brand’s needs.

Here’s how you can use the customization options with EmbedStyle for different components:

Customizing Submit Button

You can customize the submit button by providing the EmbedButtonStyle inside the EmbedStyle. This allows you to style the button's base, hover, and focus states.

Example:

// Define the base style for the submit button
val baseButtonStyle = EmbedButtonViewStyle(
    color = "#FFFFFF",
    fontFamily = "Arial, sans-serif",
    fontWeight = "bold",
    fontSize = "16px",
    fontSmoothing = null,
    lineHeight = null,
    textTransform = null,
    letterSpacing = null,
    background = "#000000",
    padding = "10px",
    borderRadius = "5px",
    boxShadow = null,
    borderStyle = null,
    borderColor = null,
    borderWidth = null
)

// Define the hover style for the submit button
val hoverButtonStyle = EmbedButtonViewStyle(
    color = null,
    fontFamily = null,
    fontWeight = null,
    fontSize = null,
    fontSmoothing = null,
    lineHeight = null,
    textTransform = null,
    letterSpacing = null,
    background = "#333333",
    padding = null,
    borderRadius = null,
    boxShadow = null,
    borderStyle = null,
    borderColor = null,
    borderWidth = null
)

// Define the focus style for the submit button
val focusButtonStyle = EmbedButtonViewStyle(
    color = null,
    fontFamily = null,
    fontWeight = null,
    fontSize = null,
    fontSmoothing = null,
    lineHeight = null,
    textTransform = null,
    letterSpacing = null,
    background = null,
    padding = null,
    borderRadius = null,
    boxShadow = null,
    borderStyle = null,
    borderColor = "#FF0000",
    borderWidth = null
)

// Combine the button styles into EmbedButtonStyle
val buttonStyle = EmbedButtonStyle(
    base = baseButtonStyle,
    hover = hoverButtonStyle,
    focus = focusButtonStyle
)

Customizing Input Fields

The EmbedInputStyle allows you to customize the base, focus, and error states of the input fields in the form. This helps you to match the input fields with the overall design of your application.

Example:

// Define the base style for the input fields
val baseInputStyle = EmbedInputViewStyle(
    height = null,
    padding = "10px",
    background = "#F5F5F5",
    borderRadius = "5px",
    boxShadow = null,
    borderStyle = null,
    borderColor = "#CCCCCC",
    borderWidth = null,
    color = null,
    fontFamily = null,
    fontWeight = null,
    fontSize = null,
    fontSmoothing = null,
    lineHeight = null
)

// Define the focus style for the input fields
val focusInputStyle = EmbedInputViewStyle(
    height = null,
    padding = null,
    background = null,
    borderRadius = null,
    boxShadow = null,
    borderStyle = null,
    borderColor = "#000000",
    borderWidth = null,
    color = null,
    fontFamily = null,
    fontWeight = null,
    fontSize = null,
    fontSmoothing = null,
    lineHeight = null
)

// Define the error style for the input fields
val errorInputStyle = EmbedInputViewStyle(
    height = null,
    padding = null,
    background = null,
    borderRadius = null,
    boxShadow = null,
    borderStyle = null,
    borderColor = "#FF0000",
    borderWidth = null,
    color = null,
    fontFamily = null,
    fontWeight = null,
    fontSize = null,
    fontSmoothing = null,
    lineHeight = null
)

// Combine the input styles into EmbedInputStyle
val inputStyle = EmbedInputStyle(
    base = baseInputStyle,
    error = errorInputStyle,
    focus = focusInputStyle
)

Customizing Loader

You can also customize the appearance of the loader that is shown during the form submission process using the EmbedLoaderStyle.

Example:

// Define the loader style
val loaderStyle = EmbedLoaderStyle(
    backgroundColor = "#000000",
    color = "#FFFFFF"
)

Applying the Custom Styles

Once you’ve customized the styles, you can apply them when calling the renderForm() method.

Example:

// Initialize the SDK using the builder
val sdkBuilder = MoneyHashSDKBuilder()
sdkBuilder.setPublicKey("your_public_api_key")
val moneyHashSDK = sdkBuilder.build()

// Combine all styles into EmbedStyle
val customEmbedStyle = EmbedStyle(
    submitButton = buttonStyle,
    loader = loaderStyle,
    input = inputStyle
)

// Assume you have an ActivityResultLauncher<IntentCreationParams> instance
val activityResultLauncher: ActivityResultLauncher<IntentCreationParams> = // initialize your launcher

// Render the form with custom styles
moneyHashSDK.renderForm(
    intentId = "your_intent_id",
    intentType = IntentType.Payment,
    embedStyle = customEmbedStyle,
    launcher = activityResultLauncher
)

In this example:

  • Custom Styles: We defined custom styles for the submit button, input fields, and loader.
  • Applying Styles: We passed the customEmbedStyle object to the renderForm method to apply the styles.
  • Rendering the Form: The renderForm method will render the embedded form with the custom styles you provided.

Note: Make sure to replace "your_public_api_key" and "your_intent_id" with your actual public API key and intent ID.


Handling Errors in the SDK

In the MoneyHash Android SDK, errors are represented using the MHThrowable class. This class provides detailed information about the error that occurred during a request or operation, including the error message, type, and additional details. This allows you to handle different error scenarios effectively and provide users with meaningful feedback.

The MHThrowable class extends Throwable and implements Parcelable, containing the following key attributes:

  • message: A user-friendly error message describing the issue.
  • errors: A list of ErrorInfo objects that provide more granular details about specific fields or issues.
  • type: An ErrorType enum value that categorizes the type of error.

The ErrorType enum categorizes the errors that can occur within the SDK. The possible types are:

  • NETWORK: Indicates a network-related issue, such as connectivity problems or API errors.
  • UNKNOWN: An unexpected or unknown error occurred.
  • CARD_VALIDATION: Validation failed for card details provided by the user.
  • CANCELLED: The operation was cancelled by the user or the system.

The ErrorInfo class provides additional context for specific errors. Each error has:

  • key: The specific field or component that caused the error.
  • message: A detailed message explaining the error related to that field or component.

Example of ErrorInfo:

val errorDetail = ErrorInfo(key = "cardNumber", message = "Invalid card number")
println("Error with field: ${errorDetail.key}, Message: ${errorDetail.message}")

Error Handling Example

When an error occurs during an operation, such as submitting payment details, you can catch the MHThrowable and handle it accordingly.

// Assume you have an instance of MoneyHashSDK
val moneyHashSDK: MoneyHashSDK = // initialize your SDK instance

fun submitPayment() {
    try {
        // Example of a MoneyHash SDK operation
        val intentDetails: IntentDetails? = moneyHashSDK.submitCardCVV(
            intentId = "your_intent_id",
            cvv = "123"
          )
        println("Payment submitted successfully.")
    } catch (error: MHThrowable) {
        // Handle different error types
        when (error.type) {
            ErrorType.NETWORK -> {
                println("Network error: ${error.message}")
            }
            ErrorType.CARD_VALIDATION -> {
                println("Card validation failed: ${error.message}")
            }
            ErrorType.CANCELLED -> {
                println("Operation cancelled: ${error.message}")
            }
            ErrorType.UNKNOWN -> {
                println("Unknown error: ${error.message}")
            }
          }

        // Additional error details
        if (error.errors.isNotEmpty()) {
            for (errorInfo in error.errors) {
                println("Error detail - Key: ${errorInfo.key}, Message: ${errorInfo.message}")
            }
        }
      } catch (throwable: Throwable) {
          // Handle other types of errors if necessary
          println("An unexpected error occurred: ${e.localizedMessage}")
      }
}

In this example:

  • Submitting Payment: We attempt to submit the CVV for a card using the submitCardCVV method.
  • Catching MHThrowable: If an MHThrowable is thrown, we catch it and handle it based on the ErrorType.
  • Error Handling:
    • Network Errors: Handle network-related issues by informing the user about connectivity problems.
    • Card Validation Errors: Provide feedback if the card details are invalid.
    • Cancellation: Handle scenarios where the operation was cancelled.
    • Unknown Errors: Catch any unexpected errors and log them appropriately.
  • Additional Error Details: We loop through the errors list to get more specific information about each error, which can be useful for debugging or displaying detailed messages to the user.
  • Catching Other Exceptions: We also catch any other exceptions that might occur to ensure robustness.

This documentation provides Android developers with the necessary guidance to handle various SDK errors effectively, following the same structure and sections as the iOS documentation provided.