> ## Documentation Index
> Fetch the complete documentation index at: https://primer.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# PrimerCheckout

> SwiftUI managed-modal checkout view that renders Primer’s default screens

<Warning>
  Primer Checkout iOS SDK is currently in **beta** (v3.0.0-beta.1).
  The API is subject to change before the stable release.
</Warning>

`PrimerCheckout` is the prebuilt, fully managed SwiftUI flow. Drop it into your view hierarchy with a client token and it renders Primer's default screens end to end — splash, payment method selection, card form, processing, and the success and error results — including 3DS and redirect handling.

This is the fastest way to integrate. You do not compose any screens or wire up sessions yourself; the view manages its own lifecycle and reports the outcome through `onCompletion`.

<Info>
  `PrimerCheckout` renders the SDK's default screens and does not expose the composable views or their `@ViewBuilder` slots. For full UI customization, embed views such as [`PrimerCardForm`](/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/primer-card-form) and [`PrimerPaymentMethods`](/docs/sdk/ios-checkout/v3.0.0-beta/api/payment-methods/primer-payment-methods) in your own layout and wire them up with [`PrimerCheckoutSession`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-session).
</Info>

## Declaration

```swift theme={"dark"}
@available(iOS 15.0, *)
@MainActor
public struct PrimerCheckout: View
```

## Initializer

```swift theme={"dark"}
public init(
  clientToken: String,
  primerSettings: PrimerSettings = PrimerSettings(),
  primerTheme: PrimerCheckoutTheme = PrimerCheckoutTheme(),
  onCompletion: ((PrimerCheckoutState) -> Void)? = nil
)
```

### Parameters

| Parameter        | Type                                                                            | Default                 | Description                                                                                                                                                                                               |
| ---------------- | ------------------------------------------------------------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `clientToken`    | `String`                                                                        | Required                | The client token obtained from your backend. See [Client session](/docs/checkout/client-session).                                                                                                              |
| `primerSettings` | [`PrimerSettings`](/docs/sdk/ios-checkout/v3.0.0-beta/api/common/primer-settings)    | `PrimerSettings()`      | Configuration settings including payment options and UI preferences.                                                                                                                                      |
| `primerTheme`    | [`PrimerCheckoutTheme`](/docs/sdk/ios-checkout/v3.0.0-beta/api/theming/primer-theme) | `PrimerCheckoutTheme()` | Theme configuration for design tokens applied across all default screens.                                                                                                                                 |
| `onCompletion`   | `((PrimerCheckoutState) -> Void)?`                                              | `nil`                   | Optional completion callback invoked when checkout completes with the final state (success, failure, or dismissed). See [`PrimerCheckoutState`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-state). |

<Note>
  `PrimerCheckout` requires iOS 15.0 or later and must be used on the main actor, like any SwiftUI `View`.
</Note>

## Usage

### Minimal

Present the managed flow with just a client token. All other parameters use their defaults.

```swift theme={"dark"}
import SwiftUI
import PrimerSDK

struct CheckoutView: View {
  let clientToken: String

  var body: some View {
    PrimerCheckout(clientToken: clientToken)
  }
}
```

### With settings and theme

Customize payment options and design tokens by passing `primerSettings` and `primerTheme`.

```swift theme={"dark"}
import SwiftUI
import PrimerSDK

struct CheckoutView: View {
  let clientToken: String

  var body: some View {
    PrimerCheckout(
      clientToken: clientToken,
      primerSettings: PrimerSettings(),
      primerTheme: PrimerCheckoutTheme()
    )
  }
}
```

### Handling the result

Pass an `onCompletion` closure and switch over the terminal [`PrimerCheckoutState`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-state) to react to the outcome.

```swift theme={"dark"}
import SwiftUI
import PrimerSDK

struct CheckoutView: View {
  let clientToken: String
  @Environment(\.dismiss) private var dismiss

  var body: some View {
    PrimerCheckout(clientToken: clientToken) { state in
      switch state {
      case let .success(result):
        print("Payment succeeded: \(result.paymentId)")
        dismiss()
      case let .failure(error):
        print("Payment failed: \(error.localizedDescription)")
      case .dismissed:
        dismiss()
      default:
        // .initializing and .ready are lifecycle states and are
        // never delivered to onCompletion.
        break
      }
    }
  }
}
```

<Tip>
  See [Handle the payment result](/docs/sdk/ios-checkout/v3.0.0-beta/guides/handle-payment-result) for a full walkthrough of consuming each `PrimerCheckoutState` case.
</Tip>

## Presenting modally

`PrimerCheckout` is an ordinary SwiftUI `View`, so present it however your navigation pattern prefers — for example, in a `.sheet`.

```swift theme={"dark"}
import SwiftUI
import PrimerSDK

struct StorefrontView: View {
  @State private var isCheckoutPresented = false
  let clientToken: String

  var body: some View {
    Button("Pay") { isCheckoutPresented = true }
      .sheet(isPresented: $isCheckoutPresented) {
        PrimerCheckout(clientToken: clientToken) { state in
          if case .dismissed = state { isCheckoutPresented = false }
          if case .success = state { isCheckoutPresented = false }
        }
      }
  }
}
```

## Customizing the UI

`PrimerCheckout` does not accept screen slots. When you need to control layout, styling, or which fields appear, build your own UI from the composable views and drive them with a session instead.

| Goal                                 | Use                                                                                                                                                                                                                                                                          |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Fastest integration, default screens | `PrimerCheckout` (this page)                                                                                                                                                                                                                                                 |
| Custom SwiftUI layout and slots      | [`PrimerCheckoutSession`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-session) + [`PrimerCardForm`](/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/primer-card-form) / [`PrimerPaymentMethods`](/docs/sdk/ios-checkout/v3.0.0-beta/api/payment-methods/primer-payment-methods) |
| UIKit apps                           | [`PrimerCheckoutPresenter`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-presenter)                                                                                                                                                                                     |

For the composable approach, create a `PrimerCheckoutSession` as a `@StateObject`, place the composable views in your layout, and attach the `.primerCheckoutSession(_:onCompletion:)` modifier. The modifier injects the session that those views resolve from the environment.

```swift theme={"dark"}
import SwiftUI
import PrimerSDK

struct CustomCheckoutView: View {
  @StateObject private var session: PrimerCheckoutSession

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

  var body: some View {
    ScrollView {
      PrimerPaymentMethods()
      PrimerCardForm()
    }
    .primerCheckoutSession(session) { state in
      handle(state)
    }
  }

  private func handle(_ state: PrimerCheckoutState) {
    // React to the terminal state.
  }
}
```

## See also

<CardGroup cols={2}>
  <Card title="PrimerCheckoutSession" icon="layer-group" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-session">
    Compose custom UI from the SwiftUI views.
  </Card>

  <Card title="PrimerCheckoutPresenter" icon="swift" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-presenter">
    Present the managed flow from UIKit.
  </Card>

  <Card title="PrimerCheckoutState" icon="diagram-project" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-state">
    The terminal states delivered to onCompletion.
  </Card>

  <Card title="PrimerCheckoutTheme" icon="palette" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/theming/primer-theme">
    Style the default screens with design tokens.
  </Card>
</CardGroup>
