Skip to main content
Primer Checkout iOS SDK is currently in beta (v3.0.0-beta.1). The API is subject to change before the stable release.
PrimerCheckoutPresenter is the UIKit entry point for the managed checkout. It presents the CheckoutComponents UI from a UIViewController and delivers results through a delegate, acting as a bridge between UIKit apps and the underlying SwiftUI implementation.
For pure SwiftUI apps, use PrimerCheckout directly instead of this class. PrimerCheckoutPresenter exists for view-controller based navigation and Objective-C interoperability.

Declaration

@available(iOS 15.0, *)
@MainActor
@objc public final class PrimerCheckoutPresenter: NSObject
The presenter is a @MainActor singleton: call its static methods from the main thread (the default for UIKit lifecycle callbacks). It is also exposed to Objective-C via @objc.

Properties

PropertyTypeDescription
sharedPrimerCheckoutPresenterThe shared singleton instance. Use it to assign the delegate. Exposed to Objective-C.
delegatePrimerCheckoutPresenterDelegate?The object that receives checkout result and lifecycle callbacks. Held weakly.
isAvailableBoolstatic. true when CheckoutComponents can be presented on the current OS version.
isPresentingBoolstatic. true while a checkout is being presented or is currently on screen.
@objc public static let shared = PrimerCheckoutPresenter()

public weak var delegate: PrimerCheckoutPresenterDelegate?

@objc public static var isAvailable: Bool
@objc public static var isPresenting: Bool
delegate is a weak reference. Retain the object you assign (for example the presenting view controller) for as long as checkout is on screen, otherwise callbacks will not fire.

Presenting checkout

presentCheckout has four overloads. They differ only in how much you configure and whether you supply the presenting view controller yourself. All overloads accept an optional trailing completion closure that runs once the checkout UI has finished presenting. None of these parameters have Swift defaults. The overloads that omit settings or theme apply the SDK’s current global PrimerSettings and a default PrimerCheckoutTheme() internally.

From an explicit view controller

@objc public static func presentCheckout(
    clientToken: String,
    from viewController: UIViewController,
    completion: (() -> Void)? = nil
)

public static func presentCheckout(
    clientToken: String,
    from viewController: UIViewController,
    primerSettings: PrimerSettings,
    completion: (() -> Void)? = nil
)

public static func presentCheckout(
    clientToken: String,
    from viewController: UIViewController,
    primerSettings: PrimerSettings,
    primerTheme: PrimerCheckoutTheme,
    completion: (() -> Void)? = nil
)

With automatic view controller detection

These overloads locate the top-most presenting view controller for you, which is convenient when you do not have a view controller reference at hand.
@objc public static func presentCheckout(
    clientToken: String,
    completion: (() -> Void)? = nil
)

public static func presentCheckout(
    clientToken: String,
    primerSettings: PrimerSettings,
    completion: (() -> Void)? = nil
)
If no presenting view controller can be found, the automatic overloads report a PrimerError through primerCheckoutPresenterDidFailWithError(_:). Assign the delegate before calling these methods.

Parameters

ParameterTypeDefaultDescription
clientTokenStringThe client token for the session. Generate it from your backend with the client session API.
viewControllerUIViewControllerThe view controller to present from. Omitted in the automatic-detection overloads.
primerSettingsPrimerSettingsConfiguration applied to this checkout session. Overloads that omit it use the SDK’s current global PrimerSettings. See PrimerSettings.
primerThemePrimerCheckoutThemeTheme configuration for the design tokens. Overloads that omit it use a default PrimerCheckoutTheme().
completion(() -> Void)?nilOptional closure invoked once the checkout UI has finished presenting.
The overloads that take primerSettings or primerTheme are not @objc compatible because of those Swift-only parameter types. From Objective-C, use the clientToken / clientToken:from: overloads, or configure settings globally via PrimerSettings.

Dismissing checkout

@objc public static func dismiss(
    animated: Bool = true,
    completion: (() -> Void)? = nil
)
ParameterTypeDefaultDescription
animatedBooltrueWhether to animate the dismissal.
completion(() -> Void)?nilOptional closure invoked after dismissal completes.
Calling dismiss triggers primerCheckoutPresenterDidDismiss() on the delegate. The checkout also dismisses itself automatically when a payment succeeds or fails.

PrimerCheckoutPresenterDelegate

@available(iOS 15.0, *)
public protocol PrimerCheckoutPresenterDelegate: AnyObject
Conform to this protocol to receive checkout results and lifecycle events. The result methods are required; the 3DS lifecycle methods are optional thanks to default implementations in a protocol extension.

Required methods

MethodDescription
primerCheckoutPresenterDidCompleteWithSuccess(_:)Called when payment is successful, with the PaymentResult.
primerCheckoutPresenterDidFailWithError(_:)Called when payment fails, with a PrimerError.
primerCheckoutPresenterDidDismiss()Called when checkout is dismissed without completion.
func primerCheckoutPresenterDidCompleteWithSuccess(_ result: PaymentResult)
func primerCheckoutPresenterDidFailWithError(_ error: PrimerError)
func primerCheckoutPresenterDidDismiss()

Optional 3DS lifecycle methods

Implement these only if you need to observe the 3-D Secure challenge lifecycle. Each has a default empty implementation, so you can omit any you do not need.
MethodDescription
primerCheckoutPresenterWillPresent3DSChallenge(_:)Called when a 3DS challenge is about to be presented, with the PrimerPaymentMethodTokenData requiring 3DS.
primerCheckoutPresenterDidDismiss3DSChallenge()Called when the 3DS challenge UI is dismissed.
primerCheckoutPresenterDidComplete3DSChallenge(success:resumeToken:error:)Called when the 3DS challenge completes, indicating success, the resume token (when successful), or the error (when failed).
func primerCheckoutPresenterWillPresent3DSChallenge(
    _ paymentMethodTokenData: PrimerPaymentMethodTokenData
)
func primerCheckoutPresenterDidDismiss3DSChallenge()
func primerCheckoutPresenterDidComplete3DSChallenge(
    success: Bool,
    resumeToken: String?,
    error: Error?
)

PaymentResult

The success callback delivers a PaymentResult value.
public struct PaymentResult: Sendable, Equatable {
    public let paymentId: String
    public let status: PaymentStatus
    public let token: String?
    public let redirectUrl: String?
    public let errorMessage: String?
    public let amount: Int?
    public let currencyCode: String?
    public let paymentMethodType: String?
}
PropertyTypeDescription
paymentIdStringThe unique identifier of the payment.
statusPaymentStatusThe final status of the payment.
tokenString?The payment token, when available.
redirectUrlString?A redirect URL, when the flow involved one.
errorMessageString?A human-readable error message, when available.
amountInt?The payment amount in minor units.
currencyCodeString?The ISO 4217 currency code.
paymentMethodTypeString?The payment method type used for the payment.

PaymentStatus

public enum PaymentStatus: Sendable {
    case pending
    case success
    case failed
}
CaseDescription
pendingThe payment is still being processed.
successThe payment completed successfully.
failedThe payment failed.
When switching on PaymentStatus, always include a default case so your code stays forward-compatible with future status values.

UIKit usage example

import PrimerSDK
import UIKit

final class CheckoutViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        PrimerCheckoutPresenter.shared.delegate = self
    }

    @IBAction func payButtonTapped(_ sender: UIButton) {
        PrimerCheckoutPresenter.presentCheckout(
            clientToken: clientToken,
            from: self
        )
    }
}

extension CheckoutViewController: PrimerCheckoutPresenterDelegate {
    func primerCheckoutPresenterDidCompleteWithSuccess(_ result: PaymentResult) {
        switch result.status {
        case .success:
            showReceipt(paymentId: result.paymentId)
        case .pending:
            showPendingState(paymentId: result.paymentId)
        case .failed:
            showError(message: result.errorMessage)
        default:
            break
        }
    }

    func primerCheckoutPresenterDidFailWithError(_ error: PrimerError) {
        showError(message: error.errorDescription)
    }

    func primerCheckoutPresenterDidDismiss() {
        // The shopper closed checkout without completing a payment.
    }
}
To apply custom settings or theming, use the richer overload:
PrimerCheckoutPresenter.presentCheckout(
    clientToken: clientToken,
    from: self,
    primerSettings: settings,
    primerTheme: theme
)
PrimerCheckoutPresenter.shared.delegate is weak. Keep the conforming object (here, the view controller) alive for the duration of checkout so the callbacks are delivered.

See also

PrimerCheckout

The SwiftUI view for embedding checkout directly in a SwiftUI hierarchy.

PrimerCheckoutState

The state model that drives the managed checkout flow.

PrimerError

The error type delivered to the failure callback.

UIKit integration

A guide to integrating the managed checkout in UIKit apps.