Improved
Checkout SDK Updates — Android v1.5.0
October 26th, 2026
Android — v1.5.0 (2026-10-13)
This is a large Android SDK release centered on custom field validation, a canonical hosted-fields catalogue aligned with the Checkout Web SDK, and hardened log/tokenize redaction. It requires recompiling against the new AARs (see Breaking Changes).
Added
- Custom additional-field validators (payments-core): new public API
Spreedly.addValidation/removeValidation/runCustomValidationBeforeSubmit. Register validators for 29 allowlisted snake_case keys (PAN, CVV/CVC, expiry, and ACH bank fields excluded; cardholder name included). Validators run on hosted-field blur and again before tokenize, fail closed, and keep tokenize failures / logs / events generic. Callbacks receive a sparse present-field snapshot (Map<AdditionalField, String>). - Submit preflight custom validation:
runCustomValidationBeforeSubmit(formFields, additionalFields)runs the same custom-validator tier as tokenize against the merged submit field map, for refreshing inline errors before tokenize. - Canonical hosted-fields tokenize keys: ten Checkout Web SDK wire keys on
AdditionalFieldandCreditCard(house_number_or_name, street, street_line2, shipping twins, billing/shipping phone country/area codes). Phone parts are separate keys; legacy address1 / shipping_address1 can coexist. - Hosted-fields catalogue
FormFieldTypevariants: FIRST_NAME, LAST_NAME, EMAIL, COMPANY, COUNTRY, PHONE_NUMBER, seven dedicated shipping types, and ten canonical address/phone types.OptionalFieldTypeexpands to 26 entries. PaymentSheetOptionalFieldCallbacks: new interface (default no-op methods) for catalogue field changes, wired throughsdk.optionalCallbacks.CardCatalogueFormFieldTypeshelper for card-catalogue mount tracking and SDK value-source-of-truth types.- Per-field required-error messages: each hosted/shipping/additional field now has its own distinct empty-value error (e.g.
PHONE_NUMBER_REQUIRED,SHIPPING_CITY_REQUIRED) instead of a shared genericADDRESS_REQUIRED. - New validator factory functions / overloads:
ValidatorFactory.shippingCity/shippingState, plus additive field-specific-error overloads onValidatorFactory.zipCode/name/limitedText(and matchingStandard*Validatorconstructors), kept as separate overloads to preserve binary compatibility.
Changed
- Additional-fields merge at tokenize: matches Checkout Web SDK
pluckWhitelistedValues— a key present inadditionalFieldsis sent unchanged (including blank); when absent, form state is used. All present name keys (first_name, last_name, full_name) are forwarded independently and resolved server-side. - Hosted-wins tokenize merge: for card tokenize, owned keys (formFields ∪ mounted catalogue types) prefer hosted / sheet state over conflicting
additionalFields; one sanitized log line per tokenize when conflicts are stripped. - Payment sheet name tokenize: the drop-in sheet no longer injects name values into
additionalFields; hosted / state values win via owned-key merge.NameFieldDisplayMode.SEPARATE_FIELDSmounts FIRST_NAME + LAST_NAME. - Field character limits aligned with the Web SDK
DEFAULT_CHAR_LIMITS: address/canonical text 500 (was 350), international ZIP max 15 (was 10), email max 254, phone parts 15, country 100. - Catalogue field value source-of-truth: with
writeCatalogueValueToSdk = true, non-encrypted catalogueSPLTextFieldtypes sync intoPaymentSheetStateon input (ACH routing/account carved out). - Custom-validator present-field evaluation: matches iOS — validators run only when their wire key is in the submit/blur snapshot; unmounted/omitted fields are skipped, never invoked with an empty string.
createPaymentMethodsubmit validation: runs the same mounted-field validation union ascreateCreditCard()when formFields is non-empty or catalogue fields are mounted.- ACH submit validation scope:
createBankAccount()validates only the merchant formFields list; the union/hosted-wins merge applies to card tokenize only this release (ACH parity deferred). - ZIP / postal-code validation: Web SDK parity — the ZIP field no longer filters keystrokes and
StandardZipCodeValidatorno longer enforces a postal-code format (only required-ness and length, counted in UTF-16 code units).ALLOW_INTERNATIONAL_ZIP_CODESis now a no-op for built-in validation. - Required-field visible-character check:
FieldValidator.validateRequirednow rejects values made up only of invisible Unicode format characters (zero-width space, RTL/LTR mark) as empty.
Fixed
- Payment sheet State/Zip row spacing: removed an extra spacer emitted for the skipped ZIP iteration when STATE and ZIP_CODE are both enabled.
- Additional-field email validation: malformed emails in
additionalFieldsat submit now classify as invalid rather than field_too_long (over-length still uses field_too_long). - Custom-validator telemetry volume: mounted
SPLTextFieldauto-wiring no longer emitssdk_method_invokedtelemetry on every keystroke/blur; direct merchant validation calls still emit as before, with no change to validation behavior.
Breaking Changes
Everything here requires recompiling against the new hostedfields, payments-core, and paymentsheet AARs — this is not a drop-in binary patch over compiled 1.4.x consumers.
createPaymentMethodformFields parameter: both overloads accept an optional trailingformFields: List<FormFieldType> = emptyList(). Kotlin omits it via defaults; new Java integrations should pass it explicitly (not@JvmOverloads).PaymentSheetStatecatalogue properties: twenty-one catalogue validators append after the original fourteen (component1–14 order unchanged), changing constructor/copy JVM descriptors — recompile and prefer named properties.CreditCardcanonical wire fields: ten nullable canonical properties append to the primary constructor (hidden 22-parameter constructor preserved for 1.4.x callers).- Exhaustive
whenoverFormFieldType/OptionalFieldType: new sealed variants require adding branches (or anelse) on upgrade. SPLTextField.writeCatalogueValueToSdk: optional trailing Compose parameter (default true on the new overload) — recompile call sites.AdditionalFieldValidatorfields snapshot: second callback parameter is nowMap<AdditionalField, String>(wasMap<String, String>); recompile custom validators.
Security
- Custom validator tokenize egress: a centralized generic tokenize failure message ("Payment form validation failed"); merchant
CustomValidationResult.errorMessagenever appears on failed results or telemetry (sanitized copy still shown in blur/preflight inline UI). - Payment form state logging:
PaymentSheetState.toString()/BankAccountSheetState.toString()redact non-blank sensitive values as***and omit catalogue/shipping/canonical properties, so crash/debug logs don't expose encrypted CHD or bank account numbers. PaymentMethod.toString: redacts non-blank email and metadata; mandate remains[REDACTED].AppNetworkError.API_ERROR.errorBodysanitized at ingress: now runs through the sameLogSanitizerredaction as the higher-layer type, closing a gap where a labeled CVV/PAN-like value in a raw server error body could reach merchant code unredacted.
Deprecated
NameParsingUtils.getNameFields(payments-core): accidentally public and no longer used; kept with 1.4.0 behavior for binary compatibility and scheduled for removal in 2.0.0. Remove direct calls — name resolution is handled internally during tokenize.

