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.
PrimerCheckoutSession is the owner of a CheckoutComponents session. You hold it (typically as a @StateObject) and wire it into your SwiftUI view hierarchy with the .primerCheckoutSession(_:onCompletion:) modifier. The session builds the SDK, runs client-token initialization, creates the checkout scope, and bridges per-method scopes into observable session objects that the composable views (such as PrimerCardForm and PrimerPaymentMethods) consume from the environment. The same session powers both the managed modal PrimerCheckout and fully inline embedding: any Primer composable view placed under the modifier resolves its session from the environment. Overlay screens for 3DS challenges and redirect flows are rendered automatically while the session is .ready.
This is the iOS analog of the Android PrimerCheckoutHost. Where Android wraps your layout in a composable host, iOS wires the session into the environment with a view modifier — child composable views read their per-feature session from EnvironmentValues.

Declaration

@available(iOS 15.0, *)
@MainActor
public final class PrimerCheckoutSession: ObservableObject

Initializer

public init(
    clientToken: String,
    settings: PrimerSettings = PrimerSettings(),
    theme: PrimerCheckoutTheme = PrimerCheckoutTheme(),
    idempotencyKey: @escaping @Sendable () -> String? = { nil }
)
ParameterTypeDefaultDescription
clientTokenStringRequiredThe client token from your POST /client-session call. See Client session.
settingsPrimerSettingsPrimerSettings()SDK configuration applied to this session.
themePrimerCheckoutThemePrimerCheckoutTheme()Design tokens applied to all SDK components within the session.
idempotencyKey@Sendable () -> String?{ nil }Declarative idempotency-key provider, invoked once per payment attempt just before the SDK creates the payment. Return nil to opt out. Ignored when onBeforePaymentCreate is set.

Phase

The lifecycle phase of the session. Terminal outcomes (success, failure, dismissed) are not delivered here — they are delivered through the modifier’s onCompletion.
public enum Phase: Equatable {
    case initializing
    case ready
}
CaseDescription
initializingThe session is building the SDK and running client-token initialization. Child sessions (cardForm, selection) are nil.
readyInitialization completed. Child sessions resolve and the composable views render.

Published properties

PropertyTypeDescription
phasePhaseThe current lifecycle phase. Declared @Published public private(set) — observe it, but only the session mutates it.

Properties

PropertyTypeDescription
onBeforePaymentCreateBeforePaymentCreateHandler?Called before a payment is created. Use the decision handler to provide an idempotency key or abort payment creation. Mutations are forwarded to the checkout scope immediately, so assigning after the session reaches .ready still takes effect for the next payment attempt.
idempotencyKey@Sendable () -> String?Declarative idempotency-key provider, invoked once per payment attempt just before the SDK creates the payment. Return nil (default) to opt out. Ignored when onBeforePaymentCreate is set. Mutations are forwarded to the checkout scope immediately, so post-.ready assignment still applies.
cardFormPrimerCardFormSession?The card-form sub-session, lazily created and cached. Non-nil only once phase == .ready.
selectionPrimerSelectionSession?The payment-method-selection sub-session, lazily created and cached. Non-nil only once phase == .ready.
onBeforePaymentCreate uses the BeforePaymentCreateHandler type:
public typealias BeforePaymentCreateHandler = @Sendable (
    _ data: PrimerCheckoutPaymentMethodData,
    _ decisionHandler: @escaping (PrimerPaymentCreationDecision) -> Void
) -> Void
If you set onBeforePaymentCreate, the declarative idempotencyKey provider is ignored — use the decision handler to supply the key instead.

Methods

MethodDescription
start() asyncBuilds the SDK and drives the session to .ready. Idempotent — repeated calls are ignored once initialization has started. The modifier calls this for you on appear.
refresh() asyncRe-fetches configuration and payment methods from the backend and returns the session to .ready. No-op unless the session has finished initializing; concurrent calls are ignored. Failures are delivered via onCompletion.
cancel()Tears the session down: dismisses the checkout scope, clears resources, drops cached sub-sessions, and resets to a restartable state. Idempotent. The modifier wires this to onDisappear.
You normally never call start() or cancel() yourself — the .primerCheckoutSession modifier handles the lifecycle. Call refresh() when you need to reload after a client-session update (for example, an amount or currency change).

View modifier

The View.primerCheckoutSession(_:onCompletion:) modifier wires a PrimerCheckoutSession into the SwiftUI environment, bootstraps it on appear, and tears it down on disappear. Apply it once around any Primer composable views — whether presented modally via PrimerCheckout or embedded inline in your own layout.
@available(iOS 15.0, *)
public extension View {
    func primerCheckoutSession(
        _ session: PrimerCheckoutSession,
        onCompletion: ((PrimerCheckoutState) -> Void)? = nil
    ) -> some View
}
ParameterTypeDefaultDescription
sessionPrimerCheckoutSessionRequiredThe session injected into the environment for child composable views to resolve.
onCompletion((PrimerCheckoutState) -> Void)?nilReceives the terminal outcome exactly once. See PrimerCheckoutState.

What the modifier provides

  1. Environment injection — exposes the PrimerCheckoutSession, the derived PrimerCardFormSession, and the PrimerSelectionSession through EnvironmentValues, so child views like PrimerCardForm and PrimerPaymentMethods resolve their per-feature session automatically.
  2. Lifecycle bootstrapping — calls start() on appear and cancel() on disappear.
  3. Overlay management — renders overlays for 3DS challenges and redirect flows automatically once the session is .ready.
Without the .primerCheckoutSession modifier above them in the hierarchy, composable views such as PrimerCardForm and PrimerPaymentMethods cannot resolve a session and will not function.

Usage

Hold the session as a @StateObject, place the composable views in a ScrollView, and attach the modifier with your completion handler.
import SwiftUI
import PrimerSDK

@available(iOS 15.0, *)
struct CheckoutView: View {
    @StateObject private var session: PrimerCheckoutSession

    init(clientToken: String) {
        _session = StateObject(
            wrappedValue: PrimerCheckoutSession(clientToken: clientToken)
        )
    }

    var body: some View {
        ScrollView {
            VStack(spacing: 24) {
                PrimerCardForm()
                PrimerPaymentMethods()
            }
            .padding()
        }
        .primerCheckoutSession(session) { state in
            switch state {
            case .success(let data):
                print("Payment complete: \(data)")
            case .failure(let error):
                print("Payment failed: \(error)")
            case .dismissed:
                print("Checkout dismissed")
            default:
                break
            }
        }
    }
}
The child composable views resolve their per-feature session from the environment — you do not pass a session into them. Behind the scenes the modifier injects PrimerCardFormSession and PrimerSelectionSession, which PrimerCardForm and PrimerPaymentMethods bind to once the session reaches .ready.

Supplying an idempotency key

Provide the declarative idempotencyKey provider at construction, or assign onBeforePaymentCreate for full control over the payment-creation decision. Either may be assigned after .ready — the change applies to the next payment attempt.
let session = PrimerCheckoutSession(
    clientToken: token,
    idempotencyKey: { UUID().uuidString }
)

See also

PrimerCheckout

The managed modal entry point powered by the same session.

PrimerCardForm

Composable card form that resolves its session from the environment.

PrimerPaymentMethods

Composable payment-method selection list for inline layouts.

PrimerCheckoutState

The terminal outcome delivered to onCompletion.