React Integration - Basic Setup

Learn how to integrate Bloque Payments into your React application using the BloqueCheckout component.

Installation

Install the React components package:

npm install @bloque/payments-react
# or
yarn add @bloque/payments-react
# or
pnpm add @bloque/payments-react
# or
bun add @bloque/payments-react

SDK Initialization

Before using the BloqueCheckout component, you need to initialize the SDK with your Public API Key:

import { init } from '@bloque/payments-react';

// Initialize once at the start of your application (e.g., in main.tsx or App.tsx)
init({
  publicApiKey: 'pk_live_...',
  mode: 'sandbox', // or 'production'
});
Public API Key

Use your Public API Key to initialize the SDK in the frontend. This key is safe to expose in client-side code. Your Secret API Key should only be used on the backend.

Basic Component Usage

The simplest way to add payments to your React app. The component processes payments directly with the Bloque API:

import { init, BloqueCheckout } from '@bloque/payments-react';

// Initialize once at the start of your application
init({
  publicApiKey: 'pk_live_...',
  mode: 'production',
});

function CheckoutPage() {
  return (
    <BloqueCheckout
      config={{
        payment_methods: ['card', 'pse', 'cash'],
        amount: 2999,
        currency: 'USD',
      }}
      onSuccess={(response) => {
        console.log('Payment successful!', response.id);
        window.location.href = '/success';
      }}
      onError={(error) => {
        console.error('Payment failed:', error.message);
        alert(`Payment failed: ${error.message}`);
      }}
    />
  );
}

export default CheckoutPage;

Usage with Custom Backend

If you prefer to process payments through your own backend, use the onSubmit prop:

import { BloqueCheckout } from '@bloque/payments-react';

function CheckoutPage() {
  const handleSubmit = async (payload) => {
    const response = await fetch('/api/payments', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      throw new Error('Payment failed');
    }

    return response.json();
  };

  return (
    <BloqueCheckout
      config={{
        payment_methods: ['card', 'pse', 'cash'],
        amount: 2999,
        currency: 'USD',
      }}
      onSubmit={handleSubmit}
      onSuccess={(response) => {
        console.log('Payment successful!', response.id);
        window.location.href = '/success';
      }}
      onError={(error) => {
        console.error('Payment failed:', error.message);
        alert(`Payment failed: ${error.message}`);
      }}
    />
  );
}

export default CheckoutPage;

Component Props

Optional Props

onSubmit

Function called when the user submits the payment form. If not provided, the component processes the payment directly with the Bloque API.

onSubmit?: (payload: PaymentSubmitPayload) => Promise<PaymentResponse | undefined>;

Example:

const handleSubmit = async (payload) => {
  const response = await fetch('/api/payments', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    throw new Error('Payment failed');
  }

  return response.json();
};

<BloqueCheckout onSubmit={handleSubmit} />

Optional Props

config

Configuration object for the checkout experience:

interface CheckoutConfig {
  payment_methods?: PaymentMethodType[];  // ['card', 'pse', 'cash']
  amount?: number;                         // Amount in smallest currency unit
  currency?: string;                       // Currency code (e.g., 'USD')
  labels?: CheckoutLabels;                 // Custom text labels
}

Example:

<BloqueCheckout
  config={{
    payment_methods: ['card', 'pse'],
    amount: 2999,
    currency: 'USD',
  }}
  onSubmit={handleSubmit}
/>

config.labels

Customize the payment form text labels:

interface CheckoutLabels {
  card?: CardFormLabels;
  pse?: PSEFormLabels;
  cash?: CashFormLabels;
}

interface CardFormLabels {
  cardNumber?: string;
  cardNumberPlaceholder?: string;
  cardholderName?: string;
  cardholderNamePlaceholder?: string;
  expiryDate?: string;
  expiryDatePlaceholder?: string;
  cvv?: string;
  cvvPlaceholder?: string;
  email?: string;
  emailPlaceholder?: string;
  submitButton?: string;
}

Example with custom labels:

<BloqueCheckout
  config={{
    payment_methods: ['card', 'pse'],
    amount: 4999,
    currency: 'USD',
    labels: {
      card: {
        cardNumber: 'Card Number',
        cardNumberPlaceholder: '1234 5678 9012 3456',
        cardholderName: 'Cardholder Name',
        cardholderNamePlaceholder: 'JOHN DOE',
        expiryDate: 'Expiry Date',
        expiryDatePlaceholder: 'MM/YY',
        cvv: 'CVV',
        cvvPlaceholder: '123',
        email: 'Email',
        emailPlaceholder: 'example@email.com',
        submitButton: 'Pay $49.99',
      },
    },
  }}
  onSubmit={handleSubmit}
/>

appearance

Customize the visual appearance:

interface AppearanceConfig {
  primaryColor?: string;    // Brand color
  borderRadius?: string;    // Border radius for inputs
  fontFamily?: string;      // Font family
}

Example:

<BloqueCheckout
  config={config}
  appearance={{
    primaryColor: '#10b981',
    borderRadius: '12px',
    fontFamily: 'Inter, system-ui, sans-serif',
  }}
  onSubmit={handleSubmit}
/>

amount

Alternative way to set the amount (instead of using config.amount):

<BloqueCheckout
  amount={2999}
  config={{
    payment_methods: ['card'],
    currency: 'USD',
  }}
  onSubmit={handleSubmit}
/>

availableMethods

Array of payment methods to show (alternative to config.payment_methods):

<BloqueCheckout
  availableMethods={['card', 'pse']}
  onSubmit={handleSubmit}
/>

requireEmail

Whether email is required for card payments (default: true):

<BloqueCheckout
  requireEmail={true}
  config={{ payment_methods: ['card'] }}
  onSubmit={handleSubmit}
/>

showMethodSelector

Show/hide the payment method selector (default: true):

<BloqueCheckout
  showMethodSelector={true}
  config={{ payment_methods: ['card', 'pse'] }}
  onSubmit={handleSubmit}
/>

onSuccess

Callback fired when payment succeeds:

<BloqueCheckout
  config={config}
  onSubmit={handleSubmit}
  onSuccess={(response) => {
    console.log('Payment successful!');
    console.log('Payment ID:', response.id);
    console.log('Status:', response.status);
    window.location.href = '/success';
  }}
/>

onError

Callback fired when payment fails:

<BloqueCheckout
  config={config}
  onSubmit={handleSubmit}
  onError={(error) => {
    console.error('Payment failed:', error.message);
    alert(`Payment failed: ${error.message}`);
  }}
/>

className and style

Standard React props for styling:

<BloqueCheckout
  config={config}
  onSubmit={handleSubmit}
  className="my-checkout"
  style={{ maxWidth: '600px', margin: '0 auto' }}
/>

Complete Example

Here's a complete example with all common options:

import { BloqueCheckout } from '@bloque/payments-react';
import type {
  CheckoutConfig,
  AppearanceConfig,
  PaymentResponse,
} from '@bloque/payments-react';

function CheckoutPage() {
  // Configuration
  const config: CheckoutConfig = {
    payment_methods: ['card', 'pse', 'cash'],
    amount: 2999,
    currency: 'USD',
  };

  // Appearance
  const appearance: AppearanceConfig = {
    primaryColor: '#10b981',
    borderRadius: '12px',
    fontFamily: 'Inter, system-ui, sans-serif',
  };

  // Submit handler
  const handleSubmit = async (payload) => {
    try {
      const response = await fetch('/api/payments', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.message || 'Payment failed');
      }

      return response.json();
    } catch (error) {
      console.error('Payment error:', error);
      throw error;
    }
  };

  // Success handler
  const handleSuccess = (response: PaymentResponse) => {
    console.log('Payment successful!');
    console.log('Payment ID:', response.id);
    console.log('Status:', response.status);
    window.location.href = `/success?payment=${response.id}`;
  };

  // Error handler
  const handleError = (error: { message: string }) => {
    console.error('Payment failed:', error.message);
    alert(`Payment failed: ${error.message}`);
  };

  return (
    <div className="checkout-container">
      <h1>Checkout</h1>
      <BloqueCheckout
        config={config}
        appearance={appearance}
        onSubmit={handleSubmit}
        onSuccess={handleSuccess}
        onError={handleError}
        className="checkout-form"
        style={{ maxWidth: '600px' }}
      />
    </div>
  );
}

export default CheckoutPage;

TypeScript Support

The package includes full TypeScript definitions:

import type {
  BloqueCheckoutProps,
  CheckoutConfig,
  AppearanceConfig,
  PaymentResponse,
  PaymentSubmitPayload,
  PaymentMethodType,
} from '@bloque/payments-react';

// Type-safe configuration
const config: CheckoutConfig = {
  payment_methods: ['card', 'pse'],
  amount: 2999,
  currency: 'USD',
};

// Type-safe handlers
const handleSuccess = (response: PaymentResponse) => {
  console.log('Payment ID:', response.id);
};

Framework-Specific Examples

Next.js App Router

'use client';

import { BloqueCheckout } from '@bloque/payments-react';

export default function CheckoutPage() {
  const handleSubmit = async (payload) => {
    const response = await fetch('/api/payments', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });
    return response.json();
  };

  return (
    <BloqueCheckout
      config={{
        payment_methods: ['card', 'pse'],
        amount: 2999,
        currency: 'USD',
      }}
      onSubmit={handleSubmit}
    />
  );
}

Next.js Pages Router

import { BloqueCheckout } from '@bloque/payments-react';

export default function Checkout() {
  const handleSubmit = async (payload) => {
    const response = await fetch('/api/payments', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });
    return response.json();
  };

  return (
    <BloqueCheckout
      config={{
        payment_methods: ['card'],
        amount: 2999,
        currency: 'USD',
      }}
      onSubmit={handleSubmit}
    />
  );
}

Vite + React

import { BloqueCheckout } from '@bloque/payments-react';

function App() {
  const handleSubmit = async (payload) => {
    const response = await fetch('http://localhost:3000/api/payments', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });
    return response.json();
  };

  return (
    <BloqueCheckout
      config={{
        payment_methods: ['card', 'pse', 'cash'],
        amount: 2999,
        currency: 'USD',
      }}
      onSubmit={handleSubmit}
    />
  );
}

export default App;

Next Steps