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

# Common objects

> API reference for shared types: PaymentResult, PrimerError, PrimerSettings, and more

## PaymentResult

Returned on successful payment via `PrimerCheckoutState.success`:

```swift theme={"dark"}
public struct PaymentResult {
  let payment: Payment?
  let paymentMethodData: PrimerPaymentMethodTokenData?
}
```

| Property            | Type                            | Description                             |
| ------------------- | ------------------------------- | --------------------------------------- |
| `payment`           | `Payment?`                      | Payment details including ID and status |
| `paymentMethodData` | `PrimerPaymentMethodTokenData?` | Token data (available in manual mode)   |

## PrimerError

Payment and configuration error details:

```swift theme={"dark"}
public struct PrimerError {
  let errorId: String
  let errorDescription: String?
  let diagnosticsId: String?
}
```

| Property           | Type      | Description                                  |
| ------------------ | --------- | -------------------------------------------- |
| `errorId`          | `String`  | Unique error identifier for support requests |
| `errorDescription` | `String?` | Human-readable error message                 |
| `diagnosticsId`    | `String?` | Diagnostic ID for Primer support             |

## PrimerSettings

```swift theme={"dark"}
public struct PrimerSettings {
  public init(
    paymentHandling: PrimerPaymentHandling = .auto,
    uiOptions: PrimerUIOptions? = nil,
    paymentMethodOptions: PrimerPaymentMethodOptions? = nil
  )
}
```

## PrimerPaymentHandling

```swift theme={"dark"}
public enum PrimerPaymentHandling {
  case auto    // Primer handles the full payment flow
  case manual  // Primer returns a token for server-side processing
}
```

## PrimerCheckoutState

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

## PresentationContext

```swift theme={"dark"}
public enum PresentationContext {
  case direct               // Show cancel button
  case fromPaymentSelection // Show back button
}
```

## DismissalMechanism

```swift theme={"dark"}
public enum DismissalMechanism {
  case gestures    // Swipe-down dismissal
  case closeButton // Close/cancel button
}
```

## CheckoutPaymentMethod

```swift theme={"dark"}
public struct CheckoutPaymentMethod {
  let id: String
  let type: String                  // e.g., "PAYMENT_CARD", "PAYPAL"
  let name: String                  // Display name
  let icon: UIImage?
  let metadata: [String: Any]?
  let surcharge: Int?               // Minor units
  let hasUnknownSurcharge: Bool
  let formattedSurcharge: String?
  let backgroundColor: UIColor?
}
```

## FieldError

```swift theme={"dark"}
public struct FieldError: Equatable, Identifiable {
  let id: UUID
  let fieldType: PrimerInputElementType
  let message: String
  let errorCode: String?
}
```

## CardFormConfiguration

```swift theme={"dark"}
public struct CardFormConfiguration: Equatable {
  let cardFields: [PrimerInputElementType]
  let billingFields: [PrimerInputElementType]
  let requiresBillingAddress: Bool
  var allFields: [PrimerInputElementType]
}
```

## FormData

```swift theme={"dark"}
public struct FormData: Equatable {
  subscript(fieldType: PrimerInputElementType) -> String { get set }
  var dictionary: [PrimerInputElementType: String]
}
```

## FieldValidationStates

Tracks validation state for individual card form fields. Used with `updateValidationState(_:isValid:)` on `DefaultCardFormScope` when providing custom field components.

```swift theme={"dark"}
public struct FieldValidationStates: Equatable {
  // Card fields
  public var cardNumber: Bool
  public var cvv: Bool
  public var expiry: Bool
  public var cardholderName: Bool

  // Billing address fields
  public var postalCode: Bool
  public var countryCode: Bool
  public var city: Bool
  public var state: Bool
  public var addressLine1: Bool
  public var addressLine2: Bool
  public var firstName: Bool
  public var lastName: Bool
  public var email: Bool
  public var phoneNumber: Bool
}
```

All fields default to `false` and become `true` when validation passes. Use KeyPaths to reference fields:

```swift theme={"dark"}
let cardScope = checkoutScope.getPaymentMethodScope(DefaultCardFormScope.self)

// Report validation from your custom component
cardScope?.updateValidationState(\.cvv, isValid: true)
cardScope?.updateValidationState(\.cardNumber, isValid: false)
```

## FormFieldState

Used by `PrimerFormRedirectScope` for form-based redirect payment methods.

```swift theme={"dark"}
public struct FormFieldState: Equatable, Identifiable {
  public enum FieldType: String, Equatable, Sendable {
    case otpCode       // BLIK 6-digit code
    case phoneNumber   // MBWay phone number
  }

  public enum KeyboardType: Equatable, Sendable {
    case numberPad
    case phonePad
    case `default`
  }

  var id: String { fieldType.rawValue }
  let fieldType: FieldType
  var value: String
  var isValid: Bool
  var errorMessage: String?
  let placeholder: String
  let label: String
  let helperText: String?
  let keyboardType: KeyboardType
  let maxLength: Int?
  var countryCodePrefix: String?
  var dialCode: String?
}
```

## Type aliases

Component closures used for UI customization:

| Alias                                   | Signature                                           |
| --------------------------------------- | --------------------------------------------------- |
| `Component`                             | `() -> any View`                                    |
| `ContainerComponent`                    | `(@escaping () -> any View) -> any View`            |
| `ErrorComponent`                        | `(String) -> any View`                              |
| `PaymentMethodItemComponent`            | `(CheckoutPaymentMethod) -> any View`               |
| `CountryItemComponent`                  | `(PrimerCountry, @escaping () -> Void) -> any View` |
| `CategoryHeaderComponent`               | `(String) -> any View`                              |
| `PaymentMethodSelectionScreenComponent` | `(PrimerPaymentMethodSelectionScope) -> any View`   |
| `CardFormScreenComponent`               | `(any PrimerCardFormScope) -> any View`             |
| `KlarnaScreenComponent`                 | `(any PrimerKlarnaScope) -> any View`               |
| `KlarnaButtonComponent`                 | `(any PrimerKlarnaScope) -> any View`               |
| `PayPalScreenComponent`                 | `(any PrimerPayPalScope) -> any View`               |
| `PayPalButtonComponent`                 | `(any PrimerPayPalScope) -> any View`               |
| `AchScreenComponent`                    | `(any PrimerAchScope) -> any View`                  |
| `AchButtonComponent`                    | `(any PrimerAchScope) -> any View`                  |
| `WebRedirectScreenComponent`            | `(any PrimerWebRedirectScope) -> any View`          |
| `WebRedirectButtonComponent`            | `(any PrimerWebRedirectScope) -> any View`          |
| `FormRedirectScreenComponent`           | `(any PrimerFormRedirectScope) -> any View`         |
| `FormRedirectButtonComponent`           | `(any PrimerFormRedirectScope) -> any View`         |
| `FormRedirectFormSectionComponent`      | `(any PrimerFormRedirectScope) -> any View`         |
| `QRCodeScreenComponent`                 | `(any PrimerQRCodeScope) -> any View`               |

## PrimerCheckoutPresenter (UIKit)

```swift theme={"dark"}
@available(iOS 15.0, *)
public final class PrimerCheckoutPresenter {
  public static let shared: PrimerCheckoutPresenter
  public weak var delegate: PrimerCheckoutPresenterDelegate?
  public static var isAvailable: Bool
  public static var isPresenting: Bool

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

  public static func dismiss(animated: Bool = true, completion: (() -> Void)? = nil)
}
```

## PrimerCheckoutPresenterDelegate

```swift theme={"dark"}
public protocol PrimerCheckoutPresenterDelegate: AnyObject {
  // Required
  func primerCheckoutPresenterDidCompleteWithSuccess(_ result: PaymentResult)
  func primerCheckoutPresenterDidFailWithError(_ error: PrimerError)
  func primerCheckoutPresenterDidDismiss()

  // Optional (3DS)
  func primerCheckoutPresenterWillPresent3DSChallenge(_ paymentMethodTokenData: PrimerPaymentMethodTokenData)
  func primerCheckoutPresenterDidDismiss3DSChallenge()
  func primerCheckoutPresenterDidComplete3DSChallenge(success: Bool, resumeToken: String?, error: Error?)
}
```

## See also

<CardGroup cols={2}>
  <Card title="Settings" icon="gear" href="/sdk/ios-checkout/v3.0.0-beta/configuration/settings">
    Configure SDK behavior
  </Card>

  <Card title="UIKit integration" icon="apple" href="/sdk/ios-checkout/v3.0.0-beta/integration-patterns/uikit-integration">
    Using PrimerCheckoutPresenter
  </Card>
</CardGroup>
