FloPay SDK Changelog

Client-facing updates for FloPay SDK releases.

v1.3.2 - Clear billing address errors on vault card checkout #

On the vault card path, an invalid billing postcode is now caught before the card is charged and shown with the billing provider's exact, country-specific message. Buyers correct the field and resubmit without re-entering card details, and postcode rules match the billing API exactly so a code accepted in the browser is accepted server-side.

10 Jul 2026

Improvement
Checkout
React SDK
Shared SDK

FloPay SDK v1.3.2 fixes a case on the vault card checkout where an invalid billing address could leave the buyer waiting until a generic "Timed out waiting for payment confirmation." message. When the billing address is rejected, the SDK now blocks the charge, surfaces the specific reason immediately, and lets the buyer correct the field and resubmit — without re-entering their card.

What changed

  • On the vault card path, the billing address is confirmed before the card is submitted for charge. If the address is rejected, the submit is held and the card is never charged, so the checkout no longer hangs on a generic timeout.
  • The exact, country-specific reason is now shown inline and reported through onError — for example "Postal/ZIP code is not valid for the selected country. Expected format: e.g. A1A 1A1" — instead of being silently dropped.
  • After a rejected address, the vault widget keeps the entered card, so the buyer fixes the postcode and resubmits without re-typing card details.
  • A transient network or server blip while saving the address no longer hard-fails checkout: the flow falls back to best-effort so a recoverable session can still complete.
  • The client-side postcode rules in @flopay/shared (isValidPostalCode, isPostalCodeSupported, getPostalCodeExample) now mirror the billing API's validation exactly, so a postcode accepted in the browser is accepted server-side and the inline hint matches the server's message.

Developer notes

  • No API changes are required to adopt this release. If you consume the @flopay/shared postcode helpers directly, their results and country-specific examples now align 1:1 with the billing API — review any places where you previously worked around client/server differences.

v1.3.1 - Client-side postcode validation before card capture #

Checkout now validates the billing postcode against the buyer's selected country before the card is captured, blocking a missing or malformed postcode with a clear, country-specific message. New public postcode helpers ship in @flopay/shared, and multi-message validation errors from the billing API now surface their real reason.

02 Jul 2026

Feature
Checkout
React SDK
Shared SDK
JS SDK

FloPay SDK v1.3.1 catches a missing or malformed billing postcode before the card is captured, on both the card checkout paths. When AVS collection is enabled, the split card form now checks the postcode format against the buyer's selected country and shows an inline, country-specific message with the expected shape, so shoppers fix the field up front instead of failing later in the charge. Countries with no postal system are never blocked.

What changed

  • The split card form validates the postcode format against the live selected country before capturing the card. A supported country with a missing or malformed postcode blocks submit and shows an inline message with the expected format — for example "Enter a valid ZIP Code (e.g. 12345 or 12345-6789)", or "ZIP Code is required" when the field is left empty.
  • Countries that have no postal system (or that aren't recognised for postcode validation) keep the field optional: empty and format checks are skipped, so those buyers are never blocked.
  • The same country-aware rules the billing API applies are now used on the client, so a postcode accepted in the browser is accepted server-side.
  • Error messages returned by the billing API as a list (one entry per failed rule) now surface their real, combined reason instead of collapsing to a generic failure message.

Why it matters

  • Buyers get immediate, specific feedback on the postcode field and correct it before payment, rather than hitting a late decline after the card is entered.
  • Client and server agree on what a valid postcode looks like for each country, reducing avoidable failed payments and mismatched validation.
  • When an account-level validation error does occur, integrators and operators see the actual reason, making failures faster to diagnose.

Developer notes

  • Upgrade @flopay/js, @flopay/react, @flopay/node, and @flopay/shared together to 1.3.1.
  • @flopay/shared now exports three country-aware postcode helpers you can use in your own UI: isPostalCodeSupported(country), isValidPostalCode(country, postalCode) (fails open for countries with no postcode), and getPostalCodeExample(country) for a sample of the expected format.
  • The new postcode validation is automatic in SplitCardForm when AVS collection is enabled — no configuration changes are required to adopt it.
  • @flopay/shared now carries one small runtime dependency (validator), installed transitively when you depend on the package. No action is needed beyond upgrading.
  • No public billing API request or response shapes have changed in this release.

v1.3.0 - Backend-orchestrated vault PCI card widget #

The card path now renders a backend-served, self-contained hosted vault widget that owns tokenization, the charge, and 3DS — gateway agnostic for cards. Also ships first-class Modern/Bold/Glass theme bundles and hides unsupported in-app-browser wallet rows.

19 Jun 2026

Feature
Checkout
JS SDK
React SDK
Shared SDK

FloPay SDK v1.3.0 moves card collection onto the vault PCI card form. When a checkout session advertises a pcivault gateway, the backend returns a self-contained hosted widget that owns the PCI card fields, its own submit button, card tokenization, PaymentIntent creation and confirmation, 3DS, and the result. The SDK injects that widget and relays its terminal outcome - this becomes gateway agnostic for cards and the backend handles the routing/cascading. Stripe stays only for non-card methods (Wallets and APMs).

What changed — vault PCI card form

  • @flopay/react's SplitCardForm renders a backend-served hosted vault widget (via the rewritten VaultCardFields) instead of Stripe's embedded card elements whenever the session advertises a pcivault gateway. On the vault path it hides its own card fields, cardholder-name input, AVS fields, and submit button — the widget owns them.
  • @flopay/js's PciVaultCardCapture is now a thin widget injector. flopay.cardCapture({ sessionId }) returns a CardCaptureAdapter whose mount(container, { html }) injects the server HTML (re-executing its bundled script) and whose on('ready' | 'complete' | 'decline' | 'error', …) relays the widget's terminal window.postMessage ({ source: 'flopay-vault', … }) to the host checkout. The SDK creates no PaymentIntent and runs no 3DS.
  • SplitCardForm relays the widget's outcome to onComplete / onDecline / onError, and obtains the widget HTML from the embedded session.vault.html (when present) or by fetching POST /v1/checkouts/sessions/{id}/vault/capture.
  • The SDK declares X-Flo-SDK-Version: 1.3.0 on POST /v1/checkouts/sessions (new FLO_SDK_VERSION_HEADER) so the backend embeds the vault block in the create-session response for SDKs ≥ 1.3.0.
  • New / changed types in @flopay/shared: VaultCaptureBlock, CardCaptureOutcomeEvent, VaultCaptureResultMessage, a redefined CardCaptureEventType ('ready' | 'complete' | 'decline' | 'error') and CardCaptureMountOptions ({ html }), and CheckoutSession.vault. PaymentAPI adds getVaultCapture() and threads the embedded vault block onto the created session.

Why it matters

  • Card data is routed through Flo's PCI vault rather than Stripe's hosted card form, decoupling the card path from any single downstream processor while keeping PCI scope off the SDK and the consumer page.
  • The backend orchestrates the charge and 3DS, so the SDK no longer ships or depends on Stripe.js for cards. Stripe is confined to wallets / PayPal / APMs.

Developer notes

  • The vault path is capability-gated on the pcivault session gateway, so existing (non-vault) card checkout is unchanged.
  • On the vault path, onTokenizedBody does not fire — use onComplete / onDecline / onError. The legacy Stripe path's onTokenizedBody is unchanged.
  • Backend dependencies this SDK relies on: the hosted widget must (a) emit the flopay-vault postMessage outcome the SDK listens for (otherwise it falls back to its own success redirect), (b) handle the ACTION_REQUIRED 3DS step internally, and (c) own AVS for the vault path (the SDK no longer collects it inline; account-level address set at session-create still flows to the backend).
  • Bump all @flopay/* packages together to 1.3.0 (@flopay/js, @flopay/react, @flopay/node, @flopay/shared).

v1.2.8 - Free-trial and $0 checkout support #

FloPay SDK now supports $0 checkouts and free trials end-to-end, routing setup-only client secrets through Stripe's SetupIntent flow so wallets, card forms, and 3DS resume all complete cleanly without a charge.

17 Jun 2026

Feature
Checkout
Stripe
JS SDK
React SDK

FloPay SDK v1.2.8 introduces first-class support for free-trial and $0 checkout sessions. When a session has no upfront amount, the SDK now routes through Stripe's SetupIntent APIs end-to-end — across the core adapter, the Express Checkout wallet button, the card form, and the 3DS resume-after-redirect flow — so shoppers can authorize a payment method without a charge and integrators no longer hit the amount must be greater than 0 error from Stripe.

What changed

  • $0 and trial-only sessions now use SetupIntents throughout. seti_ client secrets are accepted by the adapter, the Express Checkout wallet button, and the saved-payment 3DS resume path, and confirmed through the corresponding setup APIs instead of payment confirmation.
  • Apple Pay and Google Pay sheets render correctly for $0 carts. The wallet button switches to setup mode automatically, so buyers no longer see a misleading placeholder amount on the wallet sheet.
  • The split card form omits the placeholder amount and capture method when running in setup mode, keeping the form valid for free-trial sessions.
  • Cash App Pay is now hidden automatically when the cart total is below $0.50 USD, preventing a failed selection on amounts the provider cannot accept.
  • React ecosystem and tooling have been refreshed: @stripe/react-stripe-js and @stripe/stripe-js move to the latest minor releases, @paypal/paypal-js advances to v10, and React 19.2.7 is now the supported peer version.

Why it matters

  • Merchants running free trials, $0 authorization captures, or "card-on-file" onboarding can now use the standard FloPayCheckout, SplitCardForm, and automatic payment button surfaces without custom workarounds.
  • Wallet checkouts on $0 sessions no longer display a confusing fallback amount, removing a common source of buyer drop-off on trial offers.
  • 3DS challenges that redirect back into the page now resume correctly for setup-only sessions, so saved-payment flows complete cleanly after step-up authentication.

Developer notes

  • No public API or request/response shapes change. Existing paid-checkout integrations continue to work without modification.
  • To enable free-trial / $0 checkout, create a checkout session whose computed total is 0. The SDK detects the resulting setup-only client secret and selects the correct confirmation path automatically.
  • Update your peer dependencies to React 19.2.7 and @stripe/react-stripe-js ^6.6.0 when upgrading. If you pin @paypal/paypal-js directly, move to ^10.0.0 alongside this release.
  • Bump all @flopay/* packages together to 1.2.8 (@flopay/js, @flopay/react, @flopay/node, @flopay/shared).

v1.2.7 - Session-bound checkout token for the automatic payment button #

FloPayAutomaticPaymentButton now accepts and forwards the session-bound checkout token (nonce) on every continuation call, keeping consumer-supplied sessions and the inline fallback authorized against post-#640 backends. Session product type is now optional, and the payments list sorts by createdAt.

15 Jun 2026

Feature
Security
Checkout
React SDK

FloPay SDK v1.2.7 extends the session-bound checkout token (nonce) introduced in v1.2.4 to the automatic payment button. FloPayAutomaticPaymentButton now accepts a nonce prop for consumer-supplied sessions and threads the token through the session read, the /process call, the saved-payment flow, and the inline fallback checkout, so every continuation request stays authorized against backends that require x-checkout-session-token. This release also relaxes the product type field on session reads to match the v1.2.6 create-side change.

What changed

  • FloPayAutomaticPaymentButton gains a nonce prop. When you pass your own sessionId, also pass the nonce returned when that session was created — the session GET does not echo the token back, so without it the existing-session path 401s with "Missing checkout session token." on post-#640 backends. On the create-session path the SDK still mints and threads the nonce itself, so the prop is ignored there.
  • The button now resolves an effective nonce (session.clientSecret from the create path, falling back to the nonce prop) and forwards it on the session read, the saved-payment /process call, and the 3DS recovery refetch.
  • When auto-processing fails and the button opens its inline FloPayCheckout fallback, the nonce is carried over so the fallback's own session GET is authorized.
  • processSavedPaymentForMode accepts an explicit nonce (defaulting to session.clientSecret) so callers that resolved a session via GET can keep /process and 3DS recovery authorized.
  • CheckoutSessionProduct.type is now optional, mirroring the v1.2.6 change to CheckoutProduct.type. Display ordering treats any product that is not explicitly a 'subscription' as an 'item'.
  • PaymentAPI.getPaymentsByEmail now sorts by createdAt instead of occurredAt.

Why it matters

  • The automatic payment button now honours the same per-session token contract as the rest of the checkout surfaces, closing the gap where consumer-supplied sessions and the inline fallback could fail authorization on token-enforcing backends.
  • Making product type optional keeps session reads consistent with the simplified create-side payload from v1.2.6, where the backend resolves item-vs-subscription from the catalog code.

Developer notes

  • Upgrade @flopay/js, @flopay/react, @flopay/node, and @flopay/shared together to 1.2.7.
  • If you render FloPayAutomaticPaymentButton with your own sessionId, pass the nonce returned by createCheckoutSession for that session. No change is required for the create-session path (createSession / inline draft) — the SDK threads the token for you.
  • Consumers reading CheckoutSessionProduct.type should treat it as optional; anything not explicitly 'subscription' should be rendered as an item.
  • No other public exports, props, or request/response shapes have changed.

v1.2.6 - Optional product type for a simpler products payload #

CheckoutProduct.type is now optional and deprecated — the backend resolves item vs subscription from the catalog code, so you can build a products[] payload with just code and quantity. Display caching now keys on code alone.

12 Jun 2026

Feature
Checkout
Shared

FloPay SDK v1.2.6 simplifies the products payload by making CheckoutProduct.type optional. The billing API resolves whether an entry is a one-time item or a recurring subscription from the catalog code, so consumers no longer need to classify products themselves when creating a session. Existing integrations that still pass type keep working unchanged.

What changed

  • CheckoutProduct.type is now optional and deprecated. You can build a products[] entry with just code (and quantity); the backend resolves item-vs-subscription from the catalog code. type is still accepted, and when supplied it refines the client-side optimistic display rendered before the session response loads (subscriptions are listed first).
  • Display-cache merging in PaymentAPI now keys products on code alone (code:{code}) rather than the previous type:code composite. Cached display data merges back correctly even when the create-side payload omitted type.
  • buildSyntheticSession defaults a product's type to 'item' when it is omitted, so synthetic session previews remain stable.

Why it matters

  • Building a checkout session is simpler: a product is identified by its catalog code, removing a redundant field consumers previously had to set correctly.
  • The catalog code is now the single product identity used for display merging, so optimistic rendering and the session response reconcile reliably regardless of whether type was provided.

Developer notes

  • Upgrade @flopay/js, @flopay/react, @flopay/node, and @flopay/shared together to 1.2.6.
  • No code change is required for integrations that still pass type on products[] — the field remains supported during the deprecation window.
  • New integrations can omit type and pass code (plus quantity) only. Optionally pass type if you want subscriptions ordered first in the pre-response optimistic display.
  • No request/response shapes returned by the billing API have changed.

v1.2.5 - Simpler @flopay/js install with bundled Stripe runtime #

Installing @flopay/js no longer requires a separate @stripe/stripe-js install. The Stripe browser SDK is now a direct dependency, and a clearer error is surfaced if the Stripe runtime ever fails to load.

09 Jun 2026

Improvement
Stripe
JS SDK

FloPay SDK v1.2.5 simplifies installation of @flopay/js by bundling @stripe/stripe-js as a direct dependency. Consumers no longer need to install or pin the Stripe browser SDK themselves, and a load-time failure of the Stripe runtime now produces a clearly labelled FloPay error instead of failing silently.

What changed

  • @flopay/js now declares @stripe/stripe-js (^9.7.0) as a direct runtime dependency. The previous optional peer-dependency declaration has been removed, so package managers install the Stripe browser SDK automatically alongside @flopay/js.
  • If the Stripe browser SDK ever fails to resolve at runtime, the SDK now throws a FloPayError with code: 'StripeJsLoadFailed' and a descriptive message, replacing the prior silent failure path.

Developer notes

  • Update your package.json to @flopay/js@1.2.5 (matching @flopay/react@1.2.5, @flopay/node@1.2.5, and @flopay/shared@1.2.5) and reinstall.
  • You can drop any direct @stripe/stripe-js entry from your application's dependencies if you only added it to satisfy the previous peer-dependency requirement. Applications that import @stripe/stripe-js directly for their own purposes can continue to pin it themselves.
  • No public exports, props, or request/response shapes have changed.

v1.2.4 - Session-bound checkout token across continuation calls #

Checkout session creation now returns a session-bound token (nonce) that the SDK forwards on every continuation call, hardening hosted checkout, payment, and saved-payment flows against cross-session reuse.

02 Jun 2026

Feature
Security
Checkout
React SDK
Node SDK

FloPay SDK v1.2.4 introduces a per-session checkout token (nonce) that scopes every continuation request to the session that created it. The token is returned alongside the new checkout session and forwarded automatically by the SDK on payment intent, process, completion polling, and saved-payment flows. A short-lived, same-domain cookie also makes the token available to hosted checkout pages without exposing it in URLs.

What changed

  • createCheckoutSession now returns a nonce on the 201 result for @flopay/js and @flopay/node. The browser SDK additionally writes a same-domain flopay_checkout_token cookie (SameSite=Lax, Secure, 1 hour TTL) so hosted checkout pages can read the token without it appearing in the URL, browser history, or Referer header.
  • PaymentAPI.processPayment now targets POST /v1/checkouts/sessions/{id}/process and sends the token on the x-checkout-session-token header. createPaymentIntent, createSetupIntent, and the checkout-completion poll forward the same header.
  • React surfaces (CheckoutForm, SplitCardForm, DirectPayPalButton, PayPalButton) accept a new nonce prop and forward it on every inline continuation request. FloPayCheckout plumbs the session's token into each child surface automatically, including consumer-supplied form children.
  • The saved-payment flow forwards the token on process, intent creation, and the 3DS recovery refetch.
  • A clear FloPayError with code MissingCheckoutSessionToken is now thrown when a process call is attempted without a token, replacing the prior generic failure.

Why it matters

  • Every continuation call is bound to the originating checkout session, reducing the surface area for cross-session reuse and accidental cross-tab interference.
  • Hosted checkout pages can authenticate continuation calls without leaking the token through URLs or Referer headers, keeping the integration cookie-scoped and same-domain.
  • Saved-payment and 3DS recovery flows are covered by the same token contract as primary checkout, so the security posture is consistent across all payment paths.
  • Improved security hardening

Developer notes

  • This release pairs with a backend update that requires the x-checkout-session-token header on every /v1/checkouts/* continuation route. Upgrade @flopay/js, @flopay/react, @flopay/node, and @flopay/shared together to 1.2.4 to stay in sync.
  • If you call processPayment, createPaymentIntent, or createSetupIntent directly, read nonce from the createCheckoutSession result and pass it through to those calls. The SDK will throw FloPayError({ code: 'MissingCheckoutSessionToken' }) if a process call is made without it.
  • If you use FloPayCheckout or the bundled React forms, no integration change is required beyond the version bump — the provider forwards the token to each child surface for you.
  • If you render your own checkout UI on a hosted page, you can now read the flopay_checkout_token cookie on the same domain instead of carrying the token through the URL.
  • The processPayment endpoint moved from a generic /v1/checkouts/sessions/process shape to POST /v1/checkouts/sessions/{id}/process. If you proxy this call, update your route accordingly.

v1.2.1 - Refreshed Stripe SDK dependencies #

FloPay SDK now ships with the latest @stripe/stripe-js, @stripe/react-stripe-js, and stripe Node SDK releases, picking up upstream fixes and improvements with no integration changes required.

01 Jun 2026

Maintenance
Stripe
React SDK
Node SDK

FloPay SDK v1.2.1 is a maintenance release that brings the bundled Stripe SDKs up to their latest published versions across the browser, React, and Node packages. Upgrade to pick up the latest upstream behavior under the hood; no public APIs have changed.

What changed

  • @stripe/stripe-js is updated from 9.5.0 to 9.7.0 in @flopay/js.
  • @stripe/react-stripe-js is updated from 6.3.0 to 6.5.0 in @flopay/react.
  • stripe (the server SDK) is updated from 22.1.1 to 22.2.0 in @flopay/node.

Why it matters

  • Checkout sessions, Stripe Elements rendering, and server-side Stripe calls all benefit from the latest upstream bug fixes and compatibility updates.
  • Keeping the bundled Stripe SDKs current reduces the surface area for drift between FloPay-managed checkouts and Stripe's evolving payment method support.

Developer notes

  • No public exports, props, or request/response shapes have changed. Bump @flopay/js, @flopay/react, and @flopay/node to 1.2.1 in your package.json and reinstall to adopt this release.

v1.2.0 - Stripe APM (Cashapp, Klarna, Link, and others) enabled at checkout #

SplitCardForm now renders Stripe payment methods directly from the per-session enabledPaymentMethods list, so turning on Cash App Pay, Klarna, Affirm, iDEAL, and other APMs in your Stripe dashboard takes effect without any SDK or app code changes.

31 May 2026

Feature
Checkout
React SDK
Stripe

FloPay SDK v1.2.0 hands control of which Stripe payment methods appear in SplitCardForm to the session payload. The checkout reads gateways.stripe.enabledPaymentMethods from the session and renders only what the merchant has enabled for that Stripe account, partitioned automatically between the express-checkout button row and a new APM accordion. Enabling a new method in the Stripe dashboard now flows through to live checkouts with no redeploy.

What changed

  • SplitCardForm now reads gateways.stripe.enabledPaymentMethods from the checkout session and uses it to drive which methods render. Card entry continues to live in the dedicated split-card fields.
  • Express methods (Apple Pay, Google Pay, PayPal, Link, Amazon Pay, Klarna) are placed in the top express-checkout row. Other enabled APMs (Cash App Pay, Affirm, iDEAL, and similar) render in a new accordion PaymentElement region below.
  • New showStripe and showPayPal props on SplitCardForm provide gateway-level visibility toggles (both default to true). When a session ships a PayPal gateway, the PayPal renderer is selected automatically: the DirectPayPal SDK when available, otherwise Stripe-rendered PayPal.
  • SplitCardForm now emits a validation_error through onError at integration time when both showStripe={false} and PayPal is unavailable, instead of rendering an empty checkout.
  • The tokenization payload (TokenizedBody) gains two fields, gateway and paymentMethodType, so backends can route the resulting /v1/checkouts/sessions/process call by gateway and method. isPaypal is still populated for PayPal flows during the deprecation window.

Why it matters

  • Merchants can light up new Stripe payment methods directly from the Stripe dashboard and have them appear in checkout without an SDK upgrade or app release.
  • Integrators get a single, predictable layout: express buttons on top, additional APMs in an accordion, card entry in the split fields — driven entirely by the session payload.
  • Misconfigurations that previously produced an empty checkout surface are now caught early through a clear validation error.

Developer notes

  • Ensure your billing session response populates gateways.stripe.enabledPaymentMethods with the methods you want exposed (for example ["card", "apple_pay", "google_pay", "klarna", "cashapp"]). Methods omitted from this list will not render.
  • The showApplePay and showGooglePay props on SplitCardForm are deprecated in favor of session-driven visibility. They still work for now but will be removed in a future minor; prefer driving visibility through enabledPaymentMethods and the new showStripe / showPayPal props.
  • If your backend inspects the tokenization payload, you can now switch on the new gateway and paymentMethodType fields on TokenizedBody instead of relying on the isPaypal boolean. isPaypal remains set for PayPal during the deprecation window so existing integrations keep working.
  • When toggling showStripe={false}, make sure a PayPal gateway is configured for the session, otherwise SplitCardForm will surface a validation_error through onError rather than rendering.