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.
The card form validates each field and surfaces the results through PrimerCardFormState. Read validation state from the PrimerCardFormSession inside your custom slots to display targeted error messages and gate submission.

FieldError

A FieldError represents a validation error for a single form field. It is Equatable and Identifiable (its id is the fieldType), so it works directly with SwiftUI’s ForEach.
@available(iOS 15.0, *)
public struct FieldError: Equatable, Identifiable {
    public var id: PrimerInputElementType { fieldType }
    public let fieldType: PrimerInputElementType
    public let message: String
    public let errorCode: String?

    public init(
        fieldType: PrimerInputElementType,
        message: String,
        errorCode: String? = nil
    )
}
PropertyTypeDescription
idPrimerInputElementTypeDeterministic identifier based on fieldType for stable SwiftUI diffing.
fieldTypePrimerInputElementTypeThe type of field that has the error.
messageStringHuman-readable error message to display to the user.
errorCodeString?Machine-readable error code for programmatic handling.

Validation surfaces on PrimerCardFormState

Validation is exposed through the form state held by PrimerCardFormSession. Observe the session with @ObservedObject (or @StateObject) and read session.state.
MemberTypeDescription
fieldErrors[FieldError]Field-specific validation errors currently present in the form.
isValidBoolWhether the form is valid overall. Use this to enable or disable your submit button.
hasError(for:)(PrimerInputElementType) -> BoolReturns true when the given field currently has an error.
errorMessage(for:)(PrimerInputElementType) -> String?Returns the first error message for the given field, or nil if the field has no error.
@available(iOS 15.0, *)
public struct PrimerCardFormState: Equatable {
    public internal(set) var fieldErrors: [FieldError]
    public internal(set) var isValid: Bool

    public func hasError(for fieldType: PrimerInputElementType) -> Bool
    public func errorMessage(for fieldType: PrimerInputElementType) -> String?
}
isValid reflects the form’s overall validity and updates as the user edits fields. Use it to drive the enabled state of your submit button, and use fieldErrors / errorMessage(for:) to render per-field messages.

Reading a field error inside a slot

Use the helpers on session.state to show an inline error for a specific field. The example below renders a CVV field that highlights its border and shows a message when validation fails.
import SwiftUI
import PrimerSDK

@available(iOS 15.0, *)
struct CvvField: View {
    @ObservedObject var session: PrimerCardFormSession
    @State private var cvv = ""

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            TextField("CVV", text: $cvv)
                .keyboardType(.numberPad)
                .onChange(of: cvv) { newValue in
                    session.updateCvv(newValue)
                }
                .overlay(
                    RoundedRectangle(cornerRadius: 8)
                        .stroke(session.state.hasError(for: .cvv) ? .red : .secondary)
                )

            if let message = session.state.errorMessage(for: .cvv) {
                Text(message)
                    .font(.footnote)
                    .foregroundColor(.red)
            }
        }
    }
}
To enumerate every error currently present in the form, iterate fieldErrors directly — FieldError is Identifiable, so it slots into ForEach.
ForEach(session.state.fieldErrors) { error in
    Text("\(error.fieldType.stringValue): \(error.message)")
        .font(.footnote)
        .foregroundColor(.red)
}

Gating submission with isValid

Bind your submit button’s enabled state to session.state.isValid so it activates only once the form passes validation.
Button("Pay") {
    session.submit()
}
.disabled(!session.state.isValid)

PrimerInputElementType

PrimerInputElementType identifies the type of input field referenced by a FieldError (and used throughout the card form). Each case has a stringValue returning the canonical string identifier.
@objc
public enum PrimerInputElementType: Int {
    case cardNumber
    case expiryDate
    case cvv
    case cardholderName
    case otp
    case postalCode
    case phoneNumber
    case retailer
    case unknown
    case countryCode
    case firstName
    case lastName
    case addressLine1
    case addressLine2
    case city
    case state
    case email
    case all

    public var stringValue: String { get }
}
CasestringValueDescription
cardNumberCARD_NUMBERCredit/debit card number (e.g., “4242 4242 4242 4242”).
expiryDateEXPIRY_DATECard expiration date in MM/YY format.
cvvCVVCard verification value (3-4 digit security code).
cardholderNameCARDHOLDER_NAMEName as printed on the card.
otpOTPOne-time password for verification flows.
postalCodePOSTAL_CODEPostal or ZIP code for billing address.
phoneNumberPHONE_NUMBERPhone number for contact or verification.
retailerRETAILERRetail outlet selection for cash payment methods.
unknownUNKNOWNUnknown or unrecognized field type.
countryCodeCOUNTRY_CODEISO country code (e.g., “US”, “GB”).
firstNameFIRST_NAMEFirst name for billing address.
lastNameLAST_NAMELast name for billing address.
addressLine1ADDRESS_LINE_1Primary street address line.
addressLine2ADDRESS_LINE_2Secondary address line (apartment, suite, etc.).
cityCITYCity name for billing address.
stateSTATEState or province for billing address.
emailEMAILEmail address for receipts and notifications.
allALLRepresents all fields collectively (used for bulk operations).
You typically don’t construct FieldError yourself — the SDK populates fieldErrors for you. Read it through session.state and use hasError(for:) / errorMessage(for:) to drive your UI.

See also

Card form session

The observable session that exposes form state, mutation methods, and submission.

Card field components

Built-in field views you can compose inside the card form slots.