If your project has minifyEnabled = true, add these rules to your proguard-rules.pro file to ensure the SDK works correctly, especially with AGP 8.x+ R8 full mode.
Official Yuno ProGuard / R8 rules
# Preserve generic type signatures and annotations-keepattributes Signature-keepattributes *Annotation*# Yuno SDK-keep class com.yuno.** { *; }-dontwarn com.yuno.**# Gson — R8 full mode compatibility-keep class com.google.gson.** { *; }-keep,allowobfuscation,allowshrinking,allowoptimization class * extends com.google.gson.reflect.TypeToken-dontwarn com.google.gson.**# Retrofit — R8 full mode compatibility-keep,allowobfuscation,allowshrinking interface retrofit2.Call-keep,allowobfuscation,allowshrinking class retrofit2.Response-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation-dontwarn retrofit2.**# OkHttp + Okio — Suppress warnings-dontwarn okhttp3.**-dontwarn okio.**
AGP 8.x+ enables R8 full mode by default, which aggressively strips generic type signatures. Without -keepattributes Signature, Gson’s TypeToken<T> can fail at runtime with java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType.
The first step is including the library in your project. Add the Yuno Android SDK to your project through Gradle. Add the repository source and dependency:
Implement Full (Android): customizable UI, payment method management, fraud prevention, and checkout flows. More feature-rich than Headless, which focuses on core payment processing. See Requirements above.
Retrieve your public API keys from the Yuno Dashboard.If you haven’t implemented a custom application, create one. In the onCreate() method of your application class, call the initialize function (Yuno.initialize):
class CustomApplication : Application() { override fun onCreate() { super.onCreate() Yuno.initialize( this, "<your-public-api-key>", config = YunoConfig(), ) }}
See the credentials page for more information. Use the data class YunoConfig to customize the SDK’s behavior. Include this configuration when calling Yuno.initialize(). The available options are:
data class YunoConfig( val saveCardEnabled: Boolean = false, val keepLoader: Boolean = false, val language: YunoLanguage? = null, val styles: YunoStyles? = null)
cardFlow removed from YunoConfigStarting from version 2.11.0, cardFlow is no longer part of YunoConfig. Card flow configuration is now handled exclusively through the CheckoutBuilder. If you are migrating from an earlier version, remove cardFlow from your YunoConfig and configure it in the CheckoutBuilder instead.
Enables the Save card checkbox on card flows. Check the Save card section for more information.
keepLoader
A boolean that specifies whether the loader should be kept visible after the payment is initiated.
language
Defines the language to be used in the payment forms. You can set it to one of the available language options:
ar (Arabic)
es (Spanish)
en (English)
pt (Portuguese)
fil (Filipino)
id (Indonesian)
ms (Malay)
th (Thai)
zh-TW (Chinese (Traditional, Taiwan))
zh-CN (Chinese (Simplified, China))
vi (Vietnamese)
fr (French)
pl (Polish)
it (Italian)
de (German)
ru (Russian)
tr (Turkish)
nl (Dutch)
sv (Swedish)
ko (Korean)
ja (Japanese)
styles
Enables SDK-wide UI customization. Use it to define global visual styles like font family and button appearance (color, padding, radius, typography) through a YunoStyles object. For more information, check the styles section.
Each payment requires a new checkout_session. Use the Create checkout session endpoint to create one; use that session to initiate the payment.If your payment flow sends users to an external browser (e.g., for 3DS authentication or bank redirects), set the callback_url when creating your checkout session. See Handle external browser return (callback_url) for details.
Call the startCheckout method inside the onCreate() function of the activity that initializes the SDK to start a new payment process with Full (Android):
See Parameters. The following are the possible states returned by the callbackPaymentState:
const val PAYMENT_STATE_SUCCEEDED = "SUCCEEDED"const val PAYMENT_STATE_FAIL = "FAIL"const val PAYMENT_STATE_PROCESSING = "PROCESSING"const val PAYMENT_STATE_REJECT = "REJECT"const val PAYMENT_STATE_INTERNAL_ERROR = "INTERNAL_ERROR"const val PAYMENT_STATE_STATE_CANCELED_BY_USER = "CANCELED"
Possible states:
State
Description
Additional action required
SUCCEEDED
The transaction or payment process was successfully completed without any errors.
No.
FAIL
The transaction failed due to errors such as data validation issues, server connection failures, or technical/network problems.
Yes. Investigate the cause of failure (validation, network, server) and take corrective measures.
PROCESSING
The transaction is currently in progress, awaiting approval or verification.
No.
REJECT
The transaction was rejected due to reasons like insufficient funds or suspected fraudulent activity.
Yes. Inform the user of the rejection, provide the reason if possible, and suggest actions.
INTERNAL_ERROR
An unexpected internal error occurred within the system handling the payment process.
Yes. Requires technical intervention to review the system, fix internal issues, and retry or inform the user.
CANCELED
The user voluntarily canceled the transaction or abandoned the payment process.
This section explains how the SDK handles payment status when users cancel or leave payment flows, and how the SDK status relates to the backend payment status in these scenarios.
Sync payment methods (Google Pay)
For synchronous payment methods like Google Pay, when a user cancels or closes the wallet UI before a payment service provider (PSP) response is received:
SDK Status: Returns CANCELED (CANCELLED_BY_USER)
Backend payment status: Remains PENDING until PSP timeout or merchant cancellation
Important: The SDK will not return REJECT or PROCESSING in this scenario
This ensures that the backend payment remains in a pending state and can be properly handled by the merchant’s system.
Async payment methods (PIX and QR-based methods)
For asynchronous payment methods like PIX, when a user closes the QR code window (clicks X) before completing the payment:
SDK Status: Returns PROCESSING, optionally with a sub-status such as CLOSED_BY_USER
Backend payment status: Remains PENDING and the QR code remains valid until expiry
Checkout session reuse: Re-opening the same checkout session can display the same valid QR code
No Automatic Cancellation: The PIX payment is not automatically cancelled when the user closes the QR window
This behavior allows users to return to the payment flow and complete the transaction using the same QR code before it expires.
Expired async payments
If a PIX QR code expires naturally:
Backend Status: Updated to EXPIRED
SDK Status: SDK callbacks and polling endpoints return EXPIRED consistently
This ensures merchants receive accurate status information when a payment method has expired.
Use the PaymentMethodListViewComponent to display the available payment methods when implementing Full (Android) with Jetpack Compose. This component provides callbacks to notify your app when to enable or disable the pay button, and when an enrolled payment method is successfully removed.
ImportantAlways wrap the component in a Column with .verticalScroll(rememberScrollState()). Without this, the list of payment methods may not render or scroll properly when there are multiple methods available.
A boolean that specifies whether the payment status should be displayed within the Yuno interface.
callbackOTT
A required function that returns the updated one-time token (OTT) needed to complete the payment process. This token is required to complete the payment.
callBackTokenWithInformation
A function that supplies detailed information about the one-time token, wrapped in a OneTimeTokenModel object, allowing for comprehensive handling of token details.
The callBackTokenWithInformation callback provides detailed information about the one-time token through the OneTimeTokenModel object:
@Parcelizedata class OneTimeTokenModel( val token: String? = null, val vaultedToken: String? = null, val vaultOnSuccess: Boolean? = null, val type: String? = null, val cardData: CardInformationModel? = null, val customer: CustomerPayerInformationModel? = null,) : Parcelable
Card Information Model
@Parcelizedata class CardInformationModel( val holderName: String? = null, val iin: String? = null, val lfd: String? = null, val numberLength: Int? = null, val securityCodeLength: Int? = null, val brand: String? = null, val type: String? = null, val category: String? = null, val issuerName: String? = null, val issuerCode: String? = null, val countryCode: String? = null,) : Parcelable
Customer Payer Information Model
@Parcelizedata class CustomerPayerInformationModel( val name: String? = null, val lastName: String? = null, val email: String? = null, val document: Document? = null, val phone: Phone? = null, val address: Address? = null, val deviceFingerPrint: String? = null, val thirdPartySessionId: String? = null,) : Parcelable
Supporting Models
@Parcelizedata class Document( val documentNumber: String? = null, val documentType: String? = null,) : Parcelable@Parcelizedata class Phone( val number: String, val countryCode: String,) : Parcelable@Parcelizedata class Address( val addressLine1: String? = null, val addressLine2: String? = null, val country: String? = null, val city: String? = null, val state: String? = null, val zipCode: String? = null, val neighborhood: String? = null,) : Parcelable
After the customer fills out the requested data in Yuno’s payment forms, you will obtain the one-time token, a required parameter to create a payment using the Yuno API.The one-time token will be shared by Yuno using the callbackOTT function you provided in Step 6 when initiating the payment. The one-time token will be available in the onActivityResult.A loader can be shown while the one-time token is generated. Use Yuno’s default or implement your own with the required configuration.
After receiving the one-time token from Step 7, create the payment using the Create payment endpoint. Use the checkout_session from Step 3 and the one-time token to create the payment.The response from the Create payment endpoint will include the parameter sdk_action_required, which defines if additional actions are required to finish the payment based on the payment type.
Continue Payment Method IntegrationYuno requires you integrate the continuePayment method of the SDK after the payment is created because certain asynchronous payment methods require additional customer actions to complete. The API will inform you of this scenario via the sdk_action_required field of the response, which will be returned as true. The yuno.continuePayment() function will display additional screens to customers, where they can carry out the necessary actions to complete the payment without you needing to handle every scenario.
Yuno requires integrating the SDK’s continuePayment method after the payment is created, as certain asynchronous payment methods require additional customer actions to complete. The response from the Create payment endpoint, from Step 8, will include an sdk_action_required field. If it returns TRUE, you need to call the continuePayment() function to show additional screens that allow the customer to complete the payment. Otherwise, this step is not necessary. Call the continuePayment method:
Render mode offers enhanced UI flexibility, allowing you to integrate payment flows with complete control over the user interface while maintaining full SDK functionality.
The startPaymentRender function allows you to integrate the payment process in a more detailed and customizable manner. This function provides full control over when and how payment forms are displayed, facilitating a smoother integration with your existing application UI.Key benefits:
Integrate payment forms in a customized manner within your own UI.
Precisely control when payment data forms are displayed.
Gain detailed control over the payment confirmation process.
Provide a more fluid and consistent user experience.
Step 1: Initial setupEnsure the SDK is properly initialized and you have a valid checkoutSession.
Yuno.initialize(this, "your_api_key")
Step 2: Create payment flow instance
val paymentRender = Yuno.startPaymentRender( paymentMethodSelected = PaymentChosen( type = "CARD", vaultedToken = "optional_vaulted_token" ), callbackPaymentState = { state -> // Handle final state (SUCCEEDED, FAIL, etc.) })
Step 3: Render and display the form
paymentRender?.render { formView -> if (formView != null) { // Add formView to your layout myContainer.addView(formView) } else { // No form needed, you can proceed to startPayment() directly // or show a confirmation button }}
Step 4: Start payment and handle OTTWhen the user clicks your “Pay” button, call paymentRender?.startPayment(). You will receive the token through the callbackOTT provided during setup (or through the activity result, depending on your implementation).
// Inside your activity or fragmentoverride fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) Yuno.onActivityResult(requestCode, resultCode, data)}// Ensure you handle the OTT to create the payment on your backendfun onTokenUpdated(ott: String?) { if (ott != null) { createPaymentOnBackend(ott) { success -> if (success) { paymentRender?.continuePayment { additionalView -> if (additionalView != null) { // Display 3DS or other additional views myContainer.removeAllViews() myContainer.addView(additionalView) } } } } }}