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:
| Field | Type | Description |
|---|---|---|
products | array | List of products: name, price (in cents, tax-excluded), quantity |
currency | string | EUR or USD |
customerEmail | string | Customer's email address |
billingCountry | string | ISO 3166-1 alpha-2 country code (e.g. FR, DE, US) |
purchasingAsBusiness | boolean | true 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
| Prop | Type | Required | Description |
|---|---|---|---|
config.publicKey | string | Yes | Your public API key (inflow_pub_xxx) |
config.locale | string | No | UI language: en, de, es, fr, it, nl, pl, pt (defaults to browser language) |
CardElement Props
| Prop | Type | Required | Description |
|---|---|---|---|
paymentId | string | Yes* | Payment ID from your backend |
setupId | string | Yes* | Setup request ID for saving a card without charging (free trials, save-card) — see Free Trial & Card Setup |
onComplete | function | No | Called when payment completes (success or failure) |
onError | function | No | Called on SDK-level errors |
onReady | function | No | Called when the card form is mounted and ready |
onChange | function | No | Called when form validation state changes |
appearance | object | No | Theme tokens and fonts (see Styling & Customization) |
options | object | No | Layout, width, card / wallet button labels and color (wallets.buttonTheme), placeholders, success UI (see Styling & Customization) |
style | object | No | Deprecated. Legacy styling — use appearance. Still applied when appearance is omitted |
buttonText | string | No | Deprecated. Use options.buttonText |
placeholders | object | No | Deprecated. Use options.cardForm.placeholders |
showDefaultSuccessUI | boolean | No | Deprecated. 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.
Updated 18 days ago