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

# Render mode

> Migrate Android Render integrations (Activity.startPaymentRender + YunoPaymentRenderListener) to the unified Transaction API.

Render mode lets you embed the SDK's payment form inside your own layout: you called `startPaymentRender(…)` and received a `YunoPaymentFragmentController` plus a `YunoPaymentRenderListener.showView(fragment)` callback that delivered the SDK's `Fragment`. You placed it in your layout and called `controller.submitForm()` (or `controller.continuePayment()` for the 3DS step) from your own button.

In the unified API the same pattern is expressed by overriding [`showView`](/docs/yuno-sdk/controllers/show-view). The SDK still hands you a `Fragment`; you receive it together with a `TransactionProcess` control object that exposes `onSubmit()` and `onClose()`. Continuation (3DS / redirect) is no longer a separate call. The SDK emits a second `showView` with `step = ACTION` when it needs to.

## Before you start

* Replace the `com.yuno.sdk.*`, `com.yuno.payments.features.*` and `com.yuno.presentation.*` imports with their `com.yuno.payments.sdk.api.*` counterparts (the side-by-side lists them). Your public API key and the checkout sessions your backend creates do not change ([Before you begin](/docs/yuno-sdk/get-started#before-you-begin)).
* Decide who creates the payment. The checkout session's `workflow` must match that decision:

| Who creates the payment | In Render you had | In the unified API | Session `workflow` |
| - | - | - | - |
| Your backend | `returnOneTimeToken` implemented (the headless-render variant) | Override `createPayment` | Default (`SDK_CHECKOUT`) |
| The SDK | No `returnOneTimeToken` | No override | `SDK_SEAMLESS` |

<Warning>
  A default-workflow session with no `createPayment` override ends in `INTERNAL_ERROR`: the backend rejects the SDK's payment creation. See [`createPayment`](/docs/yuno-sdk/controllers/create-payment).
</Warning>

## Side-by-side

<CodeGroup>
  ```kotlin Before. Render mode theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
  import androidx.fragment.app.Fragment
  import com.yuno.sdk.payments.render.startPaymentRender
  import com.yuno.sdk.payments.render.YunoPaymentFragmentController
  import com.yuno.sdk.payments.render.YunoPaymentRenderListener
  import com.yuno.payments.features.payment.models.OneTimeTokenModel
  import com.yuno.presentation.core.components.PaymentSelected

  class CheckoutActivity : ComponentActivity(), YunoPaymentRenderListener {

      private var controller: YunoPaymentFragmentController? = null

      fun pay(paymentSelected: PaymentSelected) {
          controller = startPaymentRender(
              checkoutSession = "session-from-backend",
              countryCode = "CO",
              submitButton = false,
              showPaymentStatus = false,
              coroutineScope = lifecycleScope,
              paymentSelected = paymentSelected,
              controller = this,
          )
      }

      override fun showView(fragment: Fragment) {
          // Embed in your layout
          supportFragmentManager.beginTransaction()
              .replace(R.id.yuno_form_container, fragment)
              .commit()
      }

      override fun loadingListener(isLoading: Boolean) { /* show your own loader */ }

      override fun returnStatus(resultCode: Int, paymentStatus: String, paymentSubStatus: String?) {
          // resultCode + paymentStatus
      }

      override fun returnOneTimeToken(oneTimeToken: String, additionalData: OneTimeTokenModel?) {
          // (only fires in the headless-render variant)
      }

      fun onPayButton() {
          controller?.submitForm()
      }

      // Called after the merchant's backend returns from 3DS / redirect
      fun onContinuePayment() {
          controller?.continuePayment()
      }
  }
  ```

  ```kotlin After. showView override theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
  import androidx.fragment.app.Fragment
  import com.yuno.payments.sdk.api.Transaction
  import com.yuno.payments.sdk.api.TransactionConfig
  import com.yuno.payments.sdk.api.TransactionController
  import com.yuno.payments.sdk.api.models.TransactionProcess
  import com.yuno.payments.sdk.api.models.TransactionViewStep
  import com.yuno.payments.sdk.api.models.PaymentMethodSelected
  import com.yuno.payments.sdk.api.models.TransactionStatus

  class CheckoutActivity : ComponentActivity(), TransactionController {

      private var process: TransactionProcess? = null

      fun pay(paymentSelected: PaymentMethodSelected) {
          val config = TransactionConfig(
              checkoutSession = "session-from-backend",
              countryCode = "CO",
              controller = this,
          )

          Transaction(config = config)
              .start(activity = this, paymentSelected = paymentSelected)
      }

      // 1. Embed the delivered fragment (called once per step: FORM, then ACTION for 3DS if applicable)
      override fun showView(view: Fragment, process: TransactionProcess, step: TransactionViewStep) {
          this.process = process
          supportFragmentManager.beginTransaction()
              .replace(R.id.yuno_form_container, view)
              .commit()
      }

      // 2. Override showLoading if you want to render your own loader
      override fun showLoading(isLoading: Boolean) { /* show your own loader */ }

      // 3. Final status arrives through onStatus
      override fun onStatus(status: TransactionStatus) {
          // status.status: "SUCCEEDED" / "REJECTED" / ...
      }

      fun onPayButton() {
          process?.onSubmit()
      }
  }
  ```
</CodeGroup>

## What changes

Grouped in the order you edit the code. **Renamed**: same role, new name. **Moved**: same value, new owner. **Removed**: nothing to call. The last column is the only thing you have to do beyond the rename.

### Initialization and config

| Render | Unified | Change | What to do |
| - | - | - | - |
| `import com.yuno.sdk.*` | `import com.yuno.payments.sdk.api.*` | Renamed | |
| `checkoutSession`, `countryCode` arguments of `startPaymentRender` | The same fields on `TransactionConfig` | Moved | The call's arguments become config fields. |
| `submitButton` argument of `startPaymentRender` | *(removed)* | Removed | Delete it: the submit button is fully owned by you in the unified API. The SDK never renders one when `showView` is overridden; render it in your layout and call `process.onSubmit()` when tapped (see Views). |
| `showPaymentStatus` argument of `startPaymentRender` | `TransactionConfig.showStatusScreen` | Moved | Same role. |
| `coroutineScope` argument of `startPaymentRender` | *(removed)* | Removed | Delete it: the SDK manages its own scope. |

### Controller

| Render | Unified | Change | What to do |
| - | - | - | - |
| `YunoPaymentRenderListener` | `TransactionController` | Renamed | Implement the same class and pass it as `TransactionConfig.controller` (it was the `controller` argument of `startPaymentRender`). The SDK does not retain it: keep it alive for the whole transaction. |
| `returnStatus(resultCode, paymentStatus, paymentSubStatus)` | `onStatus(status: TransactionStatus)` | Renamed | Still the single outcome callback, once per transaction, also when the SDK shows its result screen. `resultCode` (the `PAYMENT_RESULT_*` ints) is dropped: branch on `status.status` instead. The status string is now wrapped in a `TransactionStatus` object whose `status` and `substatus` come from the backend, as the backend returns them. The legacy `REJECT`, `FAIL` and `PROCESSING` strings are no longer emitted: handle `DECLINED`, `REJECTED`, `ERROR` and `PENDING` instead. `CANCELED_BY_USER` is now `USER_CANCEL`; the SDK itself only emits `INTERNAL_ERROR` and `USER_CANCEL`. See [`Status`](/docs/yuno-sdk/reference/objects-you-receive#status). |
| `returnOneTimeToken(oneTimeToken, additionalData)` | `createPayment(token: Map<String, Any>)` | Renamed | Optional. It only fired in the headless-render variant, so it is only relevant for the non-seamless headless path. If you used it, override `createPayment`: `token` is the full One-Time Token as a map. Create the payment and return. If the handler throws, the flow stops and `onStatus` is not called, so show the error yourself. See [`createPayment`](/docs/yuno-sdk/controllers/create-payment) and [Headless migration](/docs/yuno-sdk/migration/android/payment/headless). |
| `loadingListener(isLoading)` | `showLoading(isLoading)` | Renamed | Same semantics. Render is the legacy mode where the loader callback was actually invoked, so existing Render integrations almost certainly need to migrate this. Once overridden, the SDK hides its own loader and reports the state to you. See [`showLoading`](/docs/yuno-sdk/controllers/show-loading). |

### Views

| Render | Unified | Change | What to do |
| - | - | - | - |
| `YunoPaymentRenderListener.showView(fragment)` | `showView(view, process, step)` | Renamed | Push, not pull: you no longer call anything to fetch the fragment, the SDK delivers it to your handler when ready. `process` replaces the `YunoPaymentFragmentController`. `showView` can be called more than once per transaction and `step` tells you which step you received: `FORM` for the data-capture form, `ACTION` for a 3DS challenge or external redirect. Decide how to embed each in your layout. See [`showView`](/docs/yuno-sdk/controllers/show-view). |
| `controller.submitForm()` | `process.onSubmit()` | Renamed | Same role. Call it on the `TransactionProcess` you receive in `showView`. |
| `controller.continuePayment()` | *(removed)* | Removed | Delete the call. 3DS is handled by the SDK: when a 3DS challenge or redirect is required it triggers a second `showView(view, process, step = ACTION)` itself, and you can keep embedding it inside your layout. You don't need to call anything. |

### Entry points

| Render | Unified | Change | What to do |
| - | - | - | - |
| `startPaymentRender(checkoutSession, countryCode, …, paymentSelected, controller)` returning `YunoPaymentFragmentController` | `Transaction(config).start(activity, paymentSelected)` | Renamed | Build the config, then `start`: the `Transaction` is the single entry point and the selection goes to `start`. Override `showView` to keep the form inside your layout (see Views). |
| `PaymentSelected` | `PaymentMethodSelected` | Renamed | Same role: the value you pass to `start`. |

## Related

* [`showView`](/docs/yuno-sdk/controllers/show-view). Full reference for the controller and `TransactionProcess`.
* [`showLoading`](/docs/yuno-sdk/controllers/show-loading). Loading-state controller.
* [`TransactionConfig`](/docs/yuno-sdk/reference/objects-you-pass#transaction-config). Complete field reference.
* [Migration / Lite](/docs/yuno-sdk/migration/android/payment/lite). When you don't need to embed the form yourself.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.