Skip to content
NervixPayDocs

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.

  1. 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,
          }}
        />
      )
    }
  2. Step 2: Render it for the signed-in user

    customerReference is optional reconciliation metadata; customerEmail is 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>
      )
    }
    
  3. 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, customerEmail or a browser message.

  • The component is a client component ('use client'), so it works inside Server Components pages.
  • Pass mode="inline" or mode="button" for the other layouts.
  • It only listens to resize messages coming from the NervixPay checkout iframe itself.
React and Next.js component | NervixPay Docs