# ComponentCallback ```kotlin /** * Represents a callback interface for handling events for a payment method * * @property onReady Triggered when the payment method is ready. * @property onChange Triggered when the payment method is changed and any new updates. * @property onSubmit Triggered when the payment method is submitted. * @property onSuccess Triggered when the payment is completed successfully. * @property onError Triggered when there is an error. * @property onTokenized Triggered when a card is tokenized, providing the [TokenizationResult]. * return [CallbackResult] to indicate whether to proceed with or block the payment. * @property onCardBinChanged Triggered when the card BIN (first 8 digits) changes, providing the [CardMetadata]. * return [CallbackResult] to indicate whether to proceed with card scheme or block the payment. * @property handleSubmit Triggered when payment submission is required. You can implement this to handle payment submission with your own backend. * The function receives [SessionData] and should return [ApiCallResult], indicating the success or failure of the submission. * @property handleTap Triggered when the pay button is pressed after SDK's validation for respective payment method. * If implemented and it returns true, the payment process continues. If it returns false, the payment process stops and no other callbacks are triggered. */ public data class ComponentCallback( val onReady: ((PaymentMethodComponent) -> Unit)? = null, val onChange: ((PaymentMethodComponent) -> Unit)? = null, val onSubmit: ((PaymentMethodComponent) -> Unit)? = null, val onSuccess: ((PaymentMethodComponent, String) -> Unit)? = null, val onError: ((PaymentMethodComponent, CheckoutError) -> Unit)? = null, val onTokenized: (suspend (TokenizationResult) -> CallbackResult)? = null, val onCardBinChanged: ((CardMetadata) -> CallbackResult)? = null, val handleSubmit: (suspend (SessionData) -> ApiCallResult)? = null, val handleTap: (suspend (PaymentMethodComponent) -> Boolean)? = null, ) ``` ## Methods ### onCardBinChanged(CardMetadata): -> CallbackResult Triggered when the customer inputs or changes the first eight digits of a card. Use this event to perform checks on the card based on its metadata, or to observe changes to the bank identification number (BIN). The `CardMetadata` object contains the response to the [Get card metadata](https://api-reference.checkout.com/tag/Card-metadata/#operation/requestCardMetadata!c=200&path=bin&t=response) request. If you do not provide a callback, Flow for Mobile automatically accepts the card. You can also explicitly specify the action to take: - To accept the card, return `CallbackResult.Accepted`. - To reject the card, return `CallbackResult.Rejected("Error message")`. You can also provide an optional `errorMessage` to display a custom error message on the card component. ```kotlin val callback = ComponentCallback( onCardBinChanged = { cardMetadata -> // Check if card is from a specific issuer if (cardMetadata.issuer == "RESTRICTED_BANK") { CallbackResult.Rejected("Cards from this bank are not accepted") } // Check if card is from a specific country else if (cardMetadata.issuerCountry == "XX") { CallbackResult.Rejected("Cards from this country are not supported") } // Check card type else if (cardMetadata.cardType == "credit") { CallbackResult.Rejected("Credit cards are not accepted") } // Accept all other cards else { CallbackResult.Accepted } } ) val config = CheckoutComponentConfiguration( componentCallback = callback ) ``` ### onReady(PaymentMethodComponent) Triggered when a `PaymentMethodComponent` is initialized and ready for the customer to interact. `PaymentMethodComponent` is the payment method component that triggered the event. ```kotlin fun onReady(component: PaymentMethodComponent) { // Hide loading overlay hideLoadingOverlay(); } val callback = ComponentCallback(onReady=onReady) val config = CheckoutComponentConfiguration( componentCallback = callback ) ``` ### onSubmit(PaymentMethodComponent) Triggered when you or the customer triggers a `PaymentMethodComponent` submission. `PaymentMethodComponent` is the name of the payment method component that Triggered the event. ```kotlin fun onSubmit(component: PaymentMethodComponent) { // Show loading overlay to prevent further user interaction showLoadingOverlay(); } val callback = ComponentCallback(onSubmit=onSubmit) val config = CheckoutComponentConfiguration( componentCallback = callback ) ``` ### onSuccess(PaymentMethodComponent, PaymentId) Triggered when the payment is completed synchronously or asynchronously – for example, after a successful 3DS authentication. The callback contains information on the successful payment: * `PaymentMethodComponent` is the name of the payment method component that triggered the event. * String is the unique ID of this payment. ```kotlin fun onSuccess(Component: PaymentMethodComponent, paymentId: String) { // Complete order in server side completeOrder(paymentId); } val callback = ComponentCallback(onSuccess=onSuccess) val config = CheckoutComponentConfiguration( componentCallback = callback ) ``` ### onError(PaymentMethodComponent, CheckoutError) Triggered when an error occurs. See the [CheckoutError reference](https://www.checkout.com/docs/payments/accept-payments/accept-a-payment-on-your-mobile-app/flow-for-mobile-library-reference/android/checkouterror.md) for more information. `PaymentMethodComponent` is the name of the payment method component that triggered the event. ```kotlin fun onError(component: PaymentMethodComponent, error: CheckoutError) { // Display the payment request failure message if (error.code == CheckoutErrorCode.PAYMENT_REQUEST_DECLINED) { showErrorMessage('Payment could not be processed. Please try again.'); } } val callback = ComponentCallback(onError=onError) val config = CheckoutComponentConfiguration( componentCallback = callback ) ``` ### onTokenized:(suspend (TokenizationResult) -> CallbackResult) Triggered when a supported `PaymentMethodComponent` item is tokenized and provides the `TokenizationResult` object. This callback is triggered after a successful card tokenization and provides the `TokenizationResult` for you to validate. - type – The name of the payment method that triggered the tokenization. Always set this to `card`. - data – [The card tokenization response](https://api-reference.checkout.com/tag/Tokens/#operation/requestAToken!c=201&path=0/type&t=response). - cardMetadata – An optional [Card metadata lookup response](https://api-reference.checkout.com/tag/Card-metadata/#operation/requestCardMetadata!c=200&path=bin&t=response) object included when a you receive a card metadata API response during customer input. - preferredScheme – The customer's preferred payment scheme when multiple schemes are supported for the card. For example, Visa and Cartes Bancaires. This can be null if no preference is selected, or if the scheme choice was not offered. - storeForFutureUse – The customer's save-card consent choice. `true` when the customer checked the consent checkbox, `false` when they left it unchecked, and `null` whenever consent was not collected because the checkbox was not shown. > **Important** > > When `storeForFutureUse` is not `null`, forward it as `source.store_for_future_use` on your payment request. Sending nothing means the card is not stored, regardless of what the customer chose. Whether the consent checkbox displays, and what `storeForFutureUse` reports, depends on the session value of `store_payment_details` on the card payment method: | Session value of store_payment_details | Consent checkbox shown? | storeForFutureUse | | --- | --- | --- | | `collect_consent`, Remember Me not available on the session | Yes | `true` or `false`, matching the checkbox | | `collect_consent`, Remember Me available | No. Remember Me collects consent through its own flow. | `null` | | `enabled` | No. The backend forces storage on. | `null` | | `disabled`, absent, or unrecognized | No. The backend forces storage off. | `null` | > **Note** > > If your payment session request omits `customer.email`, the backend silently downgrades `store_payment_details: collect_consent` to `disabled`. If you are not seeing the consent checkbox, check your session request before troubleshooting your integration. If you do not provide a callback, Flow for Mobile automatically accepts the card. You can also explicitly specify the action to take: - To accept the card, return `CallbackResult.Accepted`. - To reject the card, return `CallbackResult.Rejected("Error message")`. You can also provide an optional `errorMessage` to display a custom error message on the card component. > **Note** > > If you attempt to tokenize an unsupported component, the `onError()` callback triggers instead. ```kotlin suspend fun onTokenized(tokenizationResult: TokenizationResult): CallbackResult { if (tokenizationResult.data.cardType == "Credit") { CallbackResult.Rejected("Credit cards are not accepted") } else { CallbackResult.Accepted } } val callback = ComponentCallback(onTokenized = ::onTokenized) ``` ### handleSubmit: (suspend (SessionData) -> ApiCallResult) Use this callback to submit a customized payment session to the [Submit a payment session](https://api-reference.checkout.com/tag/Flow/#operation/SubmitPaymentSession) endpoint. > **Information** > > If you do not provide this callback, Flow for Mobile automatically sends the payment request for processing. `sessionData` is a unique token that represents the additional customer data captured by Flow for Mobile. You must: - Provide the token in the `session_data` field when you call the [Submit a payment session](https://api-reference.checkout.com/tag/Flow/#operation/SubmitPaymentSession) endpoint. - Provide Flow for Mobile with the unmodified response body returned by the request. ```kotlin suspend fun handleSubmit(sessionData: SessionData): ApiCallResult { return try { val response = apiClient.submitPayment(sessionData) if (response.isSuccessful) { ApiCallResult.Success(response.paymentSessionSubmissionResult) } else { ApiCallResult.Failure } } catch (e: Exception) { ApiCallResult.Failure } } val callback = ComponentCallback(handleSubmit = ::handleSubmit) ``` ### handleTap(suspend (PaymentComponent)) -> Boolean Triggered when the pay button is pressed after the SDK validates the respective payment method. This callback enables you to implement custom validation logic before you continue with the payment. - `true` - The payment process continues. - `false` – The payment process stops and no other callbacks are triggered. ```kotlin suspend fun handleTap(component: PaymentMethodComponent): Boolean { // Implement custom validation logic. // For example, check terms & conditions acceptance. if (component.isValid() && !termsAccepted) { showTermsError() return false } // Or validate business rules: if (component.isValid() && !isBusinessRuleValid()) { showBusinessRuleError() return false } // Return true to continue payment return true } val callback = ComponentCallback(handleTap = ::handleTap) ``` ### onChange(PaymentMethodComponent) -> Unit Triggered when the payment method is changed, and after any new updates. This callback enables you to handle changes in the payment component state. For example, field updates and validation changes. ```kotlin fun onChange(component: PaymentMethodComponent) { // Handle component state changes. // For example, update UI based on validation state: CoroutineScope(Dispatchers.Main).launch { try { val isValid = component.isValid() isComponentValid(isValid) } catch (e: Exception) { isComponentValid(false) } } // Or track user component selection when (component.name) { is "card"-> { // Handle card changes: } is "googlepay"-> { // Handle Google Pay changes: } } } ```