FloPayFloPay
Guides

Error Handling

Handle payment errors with FloPayError types and factory functions.

Error Handling

All errors in the FloPay SDK use the FloPayError class from @flopay/shared. It extends Error with structured fields that mirror Stripe-style error responses.

FloPayError

class FloPayError extends Error {
  readonly type: FloPayErrorType;
  readonly code?: string;
  readonly declineCode?: string;
  readonly param?: string;
}

Error Types

TypeDescription
validation_errorA required field is missing or invalid (e.g., no publishable key)
api_errorThe upstream provider or billing API returned an error
authentication_errorInvalid API key or credentials
rate_limit_errorToo many requests
network_errorNetwork connectivity failure (fetch failed)

Additional Fields

  • code -- Provider-specific error code (e.g., card_declined)
  • declineCode -- Card decline reason (e.g., insufficient_funds, lost_card)
  • param -- The parameter that caused the error (e.g., publishableKey, sessionId)

Session Lifecycle Codes

Some codes describe the state of the checkout session rather than the payment itself.

CodeStatusMeaning
checkout_session_data_attachment_required409The session is a shell whose buyer and catalog data has not been attached yet. Claim it before any process, intent, decline or vault-error call. See Session Creation.
CurrencyRequired--Thrown client-side, before any network call, when no session-level or per-line currency can be resolved.
InvalidCheckoutSessionResponse--The billing API returned no session shell for a two-phase create, so it does not support the claim endpoint.

A claim that conflicts with an earlier one also returns 409, but without the attachment-required code — the session is already attached, with a different payload. A 422 from the claim is catalog validation; inspect issues[] as described in Product Catalog.

Factory Functions

@flopay/shared exports factory functions for creating errors:

import {
  validationError,
  apiError,
  authenticationError,
  rateLimitError,
  networkError,
} from '@flopay/shared';

// Missing required field
throw validationError('sessionId is required', 'sessionId');

// Provider returned an error
throw apiError('Card was declined', 'card_declined');

// Bad credentials
throw authenticationError('Invalid publishable key');

// Too many requests
throw rateLimitError('Rate limit exceeded, retry after 30s');

// Fetch failed
throw networkError('Failed to reach billing API');

Handling Errors in Components

Both FloPayCheckout and FloPayAutomaticPaymentButton accept an onError callback:

<FloPayCheckout
  sessionId="sess_abc123"
  billingApiUrl="https://billing.example.com"
  onError={(error) => {
    switch (error.type) {
      case 'validation_error':
        // show field-level validation message
        console.error(`Validation: ${error.param} - ${error.message}`);
        break;
      case 'api_error':
        if (error.declineCode) {
          // card was declined
          console.error(`Declined: ${error.declineCode}`);
        } else {
          console.error(`API error: ${error.message}`);
        }
        break;
      case 'network_error':
        // suggest retry
        console.error('Network issue, please try again');
        break;
      default:
        console.error(error.message);
    }
  }}
  onComplete={handleComplete}
/>

Catching Errors from loadFloPay

loadFloPay throws a FloPayError if the publishable key is missing:

import { loadFloPay } from '@flopay/js';
import { FloPayError } from '@flopay/shared';

try {
  const flopay = await loadFloPay(publishableKey);
} catch (err) {
  if (err instanceof FloPayError) {
    console.error(err.type, err.param, err.message);
  }
}

FloPayError restores the prototype chain with Object.setPrototypeOf, so instanceof checks work correctly even in environments that transpile class inheritance.

On this page