Skip to main content
Orientation: Choosing Your Integration Flow, before you begin, please review the Official Integration Flow.
  • Standard Flow (Full Checkout): Recommended for most merchants. Yuno handles the UI, security, and automatic updates for payment methods.
  • Custom Flow (This SDK): Use this only if you require full control over the UX. Note: You will be responsible for manually handling payment statuses, 3DS transitions, and fraud routing data collection.
This page provides a guide to the Yuno Headless Android SDK for payments. This SDK is ideal for merchants who:
  • Need full control over the payment UI and user experience
  • Want to build custom payment flows
  • Require advanced integration capabilities
The Headless SDK includes core features like:
  • Direct API access for payment processing
  • Token generation for payment methods
  • 3DS authentication handling
  • Fraud prevention data collection
For merchants preferring a pre-built UI solution, consider using our Full Checkout SDK or Lite SDK instead.

Requirements

Before starting the Yuno Android SDK integration, ensure your project meets the technical requirements. Also, ensure the following prerequisites are in place:
  • Minimum SDK Version: minSdkVersion 21 or above
  • Java: Java 8 enabled
  • AndroidX: Use AndroidX instead of older support libraries
  • Android Gradle Plugin: 4.0.0 or above
  • ProGuard: 6.2.2 or above
  • Kotlin Gradle Plugin: 1.4.0 or above
  • ELF Page Size Support: Compliant with Google’s 16 KB ELF page alignment requirements (Android 15 / ARMv9 ready)

ProGuard / R8 Configuration

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.
# 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.**

Why are these rules necessary?

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.
Latest SDK VersionCheck the Release notes or visit the Yuno Android SDK repository to verify the current SDK version available.

Step 1: Create a customer

Create a customer using the Create customer endpoint before initiating payments. This step is required to:
  • Identify the person making the payment
  • Enable saved payment method functionality (if enabled)
  • Track payment history
The customer ID returned from this endpoint will be used when creating the checkout_session.

Step 2: Create a checkout session

Create a new checkout_session using the Create checkout session endpoint to initialize the payment flow. Make sure to:
  • Include the customer ID obtained from the previous step
  • Store the returned checkout_session ID for use in later steps
The checkout_session is unique for each payment attempt and cannot be reused.

Step 3: Include the library in your project

Include the Yuno SDK in your project through Gradle. Add the repository source:
maven { url "https://yunopayments.jfrog.io/artifactory/snapshots-libs-release" }
Add the Yuno SDK dependency to your application in the build.gradle file:
dependencies {
    implementation 'com.yuno.payments:android-sdk:{last_version}'
}
Yuno SDK includes, by default, the INTERNET permission, which is required to make network requests. <uses-permission android:name="android.permission.INTERNET" />

Step 4: Initialize headless SDK with the public key

Import Yuno and provide a valid PUBLIC_API_KEY to initialize the Headless SDK. If you don’t have your API credentials, see the Developers (Credentials) page to check how to retrieve them from the dashboard. Create a custom application if you haven’t already. In the onCreate() method of your application class, initialize the SDK by calling the Yuno.initialize() function:
class CustomApplication : Application() {
  override fun onCreate() {
    super.onCreate()
    Yuno.initialize(
      this,
      PUBLIC_API_KEY,
      config = YunoConfig(
        keepLoader = true,
      ),
    )
  }
}
For a detailed explanation of the keepLoader parameter and mandatory error handling, see the Android Reference Guide.

Step 5: Start the checkout process

Call the apiClientPayment function after your customer selects a payment method to start the checkout process. This function requires configuration parameters and initiates the collection of information needed for 3DS authentication and fraud prevention tools configured in your routing. The following table describes the required parameters:
ParameterDescription
country_codeThis parameter determines the country for which the payment process is being configured. The complete list of supported countries and their country_code is available on the Country coverage page.
checkout_sessionRefers to the current payment’s checkout session created using the Create Checkout Session endpoint. Example: '438413b7-4921-41e4-b8f3-28a5a0141638'
The following code block shows an example of the parameter configuration:
 val apiClientPayment = Yuno.apiClientPayment(
   countryCode = "US",
   checkoutSession = "74bf4b96-6b35-42a6-8c73-2fe094c34ca9",
   context = this
)

Step 6: Generate token

After collecting the user information, create a one-time token (OTT) using the apiClientPayment.generateToken function. Since this is an asynchronous function, use a try/catch block to handle any errors that may occur. The following examples show two different scenarios for creating a one-time token:
  1. Example 1: Create a one-time token using a card as the payment method and including all required card information.
  2. Example 2: Create a one-time token using the vaulted_token information.

Benefits of using a vaulted token

When you use a vaulted token with the SDK, all the fraud information from the providers you configured in your card routing is collected and attached to the one-time token. You can also add installment information and a security code if the provider requires it.
Example 1
apiClientPayment.generateToken(
   collectedData = TokenCollectedData(
       checkoutSession = "checkout_session",
       paymentMethod = PaymentMethod (
           type = "CARD",
           vaultedToken = null,
           card = CardData(
               save = true,
               detail = Detail(
                   expirationMonth = 11,
                   expirationYear = 55,
                   number = "4111111111111111",
                   securityCode = "123",
                   holderName = "Firstname Lastname",
                   type = CardType.DEBIT
               ),
               installment = Installment(
                   id = "id",
                   value = 12
               )
           ),
           customer = Customer(
               id = "id",
               merchantCustomerId = "merchant_customer_id",
               firstName = "firstName",
               lastName = "lastName",
               gender = Gender.NB,
               dateOfBirth = "DD/MM/YYYY",
               email = "email@email.com",
               country = "US",
               document = Document(
                   documentType = "PAS",
                   documentNumber = "PAS12312"
               ),
               phone = Phone(
                   number = "321123321123",
                   countryCode = "1"
               )
           )
       )
   ),
   context = this
)

Example 2
apiClientPayment.generateToken(
   collectedData = TokenCollectedData(
       checkoutSession = "checkout_session",
       paymentMethod = PaymentMethod(
           type = "CARD",
           vaultedToken = "a1c7c5d1-b260-4dc6-909a-8368704233cf",
           card = CardData(
               save = true,
               detail = Detail(
                   expirationMonth = 11,
                   expirationYear = 55,
                   number = "4111111111111111",
                   securityCode = "123",
                   holderName = "Firstname Lastname",
                   type = CardType.DEBIT
               ),
               installment = Installment(
                   id = "id",
                   value = 12
               )
           ),
           customer = Customer(
               id = "id",
               merchantCustomerId = "merchant_customer_id",
               firstName = "firstName",
               lastName = "lastName",
               lastName = "lastName",
               gender = Gender.NB,
               dateOfBirth = "DD/MM/YYYY",
               email = "email@email.com",
               country = "CO",
               document = Document(
                   documentType = "PAS",
                   documentNumber = "PAS12312"
               ),
               phone = Phone(
                   number = "321123321123",
                   countryCode = "57"
               )
           )
       )
   ),
   context = this
)

The apiClientPayment.generateToken function returns an Observable type, which is a subclass of LiveData. You can observe the response as a common LiveData with the following type SingleLiveEvent<Map<String, Any?>>, which is a LiveData that only emits once. The response type is a Map containing the whole response. The following code block shows examples of responses after calling the apiClientPayment.generateToken function.
Example 1
["token": "9ee44ac7-9134-4598-ae28-a26fec03099d",
     "type": "CARD",
     "customer": ["billing_address": null,
                  "first_name": null,
                  "gender": "",
                  "phone": nil,
                  "browser_info": ["color_depth": null,
                                   "language": "en",
                                   "accept_header": "*/*",
                                   "browser_time_difference": null,
                                   "accept_content": null,
                                   "accept_browser": null,
                                   "java_enabled": null,
                                   "user_agent": "YunoSDK_Example/1 CFNetwork/1406.0.4 Darwin/22.6.0",
                                   "screen_height": "844.0",
                                   "screen_width": "390.0",
                                   "javascript_enabled": null],
                  "document": null,
                  "last_name": null,
                  "device_fingerprint":null,
                  "email": null],
     "country": "US",
     "vaulted_token": null,
     "installment": ["rate": "",
                     "id": "cca80084-961b-4212-9c34-54f03f4f10ae",
                     "value": 24,
                     "amount": null],
     "card_data": null]

Example 2
["token": "9ee44ac7-9134-4598-ae28-a26fec03099d",
     "type": "CARD",
     "customer": ["billing_address": null,
                  "first_name": null,
                  "gender": "",
                  "phone": nil,
                  "browser_info": ["color_depth": null,
                                   "language": "en",
                                   "accept_header": "*/*",
                                   "browser_time_difference": null,
                                   "accept_content": null,
                                   "accept_browser": null,
                                   "java_enabled": null,
                                   "user_agent": "YunoSDK_Example/1 CFNetwork/1406.0.4 Darwin/22.6.0",
                                   "screen_height": "844.0",
                                   "screen_width": "390.0",
                                   "javascript_enabled": null],
                  "document": null,
                  "last_name": null,
                  "device_fingerprint":null,
                  "email": null],
     "country": "BR",
     "vaulted_token":"a1c7c5d1-b260-4dc6-909a-8368704233cf",
     "installment": ["rate": "",
                     "id": "cca80084-961b-4212-9c34-54f03f4f10ae",
                     "value": 24,
                     "amount": null],
     "card_data": null]

The endpoint response provides the sdk_action_required parameter that defines if additional actions are necessary. The following code block shows an example of observing the response:
apiClientPayment.generateToken(data, context).observe(context) { response ->
   val token = response["token"] as String?
   val error = response["error"] as String?
}

Step 7: Create the payment

After generating the one-time token, create the payment by calling the Create Payment endpoint. Include the one-time token obtained in Step 6 in the payment_method.token parameter of your request. The following code block shows an example of a payment creation request:
{
  "merchant_order_id": "0000022",
  "country": "US",
  "account_id": "<Your account_id>",
  "description": "Test",
  "amount": {
    "currency": "USD",
    "value": 500
  },
  "customer_payer": {
    "id": "cfae0941-7234-427a-a739-ef4fce966c79"
  },
  "checkout": {
    "session": "<checkout session>"
  },
  "workflow": "SDK_CHECKOUT",
  "payment_method": {
    "type":"CARD",
    "token": "2cd31999-e44e-4de3-bbe4-179981ff4295"
  }
}
The endpoint response includes the sdk_action_required parameter that indicates whether additional actions are needed to complete the payment:
  • For synchronous payment methods, the payment completes instantly. In this case, sdk_action_required will be false in the API response and the payment process ends
  • For payment flows requiring additional SDK interaction, sdk_action_required will be true. When this happens, proceed to Step 8 for next steps

Step 8: Continue the payment (if required)

When a payment created from your backend requires an additional step — for example, a 3DS challenge — the Create Payment endpoint response includes:
  • Status PENDING and sub-status WAITING_ADDITIONAL_STEP
  • sdk_action_required = true
Call continueCardPayment to let the SDK resume the payment. The SDK executes the pending action internally, including rendering the 3DS challenge, waits for the result, and delivers the final payment state to your callback.

Function signature

fun ApiClientPayment.continueCardPayment(
    activity: ComponentActivity,
    showPaymentStatus: Boolean = false,
    callbackPaymentState: ((String?, String?) -> Unit)? = null,
)

Parameters

ParameterTypeDescription
activityComponentActivityThe activity the SDK uses to present the pending action.
showPaymentStatusBooleanIf true, the SDK shows its payment status screen when the flow finishes. Set it to false to use only the callback.
callbackPaymentState((String?, String?) -> Unit)?Invoked on the main thread with the final payment state and sub-status once the flow completes.

Usage

Yuno.apiClientPayment(
    checkoutSession = checkoutSession,
    countryCode = countryCode,
    context = this,
).continueCardPayment(
    activity = this,
    showPaymentStatus = false,
) { paymentState, paymentSubState ->
    when (paymentState) {
        "SUCCEEDED" -> { }
        "PROCESSING" -> { }
        "REJECT", "FAIL" -> { }
        "CANCELED_BY_USER" -> { }
        "INTERNAL_ERROR" -> { }
        else -> { }
    }
}

Payment states

StateMeaning
SUCCEEDEDThe payment was completed successfully.
PROCESSINGThe payment is still being processed.
REJECTThe payment was rejected by the provider.
FAILThe payment failed.
CANCELED_BY_USERThe customer abandoned the additional step.
INTERNAL_ERRORAn unexpected error occurred while resuming the payment.
continueCardPayment supports CARD payments only.

Complementary features

Yuno Android SDK provides additional services and configurations you can use to improve customers’ experience. Use the SDK customization to change the SDK appearance to match your brand or to configure the loader.

Loader

The loader functionality is controlled through the keepLoader parameter in the YunoConfig data class, which is documented inline in the SDK configuration section above.

SDK customization

You can change the SDK appearance to match your brand. For more information, see the SDK customization page.
Access the Demo AppIn addition to the code examples provided, you can see the Yuno repository to complete Yuno Android SDKs implementation.

Step 9: Continue payment (Not supported)

Missing Mobile SupportThe getContinuePaymentAction method and the “Continue Payment” settings (required for features like Passkey SCOF) are currently not supported in the Headless Android SDK.If your integration requires these features, consider using the Full Checkout SDK or the Web Headless SDK as an alternative.

Error handling

Handle errors returned by the SDK in your app (e.g. failed payments, validation errors). For HTTP status and response codes, see Status and response codes in the API reference.