{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","admonition"]},"type":"markdown"},"seo":{"title":"Data validation","description":"Transform your commerce with PXP's unified platform—seamless payments, real-time insights, and global growth in one powerful integration.","lang":"en-UK","siteUrl":"https://developer.pxp.io","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"data-validation","__idx":0},"children":["Data validation"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Collect and validate the data entered by your customers."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Validation in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PXPCheckoutSDK"]}," helps you:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Cut down on avoidable declines and retries by catching bad input early."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Give shoppers clear, localisable messages tied to stable error codes (for example ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN01"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ED04"]},")."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Keep card data inside the SDK's secured fields rather than re-implementing PAN/CVC rules in your app."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Validation is driven by component configuration (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationOnBlur"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationOnChange"]},") and callbacks that receive ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["[ValidationResult]"]},". ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardSubmitComponent"]}," then runs a submit-time validation pass before tokenisation and payment."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"how-validation-runs","__idx":2},"children":["How validation runs"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Mechanism"},"children":["Mechanism"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationOnBlur"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationOnChange"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["On ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FieldComponentConfig"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SecuredFieldComponentConfig"]},". Controls whether validation runs when the field loses focus and/or when the value changes."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onValidationPassed"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onValidationFailed"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Receive ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["[ValidationResult]"]}," after a validation pass for that field."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NewCardComponentConfig.onValidation"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Aggregates validation across the new-card form."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardSubmitComponentConfig.onValidation"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Fires with combined results from linked inputs (and AVS fields when enabled) during the submit pipeline."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardSubmitComponentConfig.onCustomValidation"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["async -> Bool"]},". Runs ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["after"]}," standard field validation succeeds; return ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]}," to block ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["submitAsync()"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["submitAsync()"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Performs collection and validation internally; you don't call a separate ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validateWhenSubmit()"]}," per field."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["See",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/ios/card/events"},"children":["Events"]}," for the full callback list."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"public-value-and-validation-helpers-limited","__idx":3},"children":["Public value and validation helpers (limited)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Only a few types expose public \"read value\" or \"validate now\" methods:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Component"},"children":["Component"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Public API"},"children":["Public API"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Notes"},"children":["Notes"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Card consent"]}," / ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Pre-fill billing address checkbox"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["getValue() -> Bool"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CheckboxComponent"]}," — checked state."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Click Once (standalone)"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validate() async -> [ValidationResult]"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Primarily CVC when required."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Click Once (standalone)"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["getValue() async -> ClickOnceStandaloneComponentData?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Selected token + optional CVC; ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["nil"]}," if no token."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Field components (card number, expiry, CVC, holder name, country, postcode, address) don't expose a public ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["getValue()"]}," method. These components use internal value APIs that the SDK reads automatically. When you call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["submitAsync()"]}," on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardSubmitComponent"]},", it collects the secured values from all linked field components, so you don't need to retrieve values manually."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Card brand selector and dynamic card image are display components: no editable value and no field-validation resource in the same sense as PAN/CVC."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Pre-built containers (new card, billing address, card-on-file, click-once pre-built, card submit) compose their behaviour from children and submit functionality."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"validationresult-swift","__idx":4},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ValidationResult"]}," (Swift)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Each result bundles a boolean and an optional map of errors (keys are field identifiers used inside the SDK)."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"public struct ValidationResult: Codable {\n    public let valid: Bool\n    public let errors: [String: ValidationError]?\n}\n\npublic struct ValidationError: Codable {\n    public let message: String\n    public let code: String\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Typical handling:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"func process(_ results: [ValidationResult]) {\n    for r in results {\n        if r.valid { continue }\n        r.errors?.forEach { key, err in\n            print(\"\\(key): \\(err.code) — \\(err.message)\")\n        }\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["There is no ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["isValid"]}," property — use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["valid"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"card-number","__idx":5},"children":["Card number"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"rule-order-matches-cardnumbercomponentvalidatefield-","__idx":6},"children":["Rule order (matches ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardNumberComponent.validateField"]},")"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Code"},"children":["Code"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"When it fires"},"children":["When it fires"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN01"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Empty value (required)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN02"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Sanitised value isn't all digits."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN03"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Entered length is still below the detected brand's minimum length."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN04"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Brand is unknown after pattern matching."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN05"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Brand is known but not in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["acceptedCardBrands"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN06"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Luhn check fails (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validateCardNumber"]}," in the SDK)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN07"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Custom validation message with format argument (for example ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"%@ not accepted\""]},")"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN08"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["BIN lookup didn't return card type."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Override copy with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardNumberValidationResource"]}," (all of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN01"]},"-",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN08"]}," are required in the initialiser)."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let validations = CardNumberValidationResource(\n    CN01: \"Enter your card number\",\n    CN02: \"Use digits only\",\n    CN03: \"Card number looks too short\",\n    CN04: \"We could not recognise this card type\",\n    CN05: \"This card type is not accepted\",\n    CN06: \"Check the number and try again\",\n    CN07: \"%@ not accepted\",\n    CN08: \"Could not determine card type\"\n)\n\nvar config = CardNumberComponentConfig(\n    label: \"Card number\",\n    acceptedCardBrands: [.visa, .mastercard, .amex],\n    validations: validations,\n    validationOnBlur: true,\n    validationOnChange: false,\n    onValidationFailed: { results in\n        _ = results.first { !$0.valid }?.errors?.values.first?.message\n    }\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Brand ranges and lengths come from the SDK's internal brand tables (patterns and CVC lengths also drive ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardCvcComponent"]}," min/max). See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/ios/card/card-number"},"children":["Card number"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"luhn","__idx":7},"children":["Luhn"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The SDK implements the Luhn check in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ValidateCardNumber.swift"]}," (used for ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CN06"]},"). You don't need to duplicate it unless you are validating ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["non-SDK"]}," input."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"expiry-date","__idx":8},"children":["Expiry date"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"codes--cardexpirydatecomponent-","__idx":9},"children":["Codes (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardExpiryDateComponent"]},")"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Code"},"children":["Code"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Typical meaning"},"children":["Typical meaning"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ED05"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Empty (required)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ED01"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Disallowed characters (must be digits / allowed separators)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ED03"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Split / pattern / full-format mismatch (depends on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardExpiryDateFormatOption"]},")"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ED02"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Month not 1-12 (or non-numeric month part)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ED04"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Expiry is before the minimum valid month (respects ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["numberOfMonthExpired"]}," when set)"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Messages are set via ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardExpiryDateValidationResource"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ED01"]},"-",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ED05"]},")."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let validations = CardExpiryDateValidationResource(\n    ED01: \"Use digits only (you can use / or . as separators)\",\n    ED02: \"Enter a month from 01 to 12\",\n    ED03: \"Use the correct expiry format\",\n    ED04: \"This card appears to be expired\",\n    ED05: \"Enter the expiry date\"\n)\n\nlet expiryConfig = CardExpiryDateComponentConfig(\n    label: \"Expiry\",\n    formatOptions: .mmYY,\n    validations: validations\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/ios/card/card-expiry-date"},"children":["Card expiry date"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"cvc","__idx":10},"children":["CVC"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"codes--cardcvccomponent-","__idx":11},"children":["Codes (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardCvcComponent"]},")"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Code"},"children":["Code"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Typical meaning"},"children":["Typical meaning"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CVC01"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Required but empty"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CVC02"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Non-digit characters"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CVC03"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Shorter than min length for the current brand (often 3)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CVC04"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Longer than max (typically 4 for Amex-style rules)"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Min/max length is updated when the card number component detects a brand (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["setMinMaxLength"]},"). Configure the copy with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardCvcValidationResource"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["See ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/ios/card/card-cvc"},"children":["Card CVC"]}]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"custom-validation--oncustomvalidation-","__idx":12},"children":["Custom validation (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onCustomValidation"]},")"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardSubmitComponentConfig.onCustomValidation"]}," for ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["business"]}," checks (limits, fraud rules, cart state) after SDK field validation has passed."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"submitConfig.onCustomValidation = {\n    guard await orderStillValid() else { return false }\n    return true\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If any standard validation fails, the submit button path doesn't reach ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onCustomValidation"]},". Surface field issues via ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onValidation"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onValidationFailed"]},", or UI bound to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ValidationResult"]},"."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"real-time-vs-submit-time","__idx":13},"children":["Real-time vs submit-time"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Real-time:"]}," enable ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationOnChange"]}," (and/or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["validationOnBlur"]},") on fields where you want early feedback; use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onValidationPassed"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onValidationFailed"]}," to drive inline UI."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Submit-time:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["disableUntilValidated"]}," on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CardSubmitComponentConfig"]}," keeps the default button disabled until linked fields (and AVS, if enabled) validate; ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["submitAsync()"]}," re-validates before proceeding."]}]}]},"headings":[{"value":"Data validation","id":"data-validation","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"How validation runs","id":"how-validation-runs","depth":2},{"value":"Public value and validation helpers (limited)","id":"public-value-and-validation-helpers-limited","depth":2},{"value":"ValidationResult (Swift)","id":"validationresult-swift","depth":2},{"value":"Card number","id":"card-number","depth":2},{"value":"Rule order (matches CardNumberComponent.validateField )","id":"rule-order-matches-cardnumbercomponentvalidatefield-","depth":3},{"value":"Luhn","id":"luhn","depth":3},{"value":"Expiry date","id":"expiry-date","depth":2},{"value":"Codes ( CardExpiryDateComponent )","id":"codes--cardexpirydatecomponent-","depth":3},{"value":"CVC","id":"cvc","depth":2},{"value":"Codes ( CardCvcComponent )","id":"codes--cardcvccomponent-","depth":3},{"value":"Custom validation ( onCustomValidation )","id":"custom-validation--oncustomvalidation-","depth":2},{"value":"Real-time vs submit-time","id":"real-time-vs-submit-time","depth":2}],"frontmatter":{"seo":{"title":"Data validation"}},"lastModified":"2026-05-18T12:08:25.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/components/ios/card/data-validation","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}