Skip to main content
Primer Checkout iOS SDK is currently in beta (v3.0.0-beta.8). The API is subject to change before the stable release.
Primer Checkout is built entirely in SwiftUI, so it slots into any navigation pattern you already use. There are two integration shapes:
  • Modal flow — drop PrimerCheckout into a .sheet, .fullScreenCover, or NavigationStack destination and let the SDK render its prebuilt screens.
  • Inline embedding — hold a PrimerCheckoutSession as @StateObject, apply the .primerCheckoutSession(_:theme:onCompletion:) modifier, and place composable views such as PrimerCardForm and PrimerPaymentMethods directly in your own layout.
Both shapes deliver outcomes through a PrimerCheckoutState callback, so you drive navigation from the same .success / .dismissed / .failure cases regardless of how checkout is presented.
Primer Checkout requires iOS 15.0 or later — all checkout views and sessions are annotated @available(iOS 15.0, *), and PrimerCheckout and the session classes (PrimerCheckoutSession, PrimerCardFormSession, PrimerSelectionSession) are also @MainActor. Some SwiftUI navigation hosts shown below require a newer OS than the SDK floor: NavigationStack and .navigationDestination(for:) require iOS 16.0+, and the .navigationDestination(item:) overload requires iOS 17.0+. On an iOS 15 deployment target, present checkout with .sheet or .fullScreenCover instead.

Reading the completion state

Both SwiftUI shapes report their outcome through onCompletion with a PrimerCheckoutState. UIKit’s PrimerCheckoutPresenter uses PrimerCheckoutPresenterDelegate instead. The callback receives .failure once per failed attempt, and .success or .dismissed once the checkout ends. After .success or .dismissed, it delivers nothing more. For an inline session, a failure during initialization is the last callback. The callback never receives the lifecycle cases .initializing and .ready(clientSession:). For an inline session, read the lifecycle from PrimerCheckoutSession.phase and clientSession. Switch on the state to decide how navigation should react.
PrimerCheckoutState is an evolving enum. Always include a default case when switching on it so future cases compile without breaking your navigation logic.
PrimerCheckout is a self-contained View that renders the SDK’s default screens. Use it whenever you want the fastest integration and do not need to recompose the UI.

Sheet presentation

While a payment is processing, the customer cannot swipe the sheet away. Apple Pay and Stripe ACH show no processing screen, so the sheet is not locked while they run.

Pushing onto a NavigationStack

Use a NavigationStack when checkout is one step inside a longer flow and you want a back button rather than a modal. NavigationStack(path:) and .navigationDestination(for:) require iOS 16.0+; on an iOS 15 target, use the sheet presentation above.
On a .success, append a confirmation route and pass result.paymentId along — PaymentResult also exposes status, amount, currencyCode, and paymentMethodType for your receipt screen.

Inline embedding with PrimerCheckoutSession

To recompose the UI — for example, to place PrimerCardForm inside your own scroll view alongside an order summary — hold a PrimerCheckoutSession and wire it in with the .primerCheckoutSession(_:theme:onCompletion:) modifier. The modifier injects the session into the environment, so any Primer composable placed under it resolves automatically.
Hold the session with @StateObject so it survives view updates. The modifier bootstraps it on appear and tears it down on disappear.
The modifier wires session.cancel() to onDisappear, which also fires on transient disappearance (tab switch, push/pop, parent sheet re-present). The session resets to a restartable state and rebuilds itself when the view reappears — no extra handling required.

Embedding the payment-method list

PrimerPaymentMethods resolves the same session from the environment, so you can compose a full selection-plus-card layout under a single modifier.

Driving navigation from the completion state

Whether modal or inline, route on the same PrimerCheckoutState cases: dismiss on .dismissed, advance on .success, and leave checkout in place on a payment .failure while the SDK error screen is enabled (the default). An inline session that fails to initialize ends, so show your own error UI.
The .navigationDestination(item:) overload used above requires iOS 17.0+. On earlier targets, drive the same confirmation value through an isPresented-based .sheet or a .navigationDestination(isPresented:) binding instead.
For the inline shape, the same onCompletion closure on .primerCheckoutSession(_:theme:onCompletion:) drives the navigation in identical fashion — pop the embedding screen on .dismissed, push a confirmation on .success.
Do not dismiss checkout on a payment .failure while the SDK error screen is enabled (isErrorScreenEnabled in PrimerUIOptions, which defaults to true). The SDK shows the error inside checkout so the customer can retry or, where available, choose another payment method. Dismissing would discard that recoverable state. If you pass PrimerSettings(uiOptions: PrimerUIOptions(isErrorScreenEnabled: false)), the SDK shows no error UI and leaves the failure to you. Show your own error or dismiss checkout. An inline session that fails to initialize shows no SDK error, so handle that failure yourself.

See also

PrimerCheckoutSession

Own the inline session lifecycle and sub-sessions

PrimerCheckout

The prebuilt modal checkout view

PrimerCardForm

Compose the card form inline with slots

Handle payment result

React to checkout outcomes