Advanced Features iOS SDK
Advanced configuration and custom integrations for iOS.
Alternative Mounting Options
The basic flow uses Yuno.startPayment() which handles the full payment flow automatically. For more control, use these alternatives:
Custom Payment Method Selection (startPaymentLite)
startPaymentLite)Select which payment method to display. Your delegate must implement YunoPaymentFullDelegate with required properties:
class PaymentViewController: UIViewController, YunoPaymentFullDelegate {
var checkoutSession: String { return _checkoutSession }
var countryCode: String { "US" }
var language: String? { "en" }
var viewController: UIViewController? { self }
private var _checkoutSession: String = ""
func setupPayment() async {
// 1. Create session
let session = await createCheckoutSession()
_checkoutSession = session.checkoutSession
// 2. Fetch available methods
let methods = await fetchPaymentMethods(sessionId: checkoutSession)
// 3. Display in your UI, then start payment with selected method
Yuno.startPaymentLite(
paymentMethodType: selectedMethod, // "CARD", "PIX", etc.
vaultedToken: nil, // or saved token
delegate: self
)
}
}Simplified Flow (startPaymentSeamlessLite)
startPaymentSeamlessLite)Similar to Lite but with automatic payment creation:
Yuno.startPaymentSeamlessLite(
paymentMethodType: "CARD",
vaultedToken: nil,
delegate: self
)Enrollment (Save Cards)
Save During Payment
Your delegate provides the session info via properties:
class PaymentViewController: UIViewController, YunoPaymentFullDelegate {
var checkoutSession: String { _checkoutSession }
var countryCode: String { "US" }
var language: String? { "en" }
var viewController: UIViewController? { self }
private var _checkoutSession: String = ""
func setupPayment() async {
let session = await createCheckoutSession()
_checkoutSession = session.checkoutSession
// Start payment - SDK will show save card checkbox automatically
Yuno.startPayment()
}
// In delegate:
func yunoCreatePayment(with token: String, information: [String: Any]) {
Task {
await createPayment(
token: token,
vaultOnSuccess: true // Save after successful payment
)
Yuno.continuePayment(showPaymentStatus: true)
}
}
}Separate Enrollment
class EnrollmentViewController: UIViewController, YunoEnrollmentDelegate {
var customerSession: String { _customerSession }
var countryCode: String { "US" }
var language: String? { "en" }
var viewController: UIViewController? { self }
private var _customerSession: String = ""
func setupEnrollment() async {
// Create customer session on backend
let session = await createCustomerSession(customerId: "cus_123")
_customerSession = session.id
// Start enrollment - SDK reads session from delegate
Yuno.enrollPayment(delegate: self)
}
func yunoEnrollmentStatus(status: Yuno.EnrollmentStatus, vaultedToken: String?) {
if status == .successful, let token = vaultedToken {
print("Card saved:", token)
}
}
func yunoDidSelect(enrollmentMethod: EnrollmentMethodSelected) {
print("Selected enrollment method:", enrollmentMethod)
}
}Vaulted Token Payments
Use saved cards by providing the vaulted token to startPaymentLite:
class PaymentViewController: UIViewController, YunoPaymentFullDelegate {
var checkoutSession: String { _checkoutSession }
var countryCode: String { "US" }
var language: String? { "en" }
var viewController: UIViewController? { self }
private var _checkoutSession: String = ""
func payWithSavedCard(vaultedToken: String) {
Yuno.startPaymentLite(
paymentMethodType: "CARD",
vaultedToken: vaultedToken,
delegate: self
)
}
}Custom UI (Headless Integration)
Build completely custom payment forms with full UI control when you need complete control over every UI element, highly custom checkout experiences, or have development resources for custom UI.
import YunoSDK
class CustomPaymentVC: UIViewController {
func processWithCustomUI() async {
// 1. Initialize headless client
let apiClient = Yuno.apiClientPayment(
countryCode: "US",
checkoutSession: "session_id"
)
// 2. Collect card data in your custom UI
let cardData = CardData(
number: "4111111111111111",
expirationMonth: 12,
expirationYear: 25,
securityCode: "123",
holderName: "John Doe",
type: .credit
)
// 3. Generate token
do {
let result = try await apiClient.generateToken(data: TokenCollectedData(
checkoutSession: "session_id",
paymentMethod: CollectedData(
type: "CARD",
card: cardData
)
))
// 4. Create payment with token
await createPayment(token: result.token)
// 5. Handle continuation if needed
if apiClient.shouldContinue {
try await apiClient.continuePayment()
}
} catch {
print("Error: \(error)")
}
}
}With Vaulted Token
let result = try await apiClient.generateToken(data: TokenCollectedData(
checkoutSession: "session_id",
paymentMethod: CollectedData(
type: "CARD",
vaultedToken: "saved_token_id",
card: CardData(securityCode: "123")
)
))Render Mode Integration
Display payment form within your custom view.
class PaymentViewController: UIViewController, YunoPaymentRenderFlowProtocol {
func startRenderMode() async {
let session = try await createCheckoutSession()
let config = YunoConfig(
checkoutSession: session.id,
countryCode: "US"
)
Yuno.startPaymentRenderFlow(with: config, delegate: self)
}
// SDK provides view to embed
func formView() -> UIView? {
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 350, height: 500))
containerView.backgroundColor = .systemBackground
return containerView
}
// Handle form submission
func submitForm() async {
// Customer submitted payment form
}
// Handle result
func yunoPaymentResult(_ result: PaymentResult) {
if result.status == .succeeded {
navigateToSuccess()
}
}
}SwiftUI:
struct RenderModeView: View, YunoPaymentRenderFlowProtocol {
@State private var paymentView: UIView?
var body: some View {
if let view = paymentView {
PaymentViewWrapper(view: view)
.frame(height: 500)
}
}
func startPayment() async {
let config = YunoConfig(checkoutSession: "session_id", countryCode: "US")
await Yuno.startPaymentRenderFlow(with: config, delegate: self)
}
func formView() -> UIView? {
let view = UIView()
DispatchQueue.main.async {
paymentView = view
}
return view
}
}
struct PaymentViewWrapper: UIViewRepresentable {
let view: UIView
func makeUIView(context: Context) -> UIView { view }
func updateUIView(_ uiView: UIView, context: Context) {}
}Styling & Appearance
Customize SDK appearance with Yuno.Appearance:
import YunoSDK
func configureAppearance() {
var appearance = Yuno.Appearance()
// Colors
appearance.primaryColor = UIColor.systemBlue
appearance.backgroundColor = UIColor.systemBackground
appearance.textColor = UIColor.label
appearance.errorColor = UIColor.systemRed
// Typography
appearance.fontFamily = "SF Pro Display"
appearance.fontSize = 16
// Corner radius
appearance.cornerRadius = 12
// Apply
Yuno.setAppearance(appearance)
}Swift 6 Concurrency
Handle concurrency warnings with proper annotations:
@MainActor
class PaymentViewController: UIViewController, YunoPaymentFullDelegate {
var checkoutSession: String { _checkoutSession }
var countryCode: String { "US" }
var language: String? { "en" }
var viewController: UIViewController? { self }
private var _checkoutSession: String = ""
// Safe to call from any thread
nonisolated func startPayment() {
Task { @MainActor in
Yuno.startPayment()
}
}
// UI updates on main thread
@MainActor
func yunoPaymentResult(_ result: PaymentResult) {
updateUI(result)
}
}Non-isolated delegate:
extension PaymentViewController {
nonisolated func yunoPaymentResult(_ result: PaymentResult) {
MainActor.assumeIsolated {
// UI updates here
self.showResult(result)
}
}
}ClearSale Integration
Enable fraud prevention:
Install ClearSale SDK:
pod 'ClearSaleSDK'Initialize:
import ClearSale
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Initialize ClearSale
ClearSale.setup(apiKey: "your-clearsale-key")
// Initialize Yuno
Yuno.initialize(apiKey: "your-public-key")
return true
}ClearSale data is automatically collected and sent with payments.
Custom Configuration
Card Flow Types
Configure card input flow during Yuno initialization:
// In AppDelegate or App struct
Yuno.initialize(
apiKey: "your-public-key",
cardFlow: .oneStep // or .stepByStep
)Hide Cardholder Name
Configure cardholder name visibility:
// Set globally
Yuno.hideCardholderName = trueShow/Hide Status Screen
Control payment status screen in continuePayment():
func yunoCreatePayment(with token: String, information: [String: Any]) {
Task {
await createPayment(token: token)
Yuno.continuePayment(showPaymentStatus: false) // Handle result yourself
}
}Error Handling
func yunoPaymentResult(_ result: PaymentResult) {
switch result.status {
case .succeeded:
handleSuccess(result)
case .failed:
handleFailure(result.error)
case .pending:
handlePending(result)
case .rejected:
handleRejection(result)
}
}
func handleFailure(_ error: YunoError?) {
guard let error = error else { return }
switch error.code {
case "SESSION_EXPIRED":
// Recreate session
Task { await createNewSession() }
case "INVALID_CARD":
showAlert("Please check your card details")
case "INSUFFICIENT_FUNDS":
showAlert("Insufficient funds")
case "NETWORK_ERROR":
showAlert("Connection error. Please try again.")
default:
showAlert("Payment failed: \(error.message)")
}
}Webhooks
Verify payment status on backend:
// Backend receives webhook
POST /webhooks/yuno
{
"type": "payment.succeeded",
"data": {
"payment_id": "pay_123",
"status": "SUCCEEDED",
"amount": 2500
}
}Testing
Test Mode
// Use test key
Yuno.initialize(apiKey: "pk_test_your_key")Debug Logging
// Enable logs in development
#if DEBUG
Yuno.setLogLevel(.verbose)
#endifPerformance
Preload SDK
// Preload in background
Task(priority: .background) {
_ = Yuno.self
}Lazy Loading
// Load only when needed
lazy var yuno: Yuno = {
Yuno.initialize(apiKey: "pk_test_key")
return Yuno.shared
}()Updated about 18 hours ago