FloPayFloPay
API Reference@flopay/js

PaymentAPI

Client-side payment API service for interacting with the billing API endpoints.

PaymentAPI

Client-side payment API service. All methods call the billing API endpoints that the checkout backend exposes.

class PaymentAPI {
  constructor(billingApiUrl: string)
}
ParameterTypeRequiredDescription
billingApiUrlstringYesBase URL of the billing API. Trailing slashes are stripped.

createAndFetchSession

Create a checkout session and resolve with the complete session data.

async createAndFetchSession(
  params: InlineSessionDraft
): Promise<NormalizedCheckoutSession>
ParameterTypeRequiredDescription
paramsInlineSessionDraftYesSession draft — client, currency, products, account, URLs.

Returns: Promise<NormalizedCheckoutSession> — one fully-populated session, with buyer identity, cart, coupons and totals attached.

Eligible sessions are created through the two-phase shell + claim flow (see createDetachedSession), and this method awaits the claim — so it resolves with the same single session either way. The win is server-side: the create no longer contends on the buyer-identity advisory locks that serialise concurrent checkouts for the same customer.

Call createDetachedSession instead when you want to render from the shell before the claim lands. Pass deferDataAttachment: false to force the original one-shot create.

Session-level currency is required. The SDK throws FloPayError({ type: 'validation_error', code: 'CurrencyRequired' }) before any network call when nothing can be resolved from the session-level field or a per-line currency.


createDetachedSession

Create a checkout session detached from its buyer and catalog data, resolving as soon as the lightweight shell exists.

async createDetachedSession(
  params: InlineSessionDraft
): Promise<DetachedCheckoutSession>
ParameterTypeRequiredDescription
paramsInlineSessionDraftYesSession draft. currency and account.country are sent on the shell create as gateway-routing inputs; everything else goes on the claim.

Returns: DetachedCheckoutSession{ shell, sessionId, nonce, claimed }.

The shell create runs no catalog validation and takes no buyer-identity advisory locks, and the backend routes a gateway for it — so shell already carries the session id, nonce, gateways and the hosted vault block. The card form can mount from it immediately.

Buyer identity, address, products and coupons are attached by the claimed promise, which is already in flight when this resolves.

const { shell, sessionId, nonce, claimed } = await api.createDetachedSession(params);

mountCardForm(shell.data.session?.vault);   // interactive immediately
const session = await claimed;              // cart, coupons, totals, buyer

Nothing may be charged until claimed settles. The billing API rejects process / intent / decline calls on an unclaimed session with 409 checkout_session_data_attachment_required, and holds an unclaimed vault charge with a retryable 503. In @flopay/react, SplitCardForm gates the card submit for exactly this window.

Throws: FloPayError with code InvalidCheckoutSessionResponse when the billing API returns no session shell. There is no fallback to the one-shot create — this method requires a backend that exposes PATCH /v1/checkouts/sessions/{id}/claim.

Endpoint: POST /v1/checkouts/sessions with deferDataAttachment: true

See the Session Creation guide for the full two-phase contract.


claimCheckoutSession

Attach buyer identity, address, products and coupons to a detached session shell.

async claimCheckoutSession(
  checkoutSessionId: string,
  nonce: string,
  payload: Record<string, unknown>
): Promise<NormalizedCheckoutSession>
ParameterTypeRequiredDescription
checkoutSessionIdstringYesThe shell's session UUID.
noncestringYesSession-bound checkout token from the shell create.
payloadRecord<string, unknown>YesClaim body — currency, products, couponCodes, accountData.

Returns: Promise<NormalizedCheckoutSession> — the fully-attached session.

Endpoint: PATCH /v1/checkouts/sessions/{checkoutSessionId}/claim

The backend fingerprints the payload, so a transport retry replaying the identical body returns the same claimed session rather than conflicting. The SDK makes up to 3 attempts against a 12s deadline (override with timeoutMs on the draft) and replays a byte-identical body each time. A materially different claim for an already-claimed session returns 409 and is surfaced without retrying.

Invalid catalog data surfaces here as the same 422 the one-shot create would have returned — later in the flow, but with identical semantics.

A fourth, optional argument carries internal telemetry plumbing when the SDK calls this itself. Integrations should pass the three arguments above.


getCheckoutSession

Fetch a raw checkout session by ID.

async getCheckoutSession(
  checkoutSessionId: string
): Promise<BillingResponse<RawCheckoutSession>>
ParameterTypeRequiredDescription
checkoutSessionIdstringYesThe checkout session UUID.

Returns: Promise<BillingResponse<RawCheckoutSession>> -- the raw billing API response.

Throws: FloPayError with type 'api_error' if the request fails.

Endpoint: GET /v1/checkouts/sessions/{checkoutSessionId}

Requires the x-checkout-session-token header — the session nonce returned by the create call. See Checkout session token.


getUnifiedCheckoutSession

Fetch and normalize a checkout session. Reads the backend's gateways map (see CheckoutGatewaysDto) and wraps the session in a NormalizedCheckoutSession. gateways.stripe populates data.stripe, and gateways.paypal populates data.paypal for the direct PayPal flow.

async getUnifiedCheckoutSession(
  checkoutSessionId: string
): Promise<NormalizedCheckoutSession>
ParameterTypeRequiredDescription
checkoutSessionIdstringYesThe checkout session UUID.

Returns: Promise<NormalizedCheckoutSession>

Display-only fields are merged from the cache. The backend resolves product name and totalAmount from the catalog and may omit them on the response. If you stashed these values via cacheSessionDisplayData right after creating the session, the SDK merges them into the returned session's products[] only where the server returned null / undefined -- server values always win. The same merge runs inside getCheckoutSession. (overrideAmount is computed by the backend, not sourced from your input; the cache only backfills it in the rare case the server omits it.)


cacheSessionDisplayData

Stash display-only fields (name, totalAmount, currency) for a session ID so the SDK can merge them back into subsequent getCheckoutSession / getUnifiedCheckoutSession calls. (overrideAmount is computed by the backend, so you don't need to stash it.)

Call this on the client immediately after the server returns a session ID, before redirecting to the checkout page. Values are written to sessionStorage (browser) with an in-memory fallback for non-browser environments.

cacheSessionDisplayData(
  sessionId: string,
  data: SessionDisplayCacheData,
  options?: { ttlMs?: number }
): void
ParameterTypeRequiredDescription
sessionIdstringYesThe checkout session UUID.
dataSessionDisplayCacheDataYesDisplay-only payload to stash.
options.ttlMsnumberNoTime-to-live in milliseconds. Defaults to a reasonable cache window; entries are pruned when the TTL elapses.
import { PaymentAPI } from '@flopay/js';

const paymentAPI = new PaymentAPI(billingApiUrl);

// After your server returns the session ID:
paymentAPI.cacheSessionDisplayData(sessionId, {
  currency: 'EUR',
  products: [
    {
      code: 'initial_charge',
      name: '7 Day Dollar Trial',
      totalAmount: 1,
    },
    {
      code: '4_week_subscription',
      name: 'Hub Membership',
      totalAmount: 24.95,
    },
  ],
});

window.location.href = redirectUrl;

The standalone function cacheSessionDisplayData is also exported from @flopay/js for use without a PaymentAPI instance.

SessionDisplayCacheData

FieldTypeDescription
currencystringSession-level currency. Falls into the response only when the server omits it.
productsSessionDisplayProduct[]Display-only fields per product, unified across items and subscriptions.

SessionDisplayProduct

FieldTypeDescription
codestringCatalog code -- preferred match key.
type'item' | 'subscription'Optional, deprecated. Not used for matching — products merge on code. The backend resolves item vs subscription from the catalog.
namestring | nullDisplay-only name for the product.
totalAmountnumberOriginal/base price (major units).
overrideAmountnumber | nullOptional. Backend-computed override (server-authoritative); the server normally supplies it. Kept here only as a cache fallback for the rare case the server omits it.
currencystringPer-line currency, used only as a fallback.

Merge rules:

  • Products match on code.
  • Cache only fills fields the server returned as null / undefined. If the backend starts returning a field again, the server value wins.

clearSessionDisplayData

Drop any cached display data for a session. Call from your success/cancel page after the payment lifecycle completes; otherwise the TTL handles cleanup.

clearSessionDisplayData(sessionId: string): void
ParameterTypeRequiredDescription
sessionIdstringYesThe checkout session UUID.
import { PaymentAPI } from '@flopay/js';

const paymentAPI = new PaymentAPI(billingApiUrl);
paymentAPI.clearSessionDisplayData(sessionId);

The standalone function clearSessionDisplayData is also exported from @flopay/js. A companion getSessionDisplayData(sessionId) is available for reading the current cache entry (returns null if nothing is cached or the TTL has elapsed).


processPayment

Submit a tokenized payment to the billing backend. The backend will either succeed, return type: '3ds_required', or return type: 'paypal_redirect_required'.

async processPayment(
  userId: string,
  data: ProcessPaymentParams
): Promise<Response>
ParameterTypeRequiredDescription
userIdstringYesUser ID, sent as x-user-id header.
dataProcessPaymentParamsYesPayment data including sessionId, tokenizedData, accountData, and optional chv.

Returns: Promise<Response> -- the raw fetch response.

Endpoint: POST /v1/checkouts/sessions/{sessionId}/process

Requires the x-checkout-session-token header — the session nonce returned by the create call. See Checkout session token.


createPaymentIntent

Create a PaymentIntent on the backend with the client's payment method attached.

async createPaymentIntent(
  sessionId: string,
  email: string,
  paymentMethodType: string,
  options?: { signal?: AbortSignal; isPaypal?: string }
): Promise<Response>
ParameterTypeRequiredDescription
sessionIdstringYesCheckout session ID.
emailstringYesUser's email.
paymentMethodTypestringYesPayment method ID or type string.
options.signalAbortSignalNoAbort signal for cancellation.
options.isPaypalstringNoSet to 'true' for PayPal payments.

Returns: Promise<Response>

Endpoint: POST /v1/checkouts/payments/intents

Requires the x-checkout-session-token header — the session nonce returned by the create call. See Checkout session token.


createSetupIntent

Create a SetupIntent for saving payment methods without an immediate charge.

async createSetupIntent(
  sessionId: string,
  email: string,
  paymentMethodType: 'card' | 'google_pay' | 'apple_pay' | 'paypal_express_checkout',
  options?: { signal?: AbortSignal }
): Promise<Response>
ParameterTypeRequiredDescription
sessionIdstringYesCheckout session ID.
emailstringYesUser's email.
paymentMethodType'card' | 'google_pay' | 'apple_pay' | 'paypal_express_checkout'YesType of payment method to set up.
options.signalAbortSignalNoAbort signal for cancellation.

Returns: Promise<Response>

Endpoint: POST /v1/checkouts/payments/setup-intents

Requires the x-checkout-session-token header — the session nonce returned by the create call. See Checkout session token.


getPaymentsByEmail

Fetch a user's prior payments by email. Used to determine if saved card UX should be shown.

async getPaymentsByEmail(
  email: string,
  options?: { signal?: AbortSignal; page?: number; limit?: number }
): Promise<{ data: Array<{ id: string }>; total: number; page: number; limit: number }>
ParameterTypeRequiredDescription
emailstringYesUser's email.
options.signalAbortSignalNoAbort signal for cancellation.
options.pagenumberNoPage number. Defaults to 1.
options.limitnumberNoResults per page. Defaults to 1.

Returns: Paginated list of payment records.

Throws: FloPayError with type 'api_error' if the request fails.

Endpoint: GET /v1/payments?email=...&page=...&limit=...&sortField=createdAt&sortDirection=DESC

On this page