React and Next.js component
Drop the generated NervixPayCheckout component into a React or Next.js app and keep payment fulfillment bound to a purchase your server created.
Step 1: Add the component file
Save this as
components/nervixpay-checkout.tsx. It has no dependencies besides React. In the dashboard, choose the React / Next.js format on your embed to get it with your link id filled in.components/nervixpay-checkout.tsx 'use client' import { useEffect, useRef, useState } from 'react' import type { CSSProperties } from 'react' const NERVIXPAY_RESIZE_MESSAGE = 'lumenpay:resize' const NERVIXPAY_CHECKOUT_URL = "https://nervixpay.live/l/YOUR-LINK-ID" const INITIAL_SIZE = { card: { width: 420, height: 640 }, inline: { width: 420, height: 84 }, button: { width: 180, height: 60 } } function checkoutSrc(mode: string, customerReference?: string, customerEmail?: string) { const url = new URL(NERVIXPAY_CHECKOUT_URL) url.searchParams.set('mode', mode) if (customerReference) url.searchParams.set('ref', customerReference) if (customerEmail) url.searchParams.set('email', customerEmail) return url.toString() } export function NervixPayCheckout({ mode = 'card', customerReference, customerEmail, className, style, }: { mode?: 'card' | 'inline' | 'button' /** Your own id for the signed-in user; returned on the payment and in the webhook. */ customerReference?: string customerEmail?: string className?: string style?: CSSProperties }) { const frameRef = useRef<HTMLIFrameElement>(null) const [size, setSize] = useState(INITIAL_SIZE[mode]) useEffect(() => { setSize(INITIAL_SIZE[mode]) }, [mode]) useEffect(() => { function onMessage(event: MessageEvent) { if (event.origin !== new URL(NERVIXPAY_CHECKOUT_URL).origin || event.source !== frameRef.current?.contentWindow) return if (!event.data || event.data.type !== NERVIXPAY_RESIZE_MESSAGE) return const { height, width } = event.data setSize((prev) => ({ height: Number.isFinite(height) && height > 0 && height <= 10000 ? height : prev.height, width: Number.isFinite(width) && width > 0 && width <= 4000 ? width : prev.width, })) } window.addEventListener('message', onMessage) return () => window.removeEventListener('message', onMessage) }, []) return ( <iframe ref={frameRef} src={checkoutSrc(mode, customerReference, customerEmail)} width={size.width} height={size.height} title="Pay with NervixPay" className={className} style={{ border: 0, maxWidth: 'calc(100vw - 48px)', maxHeight: 'calc(100dvh - 48px)', borderRadius: mode === 'button' ? 0 : 16, ...(mode === 'button' ? { position: 'fixed', bottom: 24, right: 24, zIndex: 2147483000 } : {}), ...style, }} /> ) }Step 2: Render it for the signed-in user
customerReferenceis optional reconciliation metadata;customerEmailis optional. Both come back on the payment and in the webhook, but the customer controls the browser and can alter either value.app/checkout/page.tsx // app/checkout/page.tsx (Next.js App Router) import { NervixPayCheckout } from '@/components/nervixpay-checkout' import { getCurrentUser } from '@/lib/auth' // your own session helper export default async function CheckoutPage() { const user = await getCurrentUser() return ( <main> <h1>Upgrade to Pro</h1> <NervixPayCheckout customerReference={user.id} customerEmail={user.email} /> </main> ) }Step 3: Fulfil the purchase on your server
Before showing checkout, create a pending purchase in your authenticated backend and bind it to the signed-in user. When the signed payment.paid webhook arrives, match its NervixPay order or payment-link context to that server-side purchase, verify the expected amount and item, then fulfil it. Never choose the account to credit from
customerReference,customerEmailor a browser message.
- The component is a client component (
'use client'), so it works inside Server Components pages. - Pass
mode="inline"ormode="button"for the other layouts. - It only listens to resize messages coming from the NervixPay checkout iframe itself.