# Handling Client-Side Actions ## Overview When processing payments using the Ryft Android Drop-In SDK, there may be scenarios where additional **client-side actions** are required to complete the payment. These actions can include 3D Secure authentication, handling redirects, or other verification steps mandated by the card issuer or payment method. Our Drop-In SDK is designed to handle these client-side actions seamlessly, providing a smooth user experience. However, you may want to handle any required client-side actions explicitly in your application code. A common use case would be a [MIT](/documentation/overview/core_concepts/stored_payment_methods#merchant-initiated-transactions-mit) payment where the card issuer requires 3D Secure authentication to complete the transaction. In such cases, you will need to bring the customer back to your application after they complete the authentication process. ## Implementing Client-Side Actions To handle client-side actions in your application, you can use our **RyftRequiredActionComponent** object. This component provides methods to manage and execute the required actions. Similarly to the Drop-In, you can initialise the component within the fragment or activity that handles your checkout process within the `onCreate` method. Here's an example of how to initialise the Ryft Required Action Component in your activity: ```kotlin Initialise Ryft Android Required Action Component - Kotlin (Activity) class CheckoutFragment : Fragment() { // ... // Declare RyftRequiredActionComponent private lateinit var ryftRequiredActionComponent: RyftRequiredActionComponent // ... // Instantiate DefaultRyftRequiredActionComponent in onCreate() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... ryftRequiredActionComponent = DefaultRyftRequiredActionComponent( // The calling fragment (activity is also supported) fragment = this, // The class you want to listen for the result (see "Implementing the RyftRequiredActionResultListener" below) listener = this ) // ... } // ... } ``` ## Handling Required Action Results In order to handle the required action, you can simply call the `handle()` method on the `RyftRequiredActionComponent` instance you created during the initialisation step. This will include passing the necessary parameters required for the action process, such as: - the **Client Secret** obtained from your backend when creating a Payment Session; - the **Public Key**; Here's an example of how to handle the required action in your activity or fragment: Standalone Component - Single Payment ```kotlin Handling Required Actions - Standalone Component (Single Payment) class CheckoutFragment : Fragment() { // ... // Example function to handle the required action // Fetch 'requiredAction' from your backend private fun handleRequiredAction(requiredAction: RequiredAction) { ryftRequiredActionComponent.handle( RyftRequiredActionComponent.Configuration.standardAccountPayment( clientSecret = "", // The client secret returned when creating a Payment Session publicApiKey = RyftPublicApiKey("") // Your Ryft Public API Key ), requiredAction ) } // ... } ``` Standalone Component - Platform Fee Payment ```kotlin Handling Required Actions - Standalone Component (Platform Fee Payment) class CheckoutFragment : Fragment() { // ... // Example function to handle the required action // Fetch 'requiredAction' from your backend private fun handleRequiredAction(requiredAction: RequiredAction) { ryftRequiredActionComponent.handle( RyftRequiredActionComponent.Configuration.subAccountPayment( clientSecret = "", // The client secret returned when creating a Payment Session publicApiKey = RyftPublicApiKey(""), // Your Ryft Public API Key subAccountId = "" // The Id of the Sub-Account you are taking payments for ), requiredAction ) } // ... } ``` ## Implementing the RyftRequiredActionResultListener Once the `handle()` method is called, the Ryft Required Action Component will process the required action. To receive the result of this process, you need to implement the `RyftRequiredActionResultListener` interface in your activity or fragment: ```kotlin Implementing RyftRequiredActionResultListener - Kotlin (Fragment) interface RyftRequiredActionResultListener { fun onRequiredActionResult(result: RyftRequiredActionResult) } ``` This method is invoked when the required action process is completed, allowing you to handle the result accordingly. The `RyftRequiredActionResult` object has two possible outcomes that you can handle: | State | Description | Action Required | | --- | --- | --- | | Success | The required action was handled successfully, and the payment can proceed (the 3DS result may have been successful or failed). | Inspect the status of the Payment Session to determine the next steps. | | Error | An error occurred while handling the required action. | Display an error message to the user and allow them to retry (which should involve handling the required action again). | Here's an example of how to implement the `RyftRequiredActionResultListener` in your activity or fragment: ```kotlin Implementing RyftRequiredActionResultListener - Kotlin (Fragment) class CheckoutFragment : Fragment(), RyftDropInResultListener { // ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... ryftRequiredActionComponent = DefaultRyftRequiredActionComponent( fragment = this, listener = this // This fragment will listen for the dropin result ) // ... } // ... override fun onRequiredActionResult(result: RyftRequiredActionResult) = when (result) { // The required action was handled successfully - inspect the status to determine the next step // `result.paymentSession` returns the updated payment session is RyftRequiredActionResult.Success -> { val status = result.paymentSession.status // ... } // There was an error whilst handling the required action - show an alert to the customer // `result.error.displayError` provides a human friendly message you can display is RyftRequiredActionResult.Error -> { AlertDialog.Builder(requireContext()) .setTitle("Error taking payment") .setMessage(result.error.displayError) .setPositiveButton("Try again") { _, _ -> // Fetch the latest 'requiredAction' from your backend handleRequiredAction(requiredAction) } .setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() } .create() .show() } } // ... } ``` ## Next Steps Once the payment has been processed successfully, you can proceed to show a confirmation screen to the user or handle any post-payment logic as needed. It is also recommended to set up **webhooks** on your backend to listen for payment events and update your records accordingly. For more information on setting up webhooks, please refer to the [Webhooks Documentation](/documentation/get_started/webhooks) section.