> ## 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 iOS Render integrations (Yuno.startPaymentRenderFlow + formView + submitForm) to the unified Transaction API.

Render mode let you embed the SDK's payment form inside your own layout: you got a `YunoPaymentRenderFlowProtocol` from `Yuno.startPaymentRenderFlow(...)`, asked it for a `formView` to place wherever you wanted, and called `submitForm()` from your own button when the user was ready to pay.

In the unified API the same pattern is expressed by overriding [`showView`](/docs/yuno-sdk/controllers/show-view). The SDK still provides the form view; you receive it together with a `TransactionProcess` control object that exposes `onSubmit()`.

## Before you start

* Replace `import YunoSDK` with `import SdkPayments`. 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 | `yunoCreatePayment` implemented | Override `createPayment` | Default (`SDK_CHECKOUT`) |
| The SDK | No equivalent: only Seamless let the SDK create the payment | 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>
  ```swift Before. Render mode theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
  import SwiftUI
  import YunoSDK

  // 1. Initialize once at app startup
  Yuno.initialize(apiKey: "your-public-api-key")

  // 2. Implement the delegate
  final class CheckoutModel: YunoPaymentDelegate, ObservableObject {
      var checkoutSession: String = "session-from-backend"
      var countryCode: String = "CO"
      var language: String? = "en"
      var viewController: UIViewController?

      func yunoPaymentResult(_ result: Yuno.Result) { /* ... */ }

      // Called by the SDK during render mode (the only mode where this fires)
      func onLoading(isLoading: Bool) { /* show your own loader */ }
  }

  // 3. Embed the form, render layout yourself, submit from your button
  struct CheckoutView: View {
      @StateObject var model = CheckoutModel()
      let selectedMethod: PaymentMethodSelected
      @State var paymentFlow: YunoPaymentRenderFlowProtocol?
      @State var formView: AnyView?

      var body: some View {
          VStack {
              Text("Checkout")
              // ... your products / shipping / etc.
              formView    // SDK form embedded here
              Button("Pay") {
                  paymentFlow?.submitForm()
              }
          }
          .task {
              paymentFlow = await Yuno.startPaymentRenderFlow(
                  paymentMethodSelected: selectedMethod,
                  with: model
              )
              formView = await paymentFlow?.formView(
                  paymentMethodSelected: selectedMethod,
                  with: model
              )
          }
      }
  }
  ```

  ```swift After. OnShowView override theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
  import SwiftUI
  import SdkPayments

  // 1. Initialize once at app startup
  SdkPayments.initialize(apiKey: "your-public-api-key")

  // 2. Implement the controller. Override showView + showLoading
  final class CheckoutModel: SdkPayments.TransactionController, ObservableObject {

      @Published var formView: AnyView?
      @Published var process: SdkPayments.TransactionProcess?
      @Published var isLoading: Bool = false

      func showView(view: AnyView?, process: SdkPayments.TransactionProcess, step: SdkPayments.TransactionViewStep) {
          // step == .FORM for the data-capture form, .ACTION for a payment code or OTP view. 3DS and redirects are full-screen.
          self.formView = view
          self.process = process
      }

      func showLoading(isLoading: Bool) {
          self.isLoading = isLoading
      }

      func onStatus(status: SdkPayments.TransactionStatus) { /* ... */ }
  }

  // 3. Embed the delivered view, submit via process.onSubmit()
  struct CheckoutView: View {
      @StateObject var model = CheckoutModel()
      let selectedMethod: SdkPayments.PaymentMethodSelected

      var body: some View {
          VStack {
              Text("Checkout")
              // ... your products / shipping / etc.
              if model.isLoading { ProgressView() }
              model.formView
              Button("Pay") {
                  model.process?.onSubmit()
              }
          }
          .task {
              let config = SdkPayments.TransactionConfig(
                  checkoutSession: "session-from-backend",
                  countryCode: "CO",
                  controller: model
              )
              SdkPayments.Transaction(config: config)
                  .start(paymentSelected: selectedMethod)
          }
      }
  }
  ```
</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. **New**: no legacy counterpart. The last column is the only thing you have to do beyond the rename.

### Initialization and config

| Render | Unified | Change | What to do |
| - | - | - | - |
| `import YunoSDK` | `import SdkPayments` | Renamed | |
| `Yuno.initialize(apiKey:)` | `SdkPayments.initialize(apiKey:)` | Renamed | The `callback:` parameter is gone; use the `async` overload if you need to wait. |
| `Yuno.Appearance` passed in `YunoConfig.appearance` | `SdkPayments.Appearance` in `SdkPayments.TransactionConfig.appearance` | Renamed | Same initializer; drop the `Yuno.` prefix and pass it per transaction instead of once at startup. |
| `YunoPaymentDelegate.checkoutSession`, `.countryCode`, `.language`, `.viewController` | The same fields on `SdkPayments.TransactionConfig` | Moved | Delegate properties become config fields. `viewController` stays iOS-only and optional in SwiftUI. |

### Controller

| Render | Unified | Change | What to do |
| - | - | - | - |
| `YunoPaymentDelegate` | `SdkPayments.TransactionController` | Renamed | Conform the same class and pass it as `TransactionConfig.controller`. As before, the SDK does not retain it: keep it alive for the whole transaction. |
| `yunoPaymentResult(_:)` | `onStatus(status:)` | Renamed | Still the single outcome callback, once per transaction, also when the SDK shows its result screen. `status` and `substatus` come from the backend; the SDK itself only emits `INTERNAL_ERROR` and `USER_CANCEL`. See [`Status`](/docs/yuno-sdk/reference/objects-you-receive#status). |
| `Yuno.Result.message` | `SdkPayments.TransactionStatus.message` | Renamed | Same role. `source` is now an enum (`.sdk` / `.backend`) and `code` is non-optional. |
| `yunoCreatePayment(with:)` / `(with:information:)` | `createPayment(token:)` | Renamed | Optional. One handler replaces both variants; `token` is the full One-Time Token as a dictionary. Create the payment and return: returning is what used to be `continuePayment()`. 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). |
| `YunoLoaderDelegate.onLoading(isLoading:)` | `showLoading(isLoading:)` | Renamed | Same semantics. Render was the only legacy mode that actually invoked it, 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). |
| `onInstallmentSelected(_:)` with `YunoInstallmentSelected` | `onInstallmentSelected(_:)` with `SdkPayments.InstallmentSelected` | Renamed | Optional. Same trigger and fields; only the payload type changes. It fires when the shopper selects or changes an installment in the SDK's card form, including the SDK's default auto-selection, and with `nil` when the selection no longer applies. See [`onInstallmentSelected`](/docs/yuno-sdk/controllers/on-installment-selected). |
| `YunoShippingDelegate.onShippingAddressChanged(_:shippingInfo:)` | `onShippingAddressChanged(_:shippingInfo:)` via `SdkPayments.ShippingAddressHandling` | Moved | Optional. Conform the controller to the protocol; the types drop the `Yuno` prefix and the completion-based variant is gone. Same async signature and role: real-time shipping updates on the Apple Pay sheet. The protocol inherits from `TransactionController`, so the SDK picks it up from the `controller` you pass in the config. See [`onShippingAddressChanged`](/docs/yuno-sdk/controllers/on-shipping-address-changed). |

### Views

| Render | Unified | Change | What to do |
| - | - | - | - |
| `paymentFlow.formView(paymentMethodSelected:with:)` | `showView(view:process:step:)` | Moved | Push, not pull: you no longer fetch the view, the SDK delivers it to your handler when ready. Cache it in your model and render it from there. `showView` can be called more than once per transaction: `step == .FORM` for the data-capture form, `step == .ACTION` for an action view such as a payment code or an OTP. 3DS challenges and redirects never come through `showView`: the SDK presents them full-screen. See [`showView`](/docs/yuno-sdk/controllers/show-view). |
| `paymentFlow.submitForm()` | `process.onSubmit()` | Renamed | Same role. Call it on the `TransactionProcess` you receive in `showView`. |
| *(none)* | `SdkPayments.defaultShowView(view:process:step:)` | New | Call it from your `showView` override for the steps you don't want to embed (for example, embed `.FORM` and hand `.ACTION` back to the SDK). |

### Entry points

| Render | Unified | Change | What to do |
| - | - | - | - |
| `Yuno.startPaymentRenderFlow(paymentMethodSelected:with:)` | `SdkPayments.Transaction(config:).start(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). |
| `paymentFlow.continuePayment()` | *(removed)* | Removed | Delete the call: returning from `createPayment` resumes the flow. The SDK runs 3DS and redirects itself, full-screen; you no longer render them in your layout. Set [`autoContinuePayment`](/docs/yuno-sdk/reference/objects-you-pass#autocontinuepayment) to `false` only if you need the SDK to stop right after the payment is created. |
| `Yuno.receiveDeeplink(_:)` | `SdkPayments.handleDeeplink(_:)` | Renamed | Same role: forward the URL your app receives after an external redirect. See [Handle deeplinks](/docs/yuno-sdk/features/handle-deeplinks). |
| `Yuno.hideLoader()` | *(removed)* | Removed | Delete the call: the SDK dismisses its own loader. With a `showLoading` override you receive `isLoading: false` instead. |

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