React Integration

Setup

Import the React components from the SDK:

import { InflowPayProvider, CardElement, PaymentResultStatus } from '@inflow_pay/sdk/react';

Complete Example

Step 1: Create a Payment (Backend)

From your backend, create the payment with your private API key on POST /api/server/payment (default base URL, no card field — the SDK collects the card). See the two-step flow for why this endpoint is the right one for SDK integrations.

The /api/create-payment route below is an endpoint of your own backend — name it whatever you like; its job is to call the Inflow API server-side and return the paymentId to your frontend:

app.post('/api/create-payment', async (req, res) => {
  const response = await fetch('https://api.inflowpay.xyz/api/server/payment', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Inflow-Api-Key': process.env.INFLOW_PRIVATE_KEY
    },
    body: JSON.stringify({
      products: [{ name: 'Pro Plan', price: 4999, quantity: 1 }],
      currency: 'EUR',
      customerEmail: req.body.email,
      billingCountry: req.body.country,
      purchasingAsBusiness: false,
      firstName: 'John',
      lastName: 'Doe',
    })
  });

  const data = await response.json();
  res.json({ paymentId: data.id });
});

Required fields for the payment creation call:

FieldTypeDescription
productsarrayList of products: name, price (in cents, tax-excluded), quantity
currencystringEUR or USD
customerEmailstringCustomer's email address
billingCountrystringISO 3166-1 alpha-2 country code (e.g. FR, DE, US)
purchasingAsBusinessbooleantrue requires businessName and taxId; US customers also need postalCode

firstName / lastName are optional but strongly recommended — they improve 3D Secure success rates. Full list of optional fields (metadata, capture mode, pricing mode, …) in the endpoint reference and the Server-to-Server guide.

Step 2: Render the Card Form (Frontend)

import { useState, useEffect } from 'react';
import { InflowPayProvider, CardElement, PaymentResultStatus } from '@inflow_pay/sdk/react';

function Checkout() {
  const [paymentId, setPaymentId] = useState<string | null>(null);

  useEffect(() => {
    fetch('/api/create-payment', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email: '[email protected]', country: 'FR' })
    })
      .then(res => res.json())
      .then(data => setPaymentId(data.paymentId));
  }, []);

  if (!paymentId) return <div>Loading...</div>;

  return (
    <InflowPayProvider config={{ publicKey: 'inflow_pub_xxx' }}>
      <CardElement
        paymentId={paymentId}
        onComplete={(result) => {
          if (result.status === PaymentResultStatus.SUCCESS) {
            setTimeout(() => window.location.href = '/confirmation', 2000);
          }
          if (result.error) {
            console.error(result.error.message);
          }
        }}
        appearance={{
          variables: {
            fontFamily: 'Inter, system-ui, sans-serif',
            primaryColor: '#0070F3',
            buttonBackgroundColor: '#0070F3',
            buttonTextColor: '#FFFFFF',
          },
        }}
        options={{
          paymentMethodLayout: 'horizontalSelector',
          paymentMethodOrder: ['apple_pay', 'google_pay', 'card'],
          cardFieldLayout: 'compact',
          buttonText: 'Pay €49.99',
          wallets: {
            buttonText: {
              applePay: 'Pay with Apple Pay',
              googlePay: 'Pay with Google Pay',
            },
            // buttonTheme: 'white', // default is black — set 'white' for dark surfaces
          },
        }}
      />
    </InflowPayProvider>
  );
}

See Styling & Customization for the full appearance and options reference.

InflowPayProvider Props

PropTypeRequiredDescription
config.publicKeystringYesYour public API key (inflow_pub_xxx)
config.localestringNoUI language: en, de, es, fr, it, nl, pl, pt (defaults to browser language)

CardElement Props

PropTypeRequiredDescription
paymentIdstringYes*Payment ID from your backend
setupIdstringYes*Setup request ID for saving a card without charging (free trials, save-card) — see Free Trial & Card Setup
onCompletefunctionNoCalled when payment completes (success or failure)
onErrorfunctionNoCalled on SDK-level errors
onReadyfunctionNoCalled when the card form is mounted and ready
onChangefunctionNoCalled when form validation state changes
appearanceobjectNoTheme tokens and fonts (see Styling & Customization)
optionsobjectNoLayout, width, card / wallet button labels and color (wallets.buttonTheme), placeholders, success UI (see Styling & Customization)
styleobjectNoDeprecated. Legacy styling — use appearance. Still applied when appearance is omitted
buttonTextstringNoDeprecated. Use options.buttonText
placeholdersobjectNoDeprecated. Use options.cardForm.placeholders
showDefaultSuccessUIbooleanNoDeprecated. Use options.showDefaultSuccessUI (default: true)

* Provide exactly one of paymentId (charge now) or setupId (save card, no charge) — they are mutually exclusive.

Legacy style / top-level copy props remain fully supported for compatibility.

Payment Result

interface PaymentResult {
  status: 'SUCCESS' | 'FAILED';
  paymentId: string;
  error?: {
    code: string;
    message: string;
    retryable: boolean;
  };
}

Next.js

For Next.js App Router, use the 'use client' directive:

'use client';

import { InflowPayProvider, CardElement } from '@inflow_pay/sdk/react';

The SDK API may evolve. Refer to the npm package for the latest props and types.


Did this page help you?