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

# Seamless mode

> Migrate iOS Seamless integrations (Yuno.startPaymentSeamlessLite) to the unified Transaction API.

Seamless was the simplest legacy entry point: a single `await` call that returned the final result. No delegate, no callbacks. You handed in a `SeamlessParams` and a `PaymentMethodSelected`; the SDK rendered the form, tokenized, created the payment, ran 3DS, and returned a `Yuno.Result`.

In the unified API the same flow is the **default behavior** of `Transaction.start(paymentSelected:)`. No controller overrides needed beyond `onStatus`. The only structural change is the result-delivery model: was async-return, now is a callback through `onStatus`.

## 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 Seamless you had | In the unified API | Session `workflow` |
| - | - | - | - |
| Your backend | No equivalent: Seamless never let you create it | Override `createPayment` | Default (`SDK_CHECKOUT`) |
| The SDK | Always | 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. Seamless mode theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
  import YunoSDK

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

  // 2. Trigger the payment from a single async call
  func pay(paymentSelected: PaymentMethodSelected) async {
      let params = SeamlessParams(
          checkoutSession: "session-from-backend",
          countryCode: "CO",
          language: "en",
          viewController: nil
      )

      let result = await Yuno.startPaymentSeamlessLite(
          with: params,
          paymentSelected: paymentSelected,
          showPaymentStatus: true
      )

      switch result.status {
      case .succeeded:      print("Success")
      case .reject:         print("Rejected")
      case .fail:           print("Failed")
      case .processing:     print("Processing")
      case .internalError:  print("Internal error")
      case .userCancelled:  print("User cancelled")
      @unknown default:     break
      }
  }
  ```

  ```swift After. Unified Transaction theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
  import SdkPayments

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

  // 2. Implement a minimal controller
  final class Checkout: SdkPayments.TransactionController {

      func onStatus(status: SdkPayments.TransactionStatus) {
          switch status.status {
          case "INTERNAL_ERROR":  print("Internal error")
          case "USER_CANCEL":     print("User cancelled")
          // Handle other backend statuses (e.g. SUCCEEDED, DECLINED, PENDING) as needed.
          default:                break
          }
      }

      // 3. Trigger the payment
      func pay(paymentSelected: SdkPayments.PaymentMethodSelected) {
          let config = SdkPayments.TransactionConfig(
              checkoutSession: "session-from-backend",
              countryCode: "CO",
              language: "en",
              controller: self,
              showStatusScreen: true,
              viewController: nil
          )

          SdkPayments.Transaction(config: config)
              .start(paymentSelected: paymentSelected)
      }
  }
  ```
</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

| Seamless | 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. |
| `SeamlessParams.checkoutSession`, `.countryCode`, `.language`, `.viewController` | The same fields on `SdkPayments.TransactionConfig` | Moved | Same values; `viewController` stays iOS-only and optional in SwiftUI. The config also takes the `controller` (see Controller). |
| `showPaymentStatus:` argument of `startPaymentSeamlessLite` | `SdkPayments.TransactionConfig.showStatusScreen` | Moved | See the note below. |

<Note>
  **The SDK result screen is off by default now.** Set `showStatusScreen: true` to keep it.
</Note>

### Controller

| Seamless | Unified | Change | What to do |
| - | - | - | - |
| *(no delegate)* | `SdkPayments.TransactionController` | New | Even the simplest case needs a controller instance: conform a class with just `onStatus` and pass it as `TransactionConfig.controller`. The SDK does not retain it: keep it alive for the whole transaction. |
| `Yuno.Result` returned by `await` | `onStatus(status:)` with `SdkPayments.TransactionStatus` | Moved | The result is callback-based now: you cannot `await` it inline, so if your code chained logic on the returned value or returned it to the caller, refactor it to react inside `onStatus`. 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. |

### Entry points

| Seamless | Unified | Change | What to do |
| - | - | - | - |
| `Yuno.startPaymentSeamlessLite(with:paymentSelected:showPaymentStatus:)`, both the `async` and the `callback:` overloads | `SdkPayments.Transaction(config:).start(paymentSelected:)` | Renamed | Build the config, then `start`. Nothing to `await` and no callback to pass: the outcome arrives in `onStatus`. You still pick the method and pass it. |
| `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

* [Get Started](/docs/yuno-sdk/get-started). The unified-API walkthrough; the new "Seamless equivalent" is now the default path.
* [`onStatus`](/docs/yuno-sdk/controllers/on-status). Controller that delivers the final status.
* [`TransactionConfig`](/docs/yuno-sdk/reference/objects-you-pass#transaction-config). Complete field reference.
* [Migration / Lite](/docs/yuno-sdk/migration/ios/payment/lite). Almost identical migration; Seamless and Lite collapse into the same default path in the unified API.


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