> ## 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.

# PrimerCheckoutState

> Checkout lifecycle and outcome states, with the payment result model

<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>

`PrimerCheckoutState` is a public, `Equatable` enum that represents the current state of the checkout flow. It captures both the **lifecycle** of the session (initializing, ready) and its **terminal outcome** (success, failure, dismissed).

Your `onCompletion` closure on [`PrimerCheckout`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout) or on the `.primerCheckoutSession(_:onCompletion:)` modifier fires exactly once per session, and only with a **terminal** state: `.success`, `.failure`, or `.dismissed`. The lifecycle states `.initializing` and `.ready` are part of the enum's definition but are never delivered to `onCompletion`; they describe internal progress the SDK drives on your behalf.

<Info>
  On iOS, a single `PrimerCheckoutState` enum covers what the Android SDK splits across `PrimerCheckoutState` (lifecycle) and `PrimerCheckoutEvent` (outcomes). The `.initializing` and `.ready` cases mirror the lifecycle; `.success`, `.failure`, and `.dismissed` mirror the outcome events delivered to `onCompletion`.
</Info>

## Definition

```swift theme={"dark"}
@available(iOS 15.0, *)
public enum PrimerCheckoutState: Equatable {
    case initializing
    case ready(totalAmount: Int, currencyCode: String)
    case success(PaymentResult)
    case dismissed
    case failure(PrimerError)
}
```

## States

| State           | Associated values                                                      | Description                                                                                                                                    |
| --------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `.initializing` | —                                                                      | Initial state while loading configuration and payment methods. The SDK is fetching the client session and preparing available payment methods. |
| `.ready`        | `totalAmount: Int`, `currencyCode: String`                             | Checkout is fully initialized and payment methods are loaded. The session is ready for payment.                                                |
| `.success`      | [`PaymentResult`](#paymentresult)                                      | Payment completed successfully. Carries the full payment result with payment ID, status, and other details.                                    |
| `.dismissed`    | —                                                                      | Terminal state. Checkout was dismissed by user action or programmatically without completing a payment.                                        |
| `.failure`      | [`PrimerError`](/docs/sdk/ios-checkout/v3.0.0-beta/api/common/primer-error) | Payment or checkout failed. Carries the specific error with diagnostics information for debugging.                                             |

### `.ready` associated values

| Parameter      | Type     | Description                                                                       |
| -------------- | -------- | --------------------------------------------------------------------------------- |
| `totalAmount`  | `Int`    | The total payment amount in minor units (e.g., cents for USD — `1000` = \$10.00). |
| `currencyCode` | `String` | The ISO 4217 currency code (e.g., `"USD"`, `"EUR"`, `"GBP"`).                     |

## Lifecycle

A checkout session progresses from the lifecycle states to one of three mutually exclusive terminal outcomes:

```
initializing → ready → success | failure | dismissed
```

`.success`, `.failure`, and `.dismissed` are parallel terminal branches — a session ends in exactly one of them.

| Transition                 | When                                                                                        |
| -------------------------- | ------------------------------------------------------------------------------------------- |
| `.initializing` → `.ready` | Configuration and payment methods have loaded.                                              |
| `.ready` → `.success`      | Payment is confirmed by the processor (automatic payment handling).                         |
| `.ready` → `.failure`      | A payment error or SDK error occurs.                                                        |
| `→ .dismissed`             | The user closes checkout, or you dismiss it programmatically, without completing a payment. |

<Note>
  `.success`, `.failure`, and `.dismissed` are terminal. The `onCompletion` closure receives exactly one of them per session. The lifecycle states `.initializing` and `.ready` are never passed to `onCompletion`.
</Note>

## Handling completion

Pass an `onCompletion` closure when you present checkout. The closure fires once, with one of the terminal states (`.success`, `.failure`, or `.dismissed`).

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

struct CheckoutView: View {
    @StateObject private var session = PrimerCheckoutSession(clientToken: clientToken)

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

    private func handle(_ state: PrimerCheckoutState) {
        switch state {
        case let .success(result):
            print("Payment \(result.paymentId) succeeded")
        case let .failure(error):
            print("Checkout failed: \(error.localizedDescription)")
        case .dismissed:
            print("Checkout dismissed")
        default:
            // .initializing and .ready are lifecycle states and are
            // never delivered here.
            break
        }
    }
}
```

<Tip>
  `onCompletion` only delivers terminal states, but a `switch` on `PrimerCheckoutState` must still be exhaustive. Cover the lifecycle cases with a `default:` (or `@unknown default:`) so future state additions don't break compilation.
</Tip>

## PaymentResult

`PaymentResult` is the value carried by `.success`. It is a public, `Sendable`, `Equatable` struct describing the completed payment.

```swift theme={"dark"}
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?
}
```

| Property            | Type                              | Description                                                                       |
| ------------------- | --------------------------------- | --------------------------------------------------------------------------------- |
| `paymentId`         | `String`                          | Unique payment identifier assigned by Primer.                                     |
| `status`            | [`PaymentStatus`](#paymentstatus) | The final status of the payment.                                                  |
| `token`             | `String?`                         | The payment method token, when available.                                         |
| `redirectUrl`       | `String?`                         | A redirect URL associated with the payment, when applicable.                      |
| `errorMessage`      | `String?`                         | A human-readable error message, when the payment did not complete cleanly.        |
| `amount`            | `Int?`                            | The payment amount in minor units, when available.                                |
| `currencyCode`      | `String?`                         | The ISO 4217 currency code, when available.                                       |
| `paymentMethodType` | `String?`                         | The payment method type identifier used for the payment (e.g., `"PAYMENT_CARD"`). |

## PaymentStatus

`PaymentStatus` is a public, `Sendable` enum describing the final status of a payment.

```swift theme={"dark"}
public enum PaymentStatus: Sendable {
    case pending
    case success
    case failed
}
```

| Case       | Description                                                             |
| ---------- | ----------------------------------------------------------------------- |
| `.pending` | The payment is pending and awaiting further processing or confirmation. |
| `.success` | The payment completed successfully.                                     |
| `.failed`  | The payment failed.                                                     |

<Note>
  Always include a `default:` (or `@unknown default:`) case when switching on `PaymentStatus` to handle future additions.
</Note>

## Handling the result

Use the `.success` payload to read the payment details and route your UI:

```swift theme={"dark"}
private func handleCompletion(_ state: PrimerCheckoutState) {
    switch state {
    case let .success(result):
        switch result.status {
        case .success:
            showReceipt(paymentId: result.paymentId)
        case .pending:
            showPendingScreen(paymentId: result.paymentId)
        case .failed:
            showErrorScreen(message: result.errorMessage)
        @unknown default:
            break
        }
    case let .failure(error):
        showErrorScreen(message: error.localizedDescription)
    case .dismissed:
        dismiss()
    default:
        // .initializing and .ready are lifecycle states and are
        // never delivered to onCompletion.
        break
    }
}
```

For a full integration walkthrough, including manual payment handling, see [Handle payment result](/docs/sdk/ios-checkout/v3.0.0-beta/guides/handle-payment-result).

## See also

<CardGroup cols={2}>
  <Card title="PrimerCheckout" icon="square-check" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout">
    Present checkout and receive the final state through `onCompletion`.
  </Card>

  <Card title="PrimerError" icon="triangle-exclamation" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/common/primer-error">
    Error details carried by the `.failure` state.
  </Card>

  <Card title="Handle payment result" icon="receipt" href="/docs/sdk/ios-checkout/v3.0.0-beta/guides/handle-payment-result">
    Route your UI based on the checkout outcome.
  </Card>

  <Card title="PrimerCheckoutSession" icon="arrows-rotate" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-session">
    Drive the inline checkout lifecycle from your own layout.
  </Card>
</CardGroup>
