Improved

Checkout SDK Updates — Android v1.5.0

Android — v1.5.0 (2026-10-13)

View on GitHub

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 AdditionalField and CreditCard (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 FormFieldType variants: FIRST_NAME, LAST_NAME, EMAIL, COMPANY, COUNTRY, PHONE_NUMBER, seven dedicated shipping types, and ten canonical address/phone types. OptionalFieldType expands to 26 entries.
  • PaymentSheetOptionalFieldCallbacks: new interface (default no-op methods) for catalogue field changes, wired through sdk.optionalCallbacks.
  • CardCatalogueFormFieldTypes helper 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 generic ADDRESS_REQUIRED.
  • New validator factory functions / overloads: ValidatorFactory.shippingCity / shippingState, plus additive field-specific-error overloads on ValidatorFactory.zipCode / name / limitedText (and matching Standard*Validator constructors), kept as separate overloads to preserve binary compatibility.

Changed

  • Additional-fields merge at tokenize: matches Checkout Web SDK pluckWhitelistedValues — a key present in additionalFields is 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_FIELDS mounts 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 catalogue SPLTextField types sync into PaymentSheetState on 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.
  • createPaymentMethod submit validation: runs the same mounted-field validation union as createCreditCard() 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 StandardZipCodeValidator no longer enforces a postal-code format (only required-ness and length, counted in UTF-16 code units). ALLOW_INTERNATIONAL_ZIP_CODES is now a no-op for built-in validation.
  • Required-field visible-character check: FieldValidator.validateRequired now 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 additionalFields at submit now classify as invalid rather than field_too_long (over-length still uses field_too_long).
  • Custom-validator telemetry volume: mounted SPLTextField auto-wiring no longer emits sdk_method_invoked telemetry 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.

  • createPaymentMethod formFields parameter: both overloads accept an optional trailing formFields: List<FormFieldType> = emptyList(). Kotlin omits it via defaults; new Java integrations should pass it explicitly (not @JvmOverloads).
  • PaymentSheetState catalogue properties: twenty-one catalogue validators append after the original fourteen (component1–14 order unchanged), changing constructor/copy JVM descriptors — recompile and prefer named properties.
  • CreditCard canonical wire fields: ten nullable canonical properties append to the primary constructor (hidden 22-parameter constructor preserved for 1.4.x callers).
  • Exhaustive when over FormFieldType / OptionalFieldType: new sealed variants require adding branches (or an else) on upgrade.
  • SPLTextField.writeCatalogueValueToSdk: optional trailing Compose parameter (default true on the new overload) — recompile call sites.
  • AdditionalFieldValidator fields snapshot: second callback parameter is now Map<AdditionalField, String> (was Map<String, String>); recompile custom validators.

Security

  • Custom validator tokenize egress: a centralized generic tokenize failure message ("Payment form validation failed"); merchant CustomValidationResult.errorMessage never 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.errorBody sanitized at ingress: now runs through the same LogSanitizer redaction 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.