Helpers
Configuration, display, validation, and currency helper functions exported by @flopay/shared.
configureFlopay
Configure the FloPay SDK globally. Call once at app startup to set the environment.
function configureFlopay(config: { environment: FloPayEnvironment }): void| Parameter | Type | Required | Description |
|---|---|---|---|
config.environment | 'staging' | 'production' | Yes | The environment to use. |
import { configureFlopay } from '@flopay/shared';
// In production
configureFlopay({ environment: 'production' });
// In staging/development
configureFlopay({ environment: 'staging' });resolveBillingApiUrl
Resolves the billing API URL from available configuration.
function resolveBillingApiUrl(billingApiUrl?: string): string| Parameter | Type | Required | Description |
|---|---|---|---|
billingApiUrl | string | No | Explicit override (highest priority). |
Resolution priority:
- Explicit
billingApiUrlparameter configureFlopay()global environment- Fallback: staging
import { resolveBillingApiUrl } from '@flopay/shared';
// No args — reads from configureFlopay() or falls back to staging
const url = resolveBillingApiUrl();
// Explicit override
const url = resolveBillingApiUrl('https://custom.example.com');buildCheckoutDisplayData
Builds display data from a CheckoutSession for rendering an order summary.
function buildCheckoutDisplayData(
session: CheckoutSession,
options?: BuildCheckoutDisplayDataOptions,
): CheckoutDisplayData| Parameter | Type | Required | Description |
|---|---|---|---|
session | CheckoutSession | Yes | The checkout session (from useCheckout() or PaymentAPI). |
options | BuildCheckoutDisplayDataOptions | No | Display options. Defaults to {}. |
Returns: CheckoutDisplayData with computed items, totals, discounts, and currency.
import { buildCheckoutDisplayData } from '@flopay/shared';
const display = buildCheckoutDisplayData(session);
display.items; // [{ name: 'Starter', price: 24.95, originalPrice: 24.95, quantity: 1 }]
display.currency; // 'EUR'
display.total; // 24.95
display.originalTotal; // 24.95
display.totalSave; // 0
display.discountPercent; // 0BuildCheckoutDisplayDataOptions
| Field | Type | Default | Description |
|---|---|---|---|
hideBundledItems | boolean | false | When true, items are hidden from the summary if the session also contains subscriptions (legacy checkout/CheckoutModal behavior). Defaults to false -- items are always shown alongside subscriptions. |
// Default -- items show alongside subscriptions
buildCheckoutDisplayData(session);
// Legacy behavior -- hide bundled items when the session has subscriptions too
buildCheckoutDisplayData(session, { hideBundledItems: true });How prices are resolved
totalAmountis the original/base priceoverrideAmount(when notnull/undefined) is the backend-computed per-line override- An
overrideAmountof0is honored as a zero-price line — for example a free-trial subscription, which the backend sets to0
All amounts are in major currency units (dollars, not cents).
buildCheckoutDisplayData reads from session.products[] (the unified shape from billing API v1.1.3+). It partitions internally so subscriptions are listed first, then items.
The backend resolves product name and totalAmount from the catalog and may omit them on the session response. Use cacheSessionDisplayData to carry those values across the create -> redirect -> fetch round-trip; the SDK merges them back into products[] automatically before this helper sees it. overrideAmount is computed by the backend and needs no caching.
CheckoutDisplayData
| Field | Type | Description |
|---|---|---|
items | DisplayLineItem[] | Individual items/subscriptions with names, prices, and quantities. |
currency | string | ISO 4217 currency code (uppercase). |
total | number | Total amount due after discounts (major units). |
originalTotal | number | Sum of original prices before discounts (major units). |
totalSave | number | Total savings (originalTotal - total), clamped to >= 0. |
discountPercent | number | Discount percentage (0--100). |
DisplayLineItem
| Field | Type | Description |
|---|---|---|
name | string | Item or subscription name. |
quantity | number | Quantity purchased. |
price | number | Price per unit after discount (major units). |
originalPrice | number | Original price per unit before discount (major units). |
Example: order summary
import { buildCheckoutDisplayData } from '@flopay/shared';
import { useCheckout } from '@flopay/react';
function OrderSummary() {
const { session } = useCheckout();
if (!session) return null;
const { items, currency, total, totalSave, discountPercent } = buildCheckoutDisplayData(session);
const fmt = (n: number) =>
new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(n);
return (
<div>
{items.map((item, i) => (
<div key={i}>
<span>{item.name} (x{item.quantity})</span>
<span>{fmt(item.originalPrice)}</span>
</div>
))}
{totalSave > 0 && <div>{discountPercent}% OFF — you save {fmt(totalSave)}</div>}
<div>Total: {fmt(total)}</div>
</div>
);
}getCurrencyByCountry
Look up currency information by ISO 3166-1 alpha-2 country code. Falls back to USD when the country is not in the map.
function getCurrencyByCountry(countryCode: string): CurrencyInfo| Parameter | Type | Required | Description |
|---|---|---|---|
countryCode | string | Yes | ISO 3166-1 alpha-2 country code (case-insensitive). |
Returns: CurrencyInfo -- the currency info for the given country, or DEFAULT_CURRENCY (USD) if not found.
import { getCurrencyByCountry } from '@flopay/shared';
getCurrencyByCountry('DE');
// { currency: 'EUR', symbol: '\u20ac', country: 'Germany', countryCode: 'DE', tax: 1 }
getCurrencyByCountry('US');
// { currency: 'USD', symbol: '$', country: 'United States', countryCode: 'US', tax: 0 }
getCurrencyByCountry('XX');
// Falls back to DEFAULT_CURRENCY (USD)AVS Helpers
resolveAVSConfig
Normalizes the enableAVS prop value into a concrete AVSFieldConfig object (or null when AVS is disabled).
function resolveAVSConfig(enableAVS?: boolean | AVSFieldConfig): AVSFieldConfig | null| Input | Output |
|---|---|
false / undefined | null |
true | { country: true, postal_code: true } (the legacy default) |
AVSFieldConfig | The same object, returned as-is |
import { resolveAVSConfig } from '@flopay/shared';
resolveAVSConfig(true); // { country: true, postal_code: true }
resolveAVSConfig(false); // null
resolveAVSConfig({ country: true }); // { country: true }isAVSFieldVisible
Returns true if a given field should be visible for the given country, given a per-field rule.
function isAVSFieldVisible(
field: boolean | string[] | undefined,
country: string,
): booleanCountry codes are normalized (case- and whitespace-insensitive), so ['us', ' ca '] matches 'US', 'CA', 'us', etc.
import { isAVSFieldVisible } from '@flopay/shared';
isAVSFieldVisible(true, 'XX'); // true (always visible)
isAVSFieldVisible(false, 'US'); // false
isAVSFieldVisible(undefined, 'US'); // false
isAVSFieldVisible(['US', 'CA'], 'us'); // true
isAVSFieldVisible(['US', 'CA'], 'GB'); // falseisAVSEnabled
Returns true if any AVS field is meaningfully configured. Use this to derive the avsCheck analytics boolean from a raw enableAVS prop value.
function isAVSEnabled(enableAVS?: boolean | AVSFieldConfig): booleanimport { isAVSEnabled } from '@flopay/shared';
isAVSEnabled(true); // true
isAVSEnabled(false); // false
isAVSEnabled(undefined); // false
isAVSEnabled({}); // false (no fields configured)
isAVSEnabled({ country: true }); // true
isAVSEnabled({ city: ['US'] }); // truegetStateOptions
Returns the list of states/provinces for a country, or null for countries that should fall back to a free-text input.
function getStateOptions(country: string): StateOption[] | nullStateOption is { code: string; name: string }. Currently returns US_STATES for 'US' and CA_PROVINCES for 'CA'; all other country codes return null.
import { getStateOptions } from '@flopay/shared';
getStateOptions('US'); // [{ code: 'AL', name: 'Alabama' }, …] (51 entries incl. DC)
getStateOptions('CA'); // [{ code: 'AB', name: 'Alberta' }, …] (13 entries)
getStateOptions('GB'); // nullgetStateLabel
Returns the user-facing label for the state/province field based on country.
function getStateLabel(countryCode: string): string| Country | Label |
|---|---|
US | 'State' |
CA | 'Province' |
GB | 'County' |
AU | 'State / Territory' |
| All others | 'State / Province / Region' |
getStateFromPostalCode
Resolves a state / province code from a postal code for the given country.
function getStateFromPostalCode(
country: string,
postalCode: string,
): string | null| Country | Resolution |
|---|---|
US | 5-digit ZIP → 2-letter USPS state code via the 3-digit SCF prefix table. Handles ZIP+4 format. |
CA | A1A 1A1 → 2-letter ISO 3166-2:CA province code via the FSA first letter. X resolves to NT (shared with NU). |
| Others | Returns null |
Used by SplitCardForm to populate billing_details.address.state when the form collects address_line_1 and postal_code but hides the state input. See the AVS guide for the trigger condition.
import { getStateFromPostalCode } from '@flopay/shared';
getStateFromPostalCode('US', '90210'); // 'CA'
getStateFromPostalCode('US', '10001-9999'); // 'NY' (ZIP+4)
getStateFromPostalCode('CA', 'M5V 2T6'); // 'ON'
getStateFromPostalCode('CA', 'm5v2t6'); // 'ON' (case-insensitive, compact)
getStateFromPostalCode('GB', 'SW1A 1AA'); // null
getStateFromPostalCode('US', '71500'); // null (unmapped 3-digit prefix)getPostalCodeLabel
Returns the user-facing label for the postal code field based on country.
function getPostalCodeLabel(countryCode: string): string| Country | Label |
|---|---|
US | 'ZIP Code' |
GB, AU, NZ | 'Postcode' |
CA | 'Postal Code' |
IE | 'Eircode' |
| All others | 'Postal Code' |
getCountryByCode
Look up a country option by ISO 3166-1 alpha-2 code. Returns undefined if not found.
function getCountryByCode(code: string): CountryOption | undefinedimport { getCountryByCode } from '@flopay/shared';
getCountryByCode('DE'); // { code: 'DE', name: 'Germany', flag: '🇩🇪' }
getCountryByCode('XX'); // undefinedisValidPublishableKey
Returns true if the string matches the format of a Stripe publishable key.
function isValidPublishableKey(key: string): boolean| Parameter | Type | Required | Description |
|---|---|---|---|
key | string | Yes | The key to validate. |
Returns: boolean -- true if the key matches /^pk_(test|live)_[A-Za-z0-9]+$/.
import { isValidPublishableKey } from '@flopay/shared';
isValidPublishableKey('pk_test_abc123'); // true
isValidPublishableKey('pk_live_XYZ789'); // true
isValidPublishableKey('sk_test_abc123'); // false
isValidPublishableKey('invalid'); // falseisValidSecretKey
Returns true if the string matches the format of a Stripe secret key.
function isValidSecretKey(key: string): boolean| Parameter | Type | Required | Description |
|---|---|---|---|
key | string | Yes | The key to validate. |
Returns: boolean -- true if the key matches /^sk_(test|live)_[A-Za-z0-9]+$/.
import { isValidSecretKey } from '@flopay/shared';
isValidSecretKey('sk_test_abc123'); // true
isValidSecretKey('sk_live_XYZ789'); // true
isValidSecretKey('pk_test_abc123'); // false