Transaction plus getPaymentMethodsViews(...) for the embedded list, with the controllers split in two: SdkPayments.TransactionController for the transaction lifecycle and SdkPayments.PaymentListController for list-specific events.
Before you start
- Replace
import YunoSDKwithimport SdkPayments. Your public API key and the checkout sessions your backend creates do not change (Before you begin). - Decide who creates the payment. The checkout session’s
workflowmust match that decision:
| Who creates the payment | In Full 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 |
A default-workflow session with no
createPayment override ends in INTERNAL_ERROR: the backend rejects the SDK’s payment creation. See createPayment.Side-by-side
import SwiftUI
import YunoSDK
// 1. Initialize once at app startup
Yuno.initialize(
apiKey: "your-public-api-key",
config: YunoConfig(appearance: customAppearance, saveCardEnabled: true)
)
// 2. Implement the Full delegate (combines payment + list events)
final class CheckoutModel: YunoPaymentFullDelegate, ObservableObject {
var checkoutSession: String = "session-from-backend"
var countryCode: String = "CO"
var language: String? = "en"
var viewController: UIViewController?
@Published var selectedPaymentMethod: PaymentMethodSelected?
// Payment events
func yunoPaymentResult(_ result: Yuno.Result) {
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
}
}
// Payment-list events
func yunoDidSelect(paymentMethod: PaymentMethodSelected) {
selectedPaymentMethod = paymentMethod
}
func yunoDidUnenrollSuccessfully(_ success: Bool) { /* refresh UI */ }
func yunoUpdatePaymentMethodsViewHeight(_ height: CGFloat) { /* relayout */ }
}
// 3. Embed the SDK's list and trigger payment
struct CheckoutView: View {
@StateObject var model = CheckoutModel()
@State var list: AnyView?
var body: some View {
VStack {
list
Button("Pay") {
Yuno.startPayment(showPaymentStatus: true)
}
.disabled(model.selectedPaymentMethod == nil)
}
.task {
list = AnyView(await Yuno.getPaymentMethodViewAsync(delegate: model))
}
}
}
import SwiftUI
import SdkPayments
// 1. Initialize once at app startup
SdkPayments.initialize(apiKey: "your-public-api-key")
// 2. Implement BOTH controllers on the same model (or split them)
final class CheckoutModel:
SdkPayments.TransactionController,
SdkPayments.PaymentListController,
ObservableObject {
@Published var selectedPaymentMethod: SdkPayments.PaymentMethodSelected?
// Transaction events
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
}
}
// Payment-list events
func onPaymentSelected(paymentSelected: SdkPayments.PaymentMethodSelected) {
selectedPaymentMethod = paymentSelected
}
func onUnenroll(success: Bool) { /* refresh UI */ }
func onHeightChange(newHeight: CGFloat) { /* relayout */ }
}
// 3. Build a Transaction, embed the list, trigger payment
struct CheckoutView: View {
@StateObject var model = CheckoutModel()
@State var transaction: SdkPayments.Transaction?
@State var list: AnyView?
var body: some View {
VStack {
list
Button("Pay") {
if let selected = model.selectedPaymentMethod {
transaction?.start(paymentSelected: selected)
}
}
.disabled(model.selectedPaymentMethod == nil)
}
.task {
let config = SdkPayments.TransactionConfig(
checkoutSession: "session-from-backend",
countryCode: "CO",
language: "en",
appearance: customAppearance,
controller: model,
showStatusScreen: true,
saveCardEnabled: true
)
let tx = SdkPayments.Transaction(config: config)
transaction = tx
let views = tx.getPaymentMethodsViews(
types: [.PAYMENT_METHOD_LIST],
controller: model
)
list = views[.PAYMENT_METHOD_LIST]
}
}
}
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
| Full | Unified | Change | What to do |
|---|---|---|---|
import YunoSDK | import SdkPayments | Renamed | |
Yuno.initialize(apiKey:config:) | SdkPayments.initialize(apiKey:) | Renamed | YunoConfig is gone: its fields move to SdkPayments.TransactionConfig (next rows). The callback: parameter is gone too; use the async overload if you need to wait. |
YunoConfig.appearance | SdkPayments.TransactionConfig.appearance | Moved | Pass it per transaction instead of once at startup. |
Yuno.Appearance | SdkPayments.Appearance | Renamed | Same initializer; drop the Yuno. prefix. |
YunoConfig.saveCardEnabled | SdkPayments.TransactionConfig.saveCardEnabled | Moved | Defaults to false. With true, the card form shows the save-card checkbox (payments only), unchecked. |
YunoConfig.keepLoader | (removed) | Removed | The SDK keeps its loader. Override showLoading only if you want your own (see Controller). |
YunoPaymentFullDelegate.checkoutSession, .countryCode, .language, .viewController | The same fields on SdkPayments.TransactionConfig | Moved | Delegate properties become config fields. viewController stays iOS-only and optional in SwiftUI. |
showPaymentStatus: argument of startPayment | SdkPayments.TransactionConfig.showStatusScreen | Moved | See the note below. |
The SDK result screen is off by default now. Set
showStatusScreen: true to keep it.Controller
| Full | Unified | Change | What to do |
|---|---|---|---|
YunoPaymentFullDelegate | SdkPayments.TransactionController + SdkPayments.PaymentListController | Renamed | One delegate becomes two controllers: Full mixed transaction events (yunoPaymentResult) and list events (yunoDidSelect and the rest), the unified API splits them. You can still conform the same class to both, as in the example above. Pass it as TransactionConfig.controller and as the controller of getPaymentMethodsViews. 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. |
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. |
YunoLoaderDelegate.onLoading(isLoading:) | showLoading(isLoading:) | Renamed | Optional. Full never invoked it. If you override it now, the SDK hides its own loader and reports the state to you. See showLoading. |
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. |
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. |
yunoDidSelect(paymentMethod:) | onPaymentSelected(paymentSelected:) | Renamed | Required. Store the SdkPayments.PaymentMethodSelected it gives you: start needs it (see Entry points). |
yunoDidUnenrollSuccessfully(_:) | onUnenroll(success:) | Renamed | Optional. Same Bool payload. |
yunoUpdatePaymentMethodsViewHeight(_:) | onHeightChange(newHeight:) | Renamed | Optional. |
Entry points
| Full | Unified | Change | What to do |
|---|---|---|---|
Yuno.getPaymentMethodViewAsync(delegate:) | transaction.getPaymentMethodsViews(types:controller:) | Renamed | It returned a single some View; the new call returns [SdkPayments.PaymentMethodType: AnyView]. Pass [.PAYMENT_METHOD_LIST] for the equivalent of Full and read views[.PAYMENT_METHOD_LIST]; the subscript returns nil for types you did not request. You can also request .APPLE_PAY() in the same call to get the wallet button. |
Yuno.getPaymentMethodViewAsync(delegate:) returning UIView | transaction.getPaymentMethodsViewsUIKit(types:controller:) | Renamed | Same dictionary shape as the SwiftUI call, with UIView values. |
Yuno.startPayment(showPaymentStatus:) | transaction.start(paymentSelected:) | Renamed | The SDK no longer remembers the selection: pass the SdkPayments.PaymentMethodSelected you stored from onPaymentSelected. showPaymentStatus moved to the config (see Initialization and config). |
Yuno.continuePayment() | (removed) | Removed | Delete the call: returning from createPayment resumes the flow (the SDK polls the status, runs 3DS if needed and calls onStatus). Set 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. |
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. Full unified-API walkthrough.
- Payment Methods List. The new
getPaymentMethodsViewsAPI. TransactionConfig. Complete field reference.- Migration / Lite. The simpler case (single pre-selected method).