Skip to main content
The @lavapayments/checkout package provides a React hook for embedding Lava’s checkout flow as a full-screen iframe overlay. It handles the complete payment flow — phone verification, payment setup, and subscription creation.

Installation

npm install @lavapayments/checkout
Requirements: React 16.8+ (hooks support)

How It Works

Checkout is a two-step flow:
  1. Your backend creates a checkout session using the Node.js SDK, which returns a checkout_session_token
  2. Your frontend passes that token to open(), which renders the checkout as a full-screen iframe overlay
Your secret key is never exposed to the browser — session creation always happens server-side.

Checkout Modes

The checkout mode is set when creating the session on your backend, not in the React hook. See Checkout for full details on each mode.
ModePurposeRequired Params
subscriptionSubscribe to a recurring plansubscription_config_id
credit_bundleBuy a fixed credit packconnection_id, credit_bundle_id

useLavaCheckout

The SDK exports a single hook: useLavaCheckout. It returns an open function that launches the checkout iframe.
const { open } = useLavaCheckout({
  onSuccess: ({ checkoutSessionId, connectionId }) => {
    // Checkout completed — connectionId is the billing relationship ID.
    // Store it in your database linked to your user.
  },
  onCancel: ({ checkoutSessionId }) => {
    // User closed the checkout overlay without completing.
  },
  onError: ({ checkoutSessionId, error }) => {
    // Session token is invalid or malformed.
  },
});

// Pass the checkout_session_token created by your backend (see below).
open(checkoutSessionToken);
All callbacks are optional.
onSuccess is the easiest way to capture the connectionId, but the user can close their browser before it fires. For reliable server-side capture, use the connection.created webhook. In production, use both: the callback for instant UI feedback, the webhook for backend persistence.

Behavior

  • open() renders a full-screen fixed iframe (z-index: 2147483647) over your app
  • The iframe is sandboxed with allow-forms allow-scripts allow-same-origin
  • A beforeunload handler warns users if they try to navigate away mid-checkout
  • The iframe is automatically removed when checkout completes or is cancelled

Full Example

1. Backend — create a checkout session (Next.js route handler)

Use the @lavapayments/nodejs SDK to create a session. The SDK returns a checkout_session_token that you pass to your frontend.
import { Lava } from '@lavapayments/nodejs';

const lava = new Lava(); // reads LAVA_SECRET_KEY from env

export async function POST(request: Request) {
  const { subscription_config_id } = await request.json();

  const session = await lava.checkoutSessions.create({
    checkout_mode: 'subscription',
    origin_url: 'https://yourapp.com',
    subscription_config_id,
  });

  return Response.json({
    checkoutSessionToken: session.checkout_session_token,
  });
}

2. Frontend — open checkout with the session token

'use client'; // Next.js App Router

import { useLavaCheckout } from '@lavapayments/checkout';
import { useState } from 'react';

export function SubscribeButton({ planId }: { planId: string }) {
  const [loading, setLoading] = useState(false);

  const { open } = useLavaCheckout({
    onSuccess: ({ connectionId }) => {
      // Store connectionId in your database, linked to your user
      fetch('/api/save-connection', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ connectionId }),
      });
    },
    onCancel: () => {
      // User closed checkout without completing
    },
  });

  async function handleClick() {
    setLoading(true);
    try {
      // Call your backend to create a checkout session
      const res = await fetch('/api/checkout', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ subscription_config_id: planId }),
      });
      const { checkoutSessionToken } = await res.json();

      // Open the checkout iframe with the token from your backend
      open(checkoutSessionToken);
    } finally {
      setLoading(false);
    }
  }

  return (
    <button onClick={handleClick} disabled={loading}>
      {loading ? 'Loading...' : 'Subscribe'}
    </button>
  );
}

Next Steps