@flopay/react 1.4.8 → 1.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -182,6 +182,10 @@ partitions that list into two regions inside `SplitCardForm`:
182
182
  - `PaymentElement` (accordion) — every other enabled method, e.g. `cashapp`,
183
183
  `affirm`, `ideal`, `bancontact`, `sepa_debit`.
184
184
 
185
+ `card` is a capability marker, not a Stripe-rendered method. It keeps the
186
+ **Credit / Debit Card** path available and tells SDK 1.4.9+ that the hosted
187
+ vault form can be requested lazily when `session.vault` is absent.
188
+
185
189
  Enabling Cash App Pay (or any future Stripe method) in the Stripe dashboard is
186
190
  the entire integration change — no SDK redeploy or consumer code update is
187
191
  required. Wallets only render on supported devices regardless of dashboard
@@ -353,11 +357,17 @@ Skip the backend API route — create the session directly in the component:
353
357
  The component POSTs to the billing API, gets the full session back, and renders the form — zero backend code needed.
354
358
 
355
359
  That create POST sends a stable `Idempotency-Key` header automatically whenever a
356
- secure RNG is available, so a timeout or lost response never mints a second
357
- session. `FloPayCheckout` already coalesces concurrent mounts (StrictMode
358
- double-mount, Suspense remount, navigation flicker) into a single create, and
359
- rerenders during an in-flight create do **not** replace the key. You normally
360
- don't need to think about it.
360
+ secure RNG is available. `FloPayCheckout` resolves the key once per logical
361
+ checkout, stores it with the inline-session cache in `sessionStorage`, and reuses
362
+ it across transport retries, effect reruns, and component remounts. Concurrent
363
+ mounts (StrictMode double-mount, Suspense remount, or navigation flicker) share
364
+ both the session create and the auto-mode payment attempt, so one purchase cannot
365
+ fan out into multiple creates or charges.
366
+
367
+ Logical checkout identity is based on the merchant, buyer, cart/pricing, and
368
+ coupons. Checkout-mode changes, refreshed payment tokens, and analytics/UTM prop
369
+ churn do not rotate the key while that purchase is active. A different cart or
370
+ buyer gets a different key; an email-less buyer is separated by `account.userId`.
361
371
 
362
372
  To control the key yourself — for example to keep it stable across your own
363
373
  server retries — pass `idempotencyKey` on `createSession`:
@@ -386,8 +396,10 @@ When you use `onBeforeButtonClick` with `createSession`, any returned `InlineSes
386
396
  ### Advanced: Manual Provider Setup
387
397
 
388
398
  Use `SplitCardForm` when you need to compose the provider and session yourself.
389
- Card checkout still requires the backend-hosted vault block; Stripe remains
390
- limited to wallets/APMs and saved-payment authentication.
399
+ Card checkout uses the backend-hosted vault widget; Stripe remains limited to
400
+ wallets/APMs and saved-payment authentication. The session can supply the
401
+ widget eagerly in `session.vault`, or explicitly advertise `card` in
402
+ `gateways.stripe.enabledPaymentMethods` so the SDK recovers it on demand.
391
403
 
392
404
  ```tsx
393
405
  import { FloPayProvider, SplitCardForm } from '@flopay/react';
@@ -432,7 +444,8 @@ The resulting surfaces are:
432
444
 
433
445
  1. Wallet buttons and supported APM tiles from the session gateway capability.
434
446
  2. Direct or Stripe-hosted PayPal, selected from the session gateways.
435
- 3. The hosted vault widget for card-capable sessions.
447
+ 3. The hosted vault widget for sessions with embedded vault HTML or an explicit
448
+ Stripe `card` capability.
436
449
 
437
450
  Wallets, APMs, and PayPal create intents through
438
451
  `POST /v1/checkouts/sessions/{id}/intents`. The discriminated request separates
@@ -441,9 +454,13 @@ requests are unsupported. Client-observed non-card failures use the
441
454
  nonce-protected session decline endpoint and contain no payment tokens,
442
455
  provider object IDs, card data, credentials, or PII.
443
456
 
444
- If a card-capable backend omits the vault block, card checkout stays hidden.
445
- Advertised non-card methods remain usable; if none remain,
446
- `onError` receives `UnsupportedBackendVaultCapability`.
457
+ For SDK 1.4.9+, an explicit Stripe `card` capability keeps card checkout
458
+ visible even when the backend omits the vault block. In `layout="buttons"`,
459
+ `POST /v1/checkouts/sessions/{id}/vault/capture` is deferred until the buyer
460
+ selects Card. An embedded block remains the preferred fast path and causes no
461
+ recovery POST. Sessions that advertise neither an embedded block nor `card`
462
+ do not call the recovery endpoint; their non-card methods remain usable, and
463
+ if none remain, `onError` receives `UnsupportedBackendVaultCapability`.
447
464
 
448
465
  #### AVS postcode validation
449
466
 
@@ -498,30 +515,34 @@ best-effort **in parallel** with the widget's charge:
498
515
 
499
516
  ### Vault PCI card form
500
517
 
501
- When the billing API returns a hosted vault card form on the session
502
- (`session.vault`), the card path renders a **backend-served, self-contained
503
- hosted vault widget** (`VaultCardFields`) (TeamFloPay/backend#823, Model A).
504
- Every card-capable session is
505
- expected to include this block without SDK-version dispatch. It is fully
506
- **server-driven** there is no consumer prop to toggle it. The widget owns the
507
- card fields, its own submit button, card tokenization, the PaymentIntent (created
508
- **and** confirmed server-side), **3DS**, and the result, so **no Stripe.js runs
509
- on the card path** and PAN / CVC never enter the SDK runtime. Wallets / PayPal /
510
- APMs render exactly as before.
518
+ The card path renders a **backend-served, self-contained hosted vault widget**
519
+ (`VaultCardFields`) (TeamFloPay/backend#823, Model A). The billing API may
520
+ return it eagerly in `session.vault`, or advertise `card` under
521
+ `gateways.stripe.enabledPaymentMethods` and let SDK 1.4.9+ request it lazily.
522
+ It is fully **server-driven** there is no consumer prop to toggle it. The
523
+ widget owns the card fields, its own submit button, card tokenization, the
524
+ PaymentIntent (created **and** confirmed server-side), **3DS**, and the result,
525
+ so **no Stripe.js runs on the card path** and PAN / CVC never enter the SDK
526
+ runtime. Wallets / PayPal / APMs render exactly as before.
511
527
 
512
528
  Because the widget owns the form, `SplitCardForm` exposes no SDK card-entry or
513
529
  card-submit controls. Host-collected AVS fields remain outside the PCI
514
530
  widget and gate its submit. The flow is:
515
531
 
516
532
  ```text
517
- session includes a hosted vault card form (session.vault)
518
- → SDK injects the widget HTML (session.vault.html, or POST /vault/capture)
533
+ session embeds session.vault or advertises gateways.stripe.enabledPaymentMethods: ['card']
534
+ → SDK uses embedded HTML, or requests POST /vault/capture when Card is needed
535
+ → concurrent renders/remounts share that active request
519
536
  → buyer pays inside the widget (tokenize → charge → 3DS, all backend-owned)
520
537
  → widget postMessages its outcome → SDK fires onComplete / onDecline / onError
521
538
  ```
522
539
 
523
- - The widget HTML normally comes from embedded `session.vault.html`; the explicit
524
- recovery/retry path is `POST /v1/checkouts/sessions/{id}/vault/capture`.
540
+ - Embedded `session.vault.html` is the preferred fast path during rollout and
541
+ never triggers a recovery request.
542
+ - Deferred capture uses
543
+ `POST /v1/checkouts/sessions/{id}/vault/capture`, with a ten-second timeout,
544
+ bounded transient-network retry, and one shared active request per
545
+ base URL/session/nonce.
525
546
  - **Returning customers** with a card on file (`session.providerPaymentMethodId`)
526
547
  are charged by the backend's auto-checkout cascade.
527
548
  - **3DS** is handled inside the widget — there is no client-side `confirmCardPayment`.
@@ -710,11 +731,11 @@ Key payment-surface props include:
710
731
  |------|------|-------------|
711
732
  | `sessionId` | `string` | Checkout session UUID. |
712
733
  | `nonce` | `string` | Session-bound token forwarded on intent, decline, account, and process calls. |
713
- | `session` | `CheckoutSession?` | Session capability data, including the hosted `vault` block and gateways. |
734
+ | `session` | `CheckoutSession?` | Session capability data, including the optional hosted `vault` fast path and gateways. |
714
735
  | `billingApiUrl` | `string` | Billing API base URL. |
715
- | `showStripe` | `boolean` | Show Stripe-backed wallets/APMs. Card checkout is controlled by the session vault capability. |
736
+ | `showStripe` | `boolean` | Show Stripe-backed wallets/APMs and the hosted card path when the session embeds `vault` or advertises `card`. |
716
737
  | `showPayPal` | `boolean` | Show PayPal. Renderer chosen by `gateways.paypal` presence (DirectPayPal JS SDK when present; Stripe-rendered PayPal otherwise). Default: `true`. |
717
- | `enabledPaymentMethods` | `string[]?` | Per-session list of Stripe method type identifiers (`apple_pay`, `google_pay`, `cashapp`, `klarna`, `link`, `amazon_pay`, `sepa_debit`, `affirm`, `ideal`, …). Normally threaded automatically from `gateways.stripe.enabledPaymentMethods` by `FloPayCheckout`. The SDK partitions it into the ExpressCheckoutElement big-button row (intersected with `STRIPE_EXPRESS_METHODS`) and the accordion PaymentElement region; `card` is always dropped because the hosted vault owns that path. |
738
+ | `enabledPaymentMethods` | `string[]?` | Per-session list of Stripe method type identifiers (`card`, `apple_pay`, `google_pay`, `cashapp`, `klarna`, `link`, `amazon_pay`, `sepa_debit`, `affirm`, `ideal`, …). Normally threaded automatically from `gateways.stripe.enabledPaymentMethods` by `FloPayCheckout`. The SDK partitions non-card methods between ExpressCheckoutElement and PaymentElement; `card` advertises the hosted-vault path and is never rendered by Stripe. |
718
739
  | `showApplePay` | `boolean` | *Deprecated.* Apple Pay availability is dashboard-controlled at Stripe and surfaces through `enabledPaymentMethods`. Emits a one-time `console.warn` when supplied alongside `enabledPaymentMethods` and is otherwise ignored. Removed in `2.0`. |
719
740
  | `showGooglePay` | `boolean` | *Deprecated.* See `showApplePay`. |
720
741
  | `directPaypal` | `{ clientId: string; environment?: GatewayEnvironment }?` | *Deprecated input on `FloPayCheckout`* — auto-resolved from `gateways.paypal` on the session response. Still accepted on `SplitCardForm` for advanced consumers wiring providers manually. |
@@ -724,6 +745,24 @@ Key payment-surface props include:
724
745
  | `onLastNameChange` | `(value: string) => void` | Last name change callback |
725
746
  | `onComplete` / `onDecline` / `onError` | callbacks | Observable checkout outcomes. |
726
747
 
748
+ #### Deferred-vault rollout boundary
749
+
750
+ SDK `1.4.9` is the compatibility boundary for omitting embedded capture
751
+ credentials. Keep the backend's current
752
+ `link session → capture → complete idempotency → 201` ordering for requests
753
+ from older or unknown SDK versions, and until the deployed `@flopay/react`
754
+ population has crossed the adoption threshold chosen by the backend rollout.
755
+ The SDK advertises its version in `x-flo-sdk-version` on session create/read.
756
+
757
+ After that threshold, the backend may omit capture credentials from
758
+ create/read/idempotent-replay responses for requests advertising SDK `>=1.4.9`,
759
+ provided the session explicitly includes `card` in
760
+ `gateways.stripe.enabledPaymentMethods` and the nonce-protected
761
+ `POST /v1/checkouts/sessions/{id}/vault/capture` route remains available.
762
+ Backend rollout verification should confirm that create/read/replay no longer
763
+ invoke PCIVault and that capture issuance occurs only through the deferred
764
+ endpoint when a buyer enters the card path.
765
+
727
766
  ### ElementComponentProps (shared by all element components)
728
767
 
729
768
  | Prop | Type | Description |