> ## Documentation Index
> Fetch the complete documentation index at: https://yuno-3979e326-fix-create-subscription-card-usage.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Flutter

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

Integrate Yuno's Flutter SDK Lite payment and enrollment flows by following these steps.

## Requirements

* Flutter SDK installed (Dart included).
* iOS 14.0 or above.
* Android minSdkVersion 21 or above.
* Java 8 enabled and AndroidX enabled.
* Android Gradle plugin 4.0.0 or above.
* Proguard 6.2.2 or above.
* Kotlin Gradle plugin 1.4.0 or above.
* `FlutterFragmentActivity` for `MainActivity` on Android.

## Adding the SDK to your project

This section applies to both Payment and Enrollment flows. Complete these steps before implementing either flow.

### Flutter package

Add the Yuno package to your Flutter project:

```bash theme={null}
flutter pub add yuno
```

### Android configuration

Add the Yuno Maven repository to your project-level `android/build.gradle`:

```groovy theme={null}
allprojects {
  repositories {
    google()
    mavenCentral()
    maven { url "https://yunopayments.jfrog.io/artifactory/snapshots-libs-release" }
  }
}
```

Use `FlutterFragmentActivity` in `MainActivity.kt`:

```kotlin theme={null}
class MainActivity: FlutterFragmentActivity()
```

Create a custom `Application` and initialize the native SDK:

```kotlin theme={null}
import android.app.Application
import com.yuno_flutter.yuno_sdk_android.YunoSdkAndroidPlugin

class MyApp : Application() {
  override fun onCreate() {
    super.onCreate()
    YunoSdkAndroidPlugin.initSdk(this, "YUNO_API_KEY")
  }
}
```

Then register the application class in `AndroidManifest.xml`:

```xml theme={null}
<application
  android:name=".MyApp">
```

### iOS configuration

No additional iOS-specific configuration is required beyond the Flutter package installation. iOS appearance customization is configured through `IosConfig` during SDK initialization (see customizations section).

## Payment

Follow these steps to integrate the Yuno payment flow in your Flutter application.

<Steps>
  <Step title="Create a customer and checkout session">
    Before initiating a payment, create a customer and checkout session using Yuno's server-side API.

    * Use [Create customer](/reference/customers/create-customer) to represent the person making the payment.
    * Use [Create checkout session](/reference/checkout-sessions/create-checkout-session) to define transaction details.
      Keep the returned `checkout_session` ID for the next steps.
  </Step>

  <Step title="Initialize the SDK">
    Initialize the Yuno SDK in your Flutter app, typically before `runApp` in `main.dart`.

    ```dart theme={null}
    await Yuno.init(
      apiKey: 'YOUR_PUBLIC_API_KEY',
      countryCode: 'CO',
      yunoConfig: const YunoConfig(),
      iosConfig: const IosConfig(),
    );
    ```
  </Step>

  <Step title="Start the checkout process">
    Set up a payment listener (e.g., `YunoPaymentListener`) in your widget tree to receive events.

    ```dart theme={null}
    YunoPaymentListener(
      listener: (context, state) {
        final ott = state.token;
        if (ott.isNotEmpty) {
          // Send ott to your backend
        }
      },
      child: YourWidget(),
    )
    ```
  </Step>

  <Step title="Initiate payment">
    Start the Lite payment flow by calling `startPaymentLite` with the selected payment method.

    ```dart theme={null}
    await Yuno.startPaymentLite(
      arguments: StartPayment(
        checkoutSession: checkoutSessionId,
        methodSelected: const MethodSelected(
          paymentMethodType: 'CARD',
        ),
      ),
    );
    ```
  </Step>

  <Step title="Get the OTT (one-time token)">
    After the user completes the form, the SDK generates an OTT delivered to your `YunoPaymentListener`.

    ```dart theme={null}
    listener: (context, state) {
      final ott = state.token;
      if (ott.isNotEmpty) {
        // Send ott to your backend
      }
    }
    ```
  </Step>

  <Step title="Create the payment">
    Use the OTT from Step 5 to create the payment in your backend via the [Create payment](/reference/payments/create-payment) endpoint.
  </Step>

  <Step title="Continue payment">
    If the response includes `sdk_action_required: true`, call `continuePayment` to handle 3DS or redirects.

    ```dart theme={null}
    await Yuno.continuePayment(showPaymentStatus: true);
    ```
  </Step>
</Steps>

### Payment status validation

The SDK manages the relationship between frontend SDK status and backend payment status when users interact with payment flows. Understanding this distinction helps you handle payment states correctly in your application.

#### Sync payment methods (Apple Pay and Google Pay)

For synchronous payment methods like Apple Pay and Google Pay, when a user cancels or closes the wallet UI before a payment service provider (PSP) response is received:

* **SDK status**: Returns `cancelByUser` (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 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.

## Enrollment

Follow these steps to enroll payment methods in your Flutter application.

<Steps>
  <Step title="Create customer and session">
    Create a customer and a `customer_session` in your backend using the [Create customer session](/reference/customer-sessions-enrollment/create-customer-session) endpoint.
  </Step>

  <Step title="Initialize the SDK">
    Ensure the SDK is initialized with your API key and configuration.

    ```dart theme={null}
    await Yuno.init(
      apiKey: 'YOUR_PUBLIC_API_KEY',
      countryCode: 'CO',
    );
    ```
  </Step>

  <Step title="Start enrollment process">
    Set up a `YunoEnrollmentListener` to receive status updates.

    ```dart theme={null}
    YunoEnrollmentListener(
      listener: (context, state) {
        final status = state.enrollmentStatus;
        // Handle status updates
      },
      child: YourWidget(),
    )
    ```
  </Step>

  <Step title="Initiate enrollment">
    Call `enrollmentPayment` with the customer session ID.

    ```dart theme={null}
    await Yuno.enrollmentPayment(
      arguments: EnrollmentArguments(
        customerSession: customerSessionId,
        showPaymentStatus: true,
      ),
    );
    ```
  </Step>

  <Step title="Listen for status">
    Monitor the enrollment status through your listener callback.

    ```dart theme={null}
    listener: (context, state) {
      final status = state.enrollmentStatus;
      // Handle completion or errors
    }
    ```
  </Step>

  <Step title="Handle deep links (optional)">
    For methods using external authentication, pass the redirect URL to the SDK.

    ```dart theme={null}
    await Yuno.receiveDeeplink(url: uri);
    ```
  </Step>
</Steps>

## Parameters

For the full list of parameters and options, see the subsections that follow.

### `Yuno.init`

| Parameter     | Description                                                                                            |
| :------------ | :----------------------------------------------------------------------------------------------------- |
| `apiKey`      | Your Yuno public API key.                                                                              |
| `countryCode` | Country where the payment is performed. See [Country coverage](/docs/sdks/resources/country-coverage). |
| `yunoConfig`  | SDK configuration options. See `YunoConfig` below.                                                     |
| `iosConfig`   | iOS appearance configuration. See `IosConfig` below.                                                   |

### `YunoConfig`

| Parameter        | Description                                                                                                                                                                                                                                                 |
| :--------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `lang`           | Defines the language used in the payment forms. Set it to one of the available options: en (English), es (Spanish), pt (Portuguese), ms (Malay), id (Indonesian), th (Thai), ar (Arabic). See [Supported languages](#supported-languages) for more details. |
| `saveCardEnable` | Enables the Save card checkbox on card flows, allowing users to save their card for future payments. Default: `false`.                                                                                                                                      |

### `IosConfig`

| Parameter    | Description                                                                                                                                                  |
| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `appearance` | iOS-only appearance customization. See [`Appearance`](#appearance-ios) below and the [customizations](#customizations) section for detailed styling options. |

### `Appearance` (iOS)

| Parameter                              | Description                                      |
| :------------------------------------- | :----------------------------------------------- |
| `fontFamily`                           | iOS font family name.                            |
| `accentColor`                          | Accent color for highlights and active elements. |
| `buttonBackgroundColor`                | Primary button background color.                 |
| `buttonTitleBackgroundColor`           | Primary button title color.                      |
| `buttonBorderBackgroundColor`          | Primary button border color.                     |
| `secondaryButtonBackgroundColor`       | Secondary button background color.               |
| `secondaryButtonTitleBackgroundColor`  | Secondary button title color.                    |
| `secondaryButtonBorderBackgroundColor` | Secondary button border color.                   |
| `disableButtonBackgroundColor`         | Disabled button background color.                |
| `disableButtonTitleBackgroundColor`    | Disabled button title color.                     |
| `checkboxColor`                        | Checkbox color.                                  |

### `StartPayment` (Lite)

| Parameter           | Description                                                                                                                                                                                                               |
| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `checkoutSession`   | The `checkout_session` ID created in your backend using the [Create checkout session](/reference/checkout-sessions/create-checkout-session) endpoint. This session identifier is required to initialize the payment flow. |
| `methodSelected`    | The selected payment method information. See `MethodSelected` below for details on specifying the payment method type and optional vaulted token.                                                                         |
| `showPaymentStatus` | Controls whether the SDK displays its built-in payment status screens after payment completion. Set to `false` if you want to handle status display in your own UI. Default: `true`.                                      |

### `MethodSelected`

| Parameter           | Description                                                                                                                                                                                                               |
| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `paymentMethodType` | Payment method type selected by the user. Common values include: `CARD`, `PIX`, `PAYPAL`, `MERCADO_PAGO`, `GOOGLE_PAY`, `APPLE_PAY`. This value must match one of the payment methods available in your checkout session. |
| `vaultedToken`      | Optional vaulted token to reuse a previously saved payment method. When provided, the SDK will use the saved payment method instead of prompting for new payment details. Leave empty for new payment methods.            |

### `EnrollmentArguments`

| Parameter           | Description                                                                                                                                                                                                                                              |
| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `customerSession`   | The `customer_session` ID created in your backend using the [Create customer session](/reference/customer-sessions-enrollment/create-customer-session) endpoint. This session is used to associate the enrolled payment method with a specific customer. |
| `showPaymentStatus` | Controls whether the SDK displays its built-in enrollment status screens after enrollment completion. Set to `false` if you want to handle status display in your own UI. Default: `true`.                                                               |
| `countryCode`       | Optional country code override for this enrollment. If not provided, the SDK uses the country code from `Yuno.init()`. See [Country coverage](/docs/sdks/resources/country-coverage) for supported countries.                                            |

## customizations

You can customize SDK behavior and appearance using the configuration options:

* `YunoConfig` for language, save card, and loader handling
* `IosConfig.appearance` for iOS UI styling
* Android styling through native configuration (see below)

### iOS customization

iOS appearance is fully customizable through the `IosConfig.appearance` parameter in `Yuno.init()`. You can modify visual styling to match your brand identity, including colors, fonts, and button designs.

#### Available iOS customization options

| Parameter                              | Type   | Description                                                                                                 |
| -------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------- |
| `fontFamily`                           | String | Custom font family name for all SDK text. Use the font name as registered in your iOS project's Info.plist. |
| `accentColor`                          | Color  | Primary accent color used for highlights, active states, and interactive elements throughout the SDK.       |
| `buttonBackgroundColor`                | Color  | Background color for primary action buttons (e.g., "Pay", "Confirm").                                       |
| `buttonTitleBackgroundColor`           | Color  | Text color for primary button labels.                                                                       |
| `buttonBorderBackgroundColor`          | Color  | Border color for primary buttons. Set to match background for borderless buttons.                           |
| `secondaryButtonBackgroundColor`       | Color  | Background color for secondary/cancel buttons.                                                              |
| `secondaryButtonTitleBackgroundColor`  | Color  | Text color for secondary button labels.                                                                     |
| `secondaryButtonBorderBackgroundColor` | Color  | Border color for secondary buttons.                                                                         |
| `disableButtonBackgroundColor`         | Color  | Background color for disabled buttons (when user cannot proceed).                                           |
| `disableButtonTitleBackgroundColor`    | Color  | Text color for disabled button labels.                                                                      |
| `checkboxColor`                        | Color  | Color for checkboxes like "Save card for future payments".                                                  |

When using `Color(0xFF...)` for iOS appearance customization, add `import 'dart:ui';` at the top of your file.

For more iOS customization options, see [SDK customizations (iOS)](/docs/sdks/customization/ios).

### Android customization

For Android, the Flutter SDK uses the native Android SDK's styling system. customization is performed in the native Android layer using Kotlin/Java code when initializing the SDK through `YunoSdkAndroidPlugin.initSdk()`.

#### YunoConfig (Android)

The Android SDK supports comprehensive styling through the `YunoConfig` data class:

<Warning>
  **cardFlow removed from YunoConfig (Android 2.11.0+)**

  Card flow configuration is now handled exclusively through the **CheckoutBuilder** in the Dashboard. Omit `cardFlow` from `YunoConfig`.
</Warning>

```dart theme={null}
class YunoConfig {
  bool saveCardEnabled;
  YunoConfig({
    this.saveCardEnabled = false,
  });
}
```

#### YunoStyles

Control the visual appearance of SDK components:

```kotlin theme={null}
data class YunoStyles(
    val buttonStyles: YunoButtonStyles? = null,
    val fontFamily: FontFamily? = null
)
```

| Parameter      | Type             | Description                                                                                                                                                        |
| -------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `buttonStyles` | YunoButtonStyles | Customizes all primary action buttons displayed in the SDK including background, text, borders, and state colors. See YunoButtonStyles below for detailed options. |
| `fontFamily`   | FontFamily       | Sets a custom font family for all text elements throughout the SDK. Use a FontFamily registered in your Android app.                                               |

#### YunoButtonStyles

Fine-tune button appearance with these options:

```kotlin theme={null}
data class YunoButtonStyles(
    val backgroundColor: Color? = null,
    val contentColor: Color? = null,
    val cornerRadius: Dp? = null,
    val elevation: Dp? = null,
    val padding: Dp? = null,
    val fontFamily: FontFamily? = null,
    val fontSize: TextUnit? = null,
    val fontStyle: FontStyle? = null
)
```

| Parameter         | Type       | Description                                                              |
| ----------------- | ---------- | ------------------------------------------------------------------------ |
| `backgroundColor` | Color      | Background color for buttons.                                            |
| `contentColor`    | Color      | Text and icon color for buttons.                                         |
| `cornerRadius`    | Dp         | Button corner radius for rounded corners. Use `0.dp` for square buttons. |
| `elevation`       | Dp         | Shadow elevation for Material Design elevation effect.                   |
| `padding`         | Dp         | Internal padding inside buttons.                                         |
| `fontFamily`      | FontFamily | Font family specifically for button text (overrides global fontFamily).  |
| `fontSize`        | TextUnit   | Font size for button text.                                               |
| `fontStyle`       | FontStyle  | Font style (normal, italic, bold) for button text.                       |

Configure styles in your `Application` class during SDK initialization in `MyApp.kt`. For more Android customization options including XML themes and drawable customization, see [SDK customizations (Android)](/docs/sdks/customization/android).

## Environment variables (recommended)

Use `--dart-define` to avoid hardcoding keys:

```bash theme={null}
flutter run --dart-define="YUNO_API_KEY=apiKey"
```

Then read it in Dart:

```dart theme={null}
const apiKey = String.fromEnvironment('YUNO_API_KEY', defaultValue: '');
```

If you also need the key on the Android native side, map `dart-defines` into `BuildConfig` and read `BuildConfig.YUNO_API_KEY` in `MyApp` (see the Flutter SDK README for the full snippet).

## Troubleshooting

| Issue                                                            | Cause                                                                                                                                                 | Fix                                                                                                                                                                                                                                                   |
| :--------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Country code has not been initialized. Call Yuno.init() first.` | `Yuno.init()` was not called or failed before calling payment/enrollment methods.                                                                     | Ensure `Yuno.init()` completes before any SDK call, and avoid hot reload for Android configuration changes. Perform a full restart after initialization changes.                                                                                      |
| Android native initialization fails silently                     | The Android native SDK was not initialized in the `Application` class, or the custom `Application` class was not registered in `AndroidManifest.xml`. | Verify that: 1) `YunoSdkAndroidPlugin.initSdk()` is called in your custom `Application` class `onCreate()`, 2) The custom `Application` class is registered in `AndroidManifest.xml` with `android:name=".MyApp"`, 3) The API key is correct.         |
| Hot reload causes Android initialization issues                  | Flutter's hot reload does not re-execute native platform initialization code.                                                                         | Perform a full app restart (stop and restart) instead of hot reload when making changes to `Yuno.init()` or Android native configuration.                                                                                                             |
| Payment status listener not triggered                            | Listener widget is not in the widget tree above the point where payment is initiated, or the listener is recreated during navigation.                 | Ensure `YunoPaymentListener` or `YunoMultiListener` wraps the relevant part of your widget tree and persists across navigation. Place it high in the widget tree (e.g., wrapping `MaterialApp` or a top-level screen).                                |
| Deep links not working on iOS                                    | URL scheme not configured in `Info.plist` or scheme does not match the `callback_url` in checkout/customer session.                                   | Add URL scheme configuration to `Info.plist` matching the scheme used in your `callback_url`. Ensure the scheme is unique to your app. Call `Yuno.receiveDeeplink(url: uri)` in your deep link handler.                                               |
| Android build fails with Maven repository error                  | Yuno Maven repository not added or added in wrong location in `build.gradle`.                                                                         | Add `maven { url "https://yunopayments.jfrog.io/artifactory/snapshots-libs-release" }` to the `repositories` block in your project-level `android/build.gradle` (not in the app-level `build.gradle`). Ensure it is inside the `allprojects` section. |
| `MainActivity` crashes on Android                                | `MainActivity` does not extend `FlutterFragmentActivity` as required by the Yuno SDK.                                                                 | Change your `MainActivity` to extend `FlutterFragmentActivity` instead of `FlutterActivity`: `class MainActivity: FlutterFragmentActivity()`                                                                                                          |
| Token is empty or null in payment listener                       | Payment form validation failed, or the user canceled before completing the form.                                                                      | Check for validation errors in the payment form. Ensure all required fields are filled correctly. Add null/empty checks in your listener before using the token.                                                                                      |
| customization not applied                                        | Platform-specific customization not configured correctly or cached build artifacts.                                                                   | For iOS: Verify `IosConfig.appearance` is properly set in `Yuno.init()`. For Android: Check native styling in XML or programmatic configuration. Clear build cache with `flutter clean` and rebuild.                                                  |

## Notes

* The Lite payment flow requires you to render the payment method list and pass the selected `paymentMethodType`.
* Use `YunoPaymentListener`/`YunoEnrollmentListener` to receive OTT/status updates and drive backend calls.

## Supported languages

The Flutter SDK supports the following `YunoLanguage` values:

`en` (English), `es` (Spanish), `pt` (Portuguese), `ms` (Malay), `id` (Indonesian), `th` (Thai), `ar` (Arabic).
