> ## Documentation Index
> Fetch the complete documentation index at: https://docs.y.uno/llms.txt
> Use this file to discover all available pages before exploring further.

# Headless SDK (Payment Android)

> Step-by-step guide on integrating Yuno's Headless SDK (Payment Android) into your mobile application.

<Warning>
  **Orientation: Choosing Your Integration Flow**, before you begin, please review the [Official Integration Flow](/docs/sdks/overview/understanding-flows).

  * **Standard Flow ([Full Checkout](/docs/sdks/full-checkout/web-payments))**: 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.
</Warning>

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](/docs/sdks/full-checkout/android-payments) or [Lite SDK](/docs/sdks/lite-android/checkout) 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**.

<Accordion title="Official Yuno ProGuard / R8 rules">
  ```proguard theme={"theme":{"light":"github-dark","dark":"github-dark"}}
  # 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`.
</Accordion>

<Info>
  **Latest SDK Version**

  Check the Release notes or visit the [Yuno Android SDK repository](https://github.com/yuno-payments/yuno-sdk-android) to verify the current SDK version available.
</Info>

## Step 1: Create a customer

Create a customer using the [Create customer endpoint](/reference/customers/create-customer) 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](/reference/checkout-sessions/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:

```kotlin theme={"theme":{"light":"github-dark","dark":"github-dark"}}
maven { url "https://yunopayments.jfrog.io/artifactory/snapshots-libs-release" }
```

Add the Yuno SDK dependency to your application in the `build.gradle` file:

```kotlin theme={"theme":{"light":"github-dark","dark":"github-dark"}}
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)](/docs/using-yuno/settings/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:

```kotlin theme={"theme":{"light":"github-dark","dark":"github-dark"}}
class CustomApplication : Application() {
  override fun onCreate() {
    super.onCreate()
    Yuno.initialize(
      this,
      PUBLIC_API_KEY,
      config = YunoConfig(
        keepLoader = true,
      ),
    )
  }
}
```

<Info>
  For a detailed explanation of the `keepLoader` parameter and mandatory error handling, see the [Android Reference Guide](/docs/sdks/resources/references/android#keeploader-parameter).
</Info>

## 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:

| Parameter          | Description                                                                                                                                                                                                                                    |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `country_code`     | This 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](/docs/sdks/resources/country-coverage) page. |
| `checkout_session` | Refers to the current payment's checkout session created using the [Create Checkout Session](/reference/checkout-sessions/create-checkout-session) endpoint. Example: `'438413b7-4921-41e4-b8f3-28a5a0141638'`                                 |

The following code block shows an example of the parameter configuration:

```kotlin theme={"theme":{"light":"github-dark","dark":"github-dark"}}
 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.

```kotlin Example 1 theme={"theme":{"light":"github-dark","dark":"github-dark"}}
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
)

```

```javascript Example 2 theme={"theme":{"light":"github-dark","dark":"github-dark"}}
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.

```json Example 1 theme={"theme":{"light":"github-dark","dark":"github-dark"}}
["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]

```

```json Example 2 theme={"theme":{"light":"github-dark","dark":"github-dark"}}
["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:

```kotlin theme={"theme":{"light":"github-dark","dark":"github-dark"}}
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](/reference/payments/create-payment). 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:

```json theme={"theme":{"light":"github-dark","dark":"github-dark"}}
{
  "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

```kotlin theme={"theme":{"light":"github-dark","dark":"github-dark"}}
fun ApiClientPayment.continueCardPayment(
    activity: ComponentActivity,
    showPaymentStatus: Boolean = false,
    callbackPaymentState: ((String?, String?) -> Unit)? = null,
)
```

### Parameters

| Parameter              | Type                            | Description                                                                                                            |
| :--------------------- | :------------------------------ | :--------------------------------------------------------------------------------------------------------------------- |
| `activity`             | `ComponentActivity`             | The activity the SDK uses to present the pending action.                                                               |
| `showPaymentStatus`    | `Boolean`                       | If `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

```kotlin theme={"theme":{"light":"github-dark","dark":"github-dark"}}
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

| State              | Meaning                                                  |
| :----------------- | :------------------------------------------------------- |
| `SUCCEEDED`        | The payment was completed successfully.                  |
| `PROCESSING`       | The payment is still being processed.                    |
| `REJECT`           | The payment was rejected by the provider.                |
| `FAIL`             | The payment failed.                                      |
| `CANCELED_BY_USER` | The customer abandoned the additional step.              |
| `INTERNAL_ERROR`   | An 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](/docs/sdks/customization/android) 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](/docs/sdks/customization/android) page.

<Info>
  **Access the Demo App**

  In addition to the code examples provided, you can see the [Yuno repository](https://github.com/yuno-payments/yuno-sdk-android/tree/master) to complete Yuno Android SDKs implementation.
</Info>

## Step 9: Continue payment (Not supported)

<Warning>
  **Missing Mobile Support**

  The `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](/docs/sdks/full-checkout/android-payments) or the [Web Headless SDK](/docs/sdks/headless-web/payment) as an alternative.
</Warning>

## 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](/reference/payments/status-and-response-codes/payment) in the API reference.
