Fungies.io Help Center
  • 🙌Getting Started
  • Customize your online store
    • General Settings
    • Header
    • Footer
    • Add New Page
    • Add Page Section
    • Text Section
    • Image Section
    • Video Section
    • Gallery Section
    • Points Section
    • Slider Section
    • Recent Products Section
    • Custom Style
  • Add Subscription Product
  • Add Digital Downloads
  • Add Game Keys
  • Add Mobile Game Assets
  • Variants of the product
  • 🛠️Workspace Settings
    • Connect your Stripe account
    • Sandbox Mode
    • Team Management
  • 🧮Store Settings
    • Publish your store
    • Previewing The Store
    • Edit Explore / Search Page (Built-in)
    • Edit Product Page (Built-in)
      • Customize Review Categories
    • Set up Custom Domain
      • Migrating your domain to Cloudflare
  • Tax-inclusive Pricing
  • 🤑Getting Paid
    • Test Payments
    • Checkout Choice
      • Hosted Checkout
      • Overlay Checkout
      • Embedded Checkout
    • Global Availability
    • Customer Payment Methods
      • PayPal Settings
    • Billing Details
    • Payouts
    • Editing Statement Descriptor
    • Transactions Reports
    • Example React checkout
  • 👨‍💻FOR SAAS DEVELOPERS
    • Hosted Checkout (more payment methods)
    • Editing and Pausing Subscriptions
      • Downgrading / Upgrading Subscriptions
    • Creating Plans
    • Free Trials and Custom Intervals
    • Redirecting After Purchase
    • Using Webhooks
    • Types of Webhooks
      • Payment Success
      • Payment Refunded
      • Payment Failed
      • Subscription Created
      • Subscription Interval
      • Subscription Updated
      • Subscription Cancelled
    • Getting Started with the API
    • Orders APIs
      • Managing Orders through API
      • Orders List
      • Cancel Order
      • Update Order
    • Managing Subscriptions through API
    • Managing and Creating Users through API
    • Customizing Subscription Confirmation Page
    • Using CustomFields to parse data from your Software / App
      • Parse e-mails from your Software directly to checkout URL
  • Additional charges on top of Subscriptions
  • Upgrading or Downgrading Plans with API
  • Using Fungies.js npm package
    • Next.js 15 integration guide
  • 🎮For Game Developers
    • Orders
    • Platform Fees
    • Users list
    • Integrating with Game's Back-end
    • Customizing Purchase Confirmation Page
    • Webhooks
  • 💲Selling
    • Payment history
    • Selling FREE products
    • Managing Game Keys
    • Managing Game Assets
    • Pricing
    • Fulfillment of Orders
    • Prohibited Business and Products
    • Invoices and Receipts
    • Google Merchant Center XML Feed
    • SEO Sitemap
  • 🚀Marketing
    • Integrations
      • Google Tag Manager
      • Google Merchant Center
      • Trustpilot
      • Google Analytics (via Google Tag Manager)
    • SEO
    • Discount Codes
    • Pricing Localization
    • Language Localization
    • E-mail Marketing
  • 💰Billing
    • Plans and Usage
    • Invoices
    • Payment Methods
  • 🤩For End-Users
    • How to manage your Subscription?
    • How to buy a Game Key?
    • How to buy a Mobile Game Asset?
    • Getting your product
    • Steam key activation
    • Searching for games
    • Product details page
    • Order details
    • Refunds and chargebacks
  • 🗃️Other
    • FAQ
    • Roadmap
    • Product Changelog
  • 📃Legal
    • General Terms of Use
    • SaaS Terms of Use
    • Privacy Policy
    • Cookies and Tracking
Powered by GitBook
On this page
  • Integrating Fungies with Next.js 15: A Concise Guide
  • 1. Introduction
  • 2. Getting Started with Fungies & Next.js
  • 3. Implementing Fungies Checkout
  • 4. Handling Payments & Events
  • 5. Integrating with Next.js 15 Features
  • 6. Testing & Deployment
  • 7. Conclusion
  1. Using Fungies.js npm package

Next.js 15 integration guide

PreviousUsing Fungies.js npm packageNextOrders

Last updated 1 month ago

Integrating Fungies with Next.js 15: A Concise Guide

1. Introduction

Fungies is a payment merchant of record platform designed specifically for SaaS developers. It offers a streamlined way to handle payments, subscriptions, and checkout experiences with key benefits including:

  • No hidden fees pricing structure

  • Beautiful checkout solutions (Overlay, Embedded, and Hosted options)

  • Easy integration process

  • No-code store builder for quick setup

This guide will walk you through integrating Fungies checkout into your Next.js 15 application. We'll use straightforward language and provide practical code examples that you can adapt to your own projects.

2. Getting Started with Fungies & Next.js

Prerequisites

Before beginning the integration process, ensure you have:

  • Next.js 15 Project: Create one with npx create-next-app@latest my-fungies-app

    • Use TypeScript (recommended)

    • Use App Router (to leverage Next.js 15 features)

  • Fungies Account:

    • Sign up at

    • For testing, use the Sandbox environment:

    • Create a store in your dashboard

    • Set up at least one product or subscription

    • Note your API keys (public and secret)

    • Create a checkout element and note the checkout URL

  • Development Environment:

    • Node.js 18.17 or later

    • npm, yarn, or pnpm package manager

Installation

Install the Fungies JavaScript SDK in your Next.js project:bash

# Using npm
npm install @fungies/fungies-js

# Using yarn
yarn add @fungies/fungies-js

# Using pnpm
pnpm add @fungies/fungies-js

Setup

  1. Environment Variables

Create a .env.local file in your project root:

# .env.local
# For production
NEXT_PUBLIC_FUNGIES_PUBLIC_KEY=pub_your_public_key
FUNGIES_SECRET_KEY=sec_your_secret_key

# For sandbox testing (https://app.stage.fungies.net) 
NEXT_PUBLIC_FUNGIES_SANDBOX_PUBLIC_KEY=pub_your_sandbox_key
FUNGIES_SANDBOX_SECRET_KEY=sec_your_sandbox_key
NEXT_PUBLIC_FUNGIES_ENVIRONMENT=sandbox
  1. SDK Initialization

Create a utility file to initialize the Fungies SDK (lib/fungies.ts):typescript

// lib/fungies.ts
import { Fungies } from '@fungies/fungies-js';

// Initialize Fungies on the client side only
export const initFungies = () => {
  if (typeof window !== 'undefined') {
    Fungies.Initialize({
      // Optional: Disable data attribute support if not needed
      // enableDataAttributes: false
    });
    
    return Fungies;
  }
  
  return null;
};

// Helper function to get the Fungies instance
export const getFungies = () => {
  if (typeof window !== 'undefined') {
    return Fungies;
  }
  
  return null;
};

This utility ensures Fungies is only initialized on the client side, preventing server-side rendering errors.

3. Implementing Fungies Checkout

Checkout Options Overview

Fungies offers three main checkout integration options:

  1. Overlay Checkout: Displays in a modal overlay (simplest option)

  2. Embedded Checkout: Displays directly within your page layout

  3. Hosted Checkout: Redirects to a Fungies-hosted checkout page

We'll focus on implementing the Overlay and Embedded options as they provide the best balance of ease and user experience.

Overlay Checkout Implementation

Create a client component for the overlay checkout (components/OverlayCheckoutButton.tsx):typescript

'use client';

import { useEffect } from 'react';
import { initFungies, getFungies } from '@/lib/fungies';

interface OverlayCheckoutButtonProps {
  checkoutUrl: string;
  buttonText?: string;
  customerEmail?: string;
  discountCode?: string;
  quantity?: number;
  customFields?: Record<string, string>;
  onCheckoutComplete?: () => void;
  onCheckoutClose?: () => void;
}

export default function OverlayCheckoutButton({
  checkoutUrl,
  buttonText = 'Buy Now',
  customerEmail,
  discountCode,
  quantity,
  customFields,
  onCheckoutComplete,
  onCheckoutClose
}: OverlayCheckoutButtonProps) {
  useEffect(() => {
    // Initialize Fungies when the component mounts
    const Fungies = initFungies();
    
    if (Fungies) {
      // Set up event listeners
      const handleComplete = () => {
        console.log('Checkout completed!');
        onCheckoutComplete?.();
      };
      
      const handleClose = () => {
        console.log('Checkout closed!');
        onCheckoutClose?.();
      };
      
      // Add event listeners
      document.addEventListener('fungies:checkout:complete', handleComplete);
      document.addEventListener('fungies:checkout:close', handleClose);
      
      // Clean up event listeners on unmount
      return () => {
        document.removeEventListener('fungies:checkout:complete', handleComplete);
        document.removeEventListener('fungies:checkout:close', handleClose);
      };
    }
  }, [onCheckoutComplete, onCheckoutClose]);
  
  const handleCheckout = () => {
    const Fungies = getFungies();
    if (!Fungies) return;
    
    Fungies.Checkout.open({
      checkoutUrl,
      settings: {
        mode: 'overlay',
      },
      ...(customerEmail && { customerEmail }),
      ...(discountCode && { discountCode }),
      ...(quantity && { quantity }),
      ...(customFields && { customFields })
    });
  };
  
  return (
    <button 
      onClick={handleCheckout}
      className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"
    >
      {buttonText}
    </button>
  );
}

Use this component in any page:tsx

// app/products/[id]/page.tsx
import OverlayCheckoutButton from '@/components/OverlayCheckoutButton';

export default function ProductPage() {
  const checkoutUrl = 'https://your-store.fungies.io/checkout-element/your-checkout-id';
  
  return (
    <div className="max-w-4xl mx-auto p-6">
      <h1 className="text-3xl font-bold mb-4">Product Name</h1>
      <p className="mb-6">Product description goes here...</p>
      <div className="flex items-center justify-between">
        <span className="text-2xl font-semibold">$29.99</span>
        <OverlayCheckoutButton 
          checkoutUrl={checkoutUrl}
          onCheckoutComplete={()  => {
            // Redirect or show success message
            console.log('Purchase completed!');
          }}
        />
      </div>
    </div>
  );
}

Embedded Checkout Implementation

Create a container component for the embedded checkout (components/EmbeddedCheckout.tsx):typescript

'use client';

import { useEffect, useRef } from 'react';
import { initFungies, getFungies } from '@/lib/fungies';

interface EmbeddedCheckoutProps {
  checkoutUrl: string;
  containerClassName?: string;
  customerEmail?: string;
  discountCode?: string;
  quantity?: number;
  customFields?: Record<string, string>;
  onCheckoutComplete?: () => void;
  onCheckoutClose?: () => void;
}

export default function EmbeddedCheckout({
  checkoutUrl,
  containerClassName = 'w-full min-h-[600px] border rounded',
  customerEmail,
  discountCode,
  quantity,
  customFields,
  onCheckoutComplete,
  onCheckoutClose
}: EmbeddedCheckoutProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const containerId = 'fungies-embedded-checkout';
  
  useEffect(() => {
    // Initialize Fungies when the component mounts
    const Fungies = initFungies();
    
    if (Fungies && containerRef.current) {
      // Set up event listeners
      const handleComplete = () => {
        console.log('Checkout completed!');
        onCheckoutComplete?.();
      };
      
      const handleClose = () => {
        console.log('Checkout closed!');
        onCheckoutClose?.();
      };
      
      // Add event listeners
      document.addEventListener('fungies:checkout:complete', handleComplete);
      document.addEventListener('fungies:checkout:close', handleClose);
      
      // Open the checkout in embedded mode
      Fungies.Checkout.open({
        checkoutUrl,
        settings: {
          mode: 'embed',
          frameTarget: containerId,
        },
        ...(customerEmail && { customerEmail }),
        ...(discountCode && { discountCode }),
        ...(quantity && { quantity }),
        ...(customFields && { customFields })
      });
      
      // Clean up event listeners and checkout on unmount
      return () => {
        document.removeEventListener('fungies:checkout:complete', handleComplete);
        document.removeEventListener('fungies:checkout:close', handleClose);
        Fungies.Checkout.close();
      };
    }
  }, [checkoutUrl, customerEmail, discountCode, quantity, customFields, onCheckoutComplete, onCheckoutClose]);
  
  return (
    <div 
      id={containerId}
      ref={containerRef}
      className={containerClassName}
    />
  );
}

Use the embedded checkout in your pages:tsx

// app/checkout/page.tsx
import EmbeddedCheckout from '@/components/EmbeddedCheckout';

export default function CheckoutPage() {
  const checkoutUrl = 'https://your-store.fungies.io/checkout-element/your-checkout-id';
  
  return (
    <div className="max-w-4xl mx-auto p-6">
      <h1 className="text-3xl font-bold mb-6">Checkout</h1>
      <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
        <div>
          <h2 className="text-xl font-semibold mb-4">Order Summary</h2>
          <div className="border rounded p-4 mb-4">
            <p className="font-medium">Premium SaaS Subscription</p>
            <p className="text-gray-600">$29.99/month</p>
          </div>
        </div>
        <div>
          <h2 className="text-xl font-semibold mb-4">Payment Details</h2>
          <EmbeddedCheckout 
            checkoutUrl={checkoutUrl}
            containerClassName="w-full min-h-[600px] border rounded-lg shadow-md bg-white"
            onCheckoutComplete={()  => {
              // Redirect to success page
              window.location.href = '/checkout/success';
            }}
          />
        </div>
      </div>
    </div>
  );
}

4. Handling Payments & Events

Working with Checkout Data

Fungies provides several options for customizing the checkout experience:

Pre-filling Customer Information

typescript

Fungies.Checkout.open({
  checkoutUrl,
  settings: { mode: 'overlay' },
  customerEmail: 'customer@example.com',
  customFields: {
    firstName: 'John',
    lastName: 'Doe'
  }
});

Applying Discount Codes

typescript

Fungies.Checkout.open({
  checkoutUrl,
  settings: { mode: 'overlay' },
  discountCode: 'WELCOME10'
});

Setting Quantities

typescript

Fungies.Checkout.open({
  checkoutUrl,
  settings: { mode: 'overlay' },
  quantity: 2
});

Webhook Integration

Webhooks allow your application to receive real-time notifications about events in your Fungies account.Create an API route to handle webhook events:typescript

// app/api/webhooks/fungies/route.ts
import { NextRequest, NextResponse } from 'next/server';
import crypto from 'crypto';

// This should be stored in your environment variables
const webhookSecret = process.env.FUNGIES_WEBHOOK_SECRET;

export async function POST(request: NextRequest) {
  try {
    // Get the signature from the headers
    const signature = request.headers.get('x-fngs-signature');
    
    if (!signature || !webhookSecret) {
      return NextResponse.json(
        { error: 'Missing signature or webhook secret' },
        { status: 401 }
      );
    }
    
    // Get the raw request body
    const rawBody = await request.text();
    
    // Verify the signature
    const hmac = crypto.createHmac('sha256', webhookSecret);
    const digest = hmac.update(rawBody).digest('hex');
    
    if (digest !== signature) {
      return NextResponse.json(
        { error: 'Invalid signature' },
        { status: 401 }
      );
    }
    
    // Parse the webhook payload
    const event = JSON.parse(rawBody);
    
    // Handle different event types
    switch (event.type) {
      case 'payment_success':
        await handlePaymentSuccess(event);
        break;
      case 'subscription_created':
        await handleSubscriptionCreated(event);
        break;
      case 'subscription_cancelled':
        await handleSubscriptionCancelled(event);
        break;
      // Add more event handlers as needed
      default:
        console.log(`Unhandled event type: ${event.type}`);
    }
    
    // Return a 200 response to acknowledge receipt of the webhook
    return NextResponse.json({ received: true });
  } catch (error) {
    console.error('Webhook error:', error);
    return NextResponse.json(
      { error: 'Webhook processing failed' },
      { status: 500 }
    );
  }
}

// Example event handlers
async function handlePaymentSuccess(event: any) {
  // Update your database, send confirmation emails, etc.
  console.log('Payment successful:', event.data.id);
}

async function handleSubscriptionCreated(event: any) {
  // Provision access to your service, update user status, etc.
  console.log('Subscription created:', event.data.id);
}

async function handleSubscriptionCancelled(event: any) {
  // Update user status, send retention emails, etc.
  console.log('Subscription cancelled:', event.data.id);
}

Security Considerations for Webhooks

  1. Always verify signatures using the webhook secret

  2. Store secrets in environment variables, never hardcode them

  3. Design webhook handlers to be idempotent as Fungies may retry webhook deliveries

  4. Catch and log errors but still return a 200 status to acknowledge receipt

  5. Keep webhook processing quick or move long-running tasks to a background job

5. Integrating with Next.js 15 Features

Server vs. Client Components

Next.js 15 uses React's Server Components by default, but Fungies SDK requires client-side JavaScript.Server Components are great for:

  • Fetching data from your backend or APIs

  • Accessing environment variables securely

  • Rendering static content

Client Components are necessary for:

  • Interacting with the Fungies SDK

  • Handling user interactions like button clicks

  • Managing local state

Here's a pattern for combining both:tsx

// app/products/[id]/page.tsx (Server Component)
import { Suspense } from 'react';
import ProductDetails from './ProductDetails';
import CheckoutSection from './CheckoutSection';
import { getProductById } from '@/lib/products';

export default async function ProductPage({ params }: { params: { id: string } }) {
  // Fetch product data on the server
  const product = await getProductById(params.id);
  
  return (
    <div className="max-w-6xl mx-auto p-6">
      <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
        <Suspense fallback={<div>Loading product details...</div>}>
          {/* Server Component for product details */}
          <ProductDetails product={product} />
        </Suspense>
        
        <Suspense fallback={<div>Loading checkout options...</div>}>
          {/* Client Component for Fungies integration */}
          <CheckoutSection 
            productId={product.id}
            price={product.price}
            checkoutUrl={product.checkoutUrl}
          />
        </Suspense>
      </div>
    </div>
  );
}

tsx

// app/products/[id]/CheckoutSection.tsx (Client Component)
'use client';

import { useState, useEffect } from 'react';
import { initFungies, getFungies } from '@/lib/fungies';

export default function CheckoutSection({
  productId,
  price,
  checkoutUrl
}) {
  // Client-side code for Fungies integration
  // ...
}

Server Actions

Next.js 15 includes Server Actions, which allow you to run server-side code from client components. This is perfect for operations that require your secret API key.typescript

// app/actions/checkout.ts
'use server';

// This function runs on the server and can access environment variables securely
export async function createCheckoutSession(formData: FormData) {
  const productId = formData.get('productId') as string;
  const quantity = parseInt(formData.get('quantity') as string, 10);
  
  if (!productId || isNaN(quantity)) {
    throw new Error('Invalid product or quantity');
  }
  
  try {
    // Use your secret API key securely on the server
    const apiKey = process.env.FUNGIES_SECRET_KEY;
    
    // Make API request to Fungies to create a checkout session
    const response = await fetch('https://api.fungies.io/v0/checkout-sessions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-fngs-public-key': process.env.NEXT_PUBLIC_FUNGIES_PUBLIC_KEY!,
        'x-fngs-secret-key': apiKey!,
      },
      body: JSON.stringify({
        productId,
        quantity,
        successUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/checkout/success`,
        cancelUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/checkout/cancel`,
      }) ,
    });
    
    if (!response.ok) {
      throw new Error('Failed to create checkout session');
    }
    
    const data = await response.json();
    return { checkoutUrl: data.url };
  } catch (error) {
    console.error('Error creating checkout session:', error);
    throw new Error('Failed to create checkout session');
  }
}

Use this Server Action in a client component:tsx

// app/products/[id]/CheckoutForm.tsx
'use client';

import { useEffect, useState } from 'react';
import { createCheckoutSession } from '@/app/actions/checkout';
import { initFungies, getFungies } from '@/lib/fungies';

export default function CheckoutForm({ productId }: { productId: string }) {
  const [quantity, setQuantity] = useState(1);
  const [isLoading, setIsLoading] = useState(false);
  
  useEffect(() => {
    initFungies();
  }, []);
  
  async function handleSubmit(formData: FormData) {
    setIsLoading(true);
    
    try {
      // Call the server action
      const result = await createCheckoutSession(formData);
      
      // Open the checkout using the returned URL
      const Fungies = getFungies();
      if (Fungies && result.checkoutUrl) {
        Fungies.Checkout.open({
          checkoutUrl: result.checkoutUrl,
          settings: { mode: 'overlay' },
        });
      }
    } catch (err) {
      console.error(err);
    } finally {
      setIsLoading(false);
    }
  }
  
  return (
    <form action={handleSubmit} className="space-y-4">
      <input type="hidden" name="productId" value={productId} />
      
      <div>
        <label htmlFor="quantity" className="block text-sm font-medium text-gray-700 mb-1">
          Quantity
        </label>
        <select
          id="quantity"
          name="quantity"
          value={quantity}
          onChange={(e) => setQuantity(parseInt(e.target.value, 10))}
          className="w-full px-3 py-2 border border-gray-300 rounded-md"
        >
          {[1, 2, 3, 4, 5].map((num) => (
            <option key={num} value={num}>{num}</option>
          ))}
        </select>
      </div>
      
      <button
        type="submit"
        disabled={isLoading}
        className="w-full py-2 px-4 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50"
      >
        {isLoading ? 'Processing...' : 'Proceed to Checkout'}
      </button>
    </form>
  );
}

Performance Tips

Lazy Loading Checkout Components

Use Next.js dynamic imports to lazy load checkout components:typescript

// components/LazyCheckoutButton.tsx
import dynamic from 'next/dynamic';

// Dynamically import the checkout component
const CheckoutButton = dynamic(
  () => import('@/components/OverlayCheckoutButton'),
  {
    loading: () => <button className="px-4 py-2 bg-gray-300 text-gray-700 rounded">
      Loading...
    </button>,
    ssr: false, // Disable server-side rendering
  }
);

export default function LazyCheckoutButton(props) {
  return <CheckoutButton {...props} />;
}

Optimizing Webhook Processing

For long-running webhook tasks, use a background process:typescript

// app/api/webhooks/fungies/route.ts
export async function POST(request: NextRequest) {
  try {
    // Verify the webhook (code omitted for brevity)
    
    // Get the event data
    const event = await request.json();
    
    // For long-running tasks, use a background process
    await enqueueWebhookProcessing(event);
    
    // Return a 200 response immediately
    return NextResponse.json({ received: true });
  } catch (error) {
    console.error('Webhook error:', error);
    return NextResponse.json(
      { error: 'Webhook processing failed' },
      { status: 500 }
    );
  }
}

// Function to enqueue webhook processing
async function enqueueWebhookProcessing(event: any) {
  // This could be a message queue, database insert, etc.
  console.log('Enqueueing webhook processing for event:', event.id);
}

6. Testing & Deployment

Testing with Fungies Sandbox

Fungies provides a Sandbox environment for testing:

Set up environment variables to switch between environments:typescript

// lib/fungies-config.ts
export const FUNGIES_ENVIRONMENTS = {
  sandbox: {
    apiBase: 'https://api.stage.fungies.net/v0',
    checkoutBase: 'https://checkout.stage.fungies.net',
    publicKey: process.env.NEXT_PUBLIC_FUNGIES_SANDBOX_PUBLIC_KEY,
    secretKey: process.env.FUNGIES_SANDBOX_SECRET_KEY,
  },
  production: {
    apiBase: 'https://api.fungies.io/v0',
    checkoutBase: 'https://checkout.fungies.io',
    publicKey: process.env.NEXT_PUBLIC_FUNGIES_PRODUCTION_PUBLIC_KEY,
    secretKey: process.env.FUNGIES_PRODUCTION_SECRET_KEY,
  },
};

export const getFungiesConfig = ()  => {
  const environment = process.env.NEXT_PUBLIC_FUNGIES_ENVIRONMENT || 
                     (process.env.NODE_ENV === 'production' ? 'production' : 'sandbox');
  
  return FUNGIES_ENVIRONMENTS[environment as keyof typeof FUNGIES_ENVIRONMENTS];
};

Use this configuration in your API calls:typescript

// Example server action using the environment config
export async function createCheckoutSession(formData: FormData) {
  const config = getFungiesConfig();
  
  // This will use https://api.stage.fungies.net/v0/checkout-sessions in sandbox mode
  // or https://api.fungies.io/v0/checkout-sessions in production
  const response = await fetch(`${config.apiBase}/checkout-sessions`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-fngs-public-key': config.publicKey!,
      'x-fngs-secret-key': config.secretKey!,
    },
    // ...
  }) ;
  
  // ...
}

Debugging Common Issues

SDK Not Loading

typescript

// Debug helper to check if SDK is loaded
export const debugFungiesSDK = () => {
  if (typeof window === 'undefined') {
    console.log('Running on server - Fungies SDK not available');
    return false;
  }
  
  if (typeof Fungies === 'undefined') {
    console.error('Fungies SDK not loaded correctly');
    return false;
  }
  
  console.log('Fungies SDK loaded successfully');
  return true;
};

Webhook Verification Issues

typescript

// app/api/webhooks/fungies/debug/route.ts
export async function POST(request: NextRequest) {
  try {
    // Get the signature from the headers
    const signature = request.headers.get('x-fngs-signature');
    const webhookSecret = process.env.FUNGIES_WEBHOOK_SECRET;
    
    console.log('Received webhook with signature:', signature);
    console.log('Using webhook secret (first 4 chars):', webhookSecret?.substring(0, 4));
    
    // Get the raw request body
    const rawBody = await request.text();
    
    // Verify the signature
    const hmac = crypto.createHmac('sha256', webhookSecret || '');
    const digest = hmac.update(rawBody).digest('hex');
    
    console.log('Calculated signature:', digest);
    console.log('Signatures match:', digest === signature);
    
    // Return debug info (only in development!)
    if (process.env.NODE_ENV === 'development') {
      return NextResponse.json({
        received: true,
        signatureProvided: signature,
        signatureCalculated: digest,
        match: digest === signature,
      });
    }
    
    return NextResponse.json({ received: true });
  } catch (error) {
    console.error('Webhook debug error:', error);
    return NextResponse.json(
      { error: 'Webhook processing failed' },
      { status: 500 }
    );
  }
}

Deployment

Environment Variables in Production

For Vercel deployments, add these environment variables in the Vercel dashboard:

NEXT_PUBLIC_FUNGIES_ENVIRONMENT=production
NEXT_PUBLIC_FUNGIES_PRODUCTION_PUBLIC_KEY=pub_your_production_key
FUNGIES_PRODUCTION_SECRET_KEY=sec_your_production_key
FUNGIES_WEBHOOK_SECRET=your_webhook_secret
NEXT_PUBLIC_BASE_URL=https://your-production-domain.com

Security Best Practices

  1. Never expose your secret API key in client-side code

  2. Add security headers to your webhook endpoints

  3. Validate user input before sending it to Fungies

  4. Use Server Actions for operations requiring the secret key

7. Conclusion

In this guide, we've covered how to integrate Fungies checkout into your Next.js 15 application. We've explored:

  1. Setting up the Fungies SDK in a Next.js environment

  2. Implementing both Overlay and Embedded checkout options

  3. Working with checkout data and customization

  4. Setting up webhooks to handle payment events

  5. Leveraging Next.js 15 features like Server Components and Server Actions

  6. Testing with the Fungies Sandbox environment

  7. Deploying your integration to production

For more information, refer to:

Sandbox App URL:

Sandbox API Docs:

For support, contact or join the Fungies community forums.

Fungies.io
https://app.stage.fungies.net
https://app.stage.fungies.net
https://api.stage.fungies.net/v0/api-docs/
Fungies Documentation
Fungies API Documentation
Fungies Sandbox API Documentation
Next.js Documentation
support@fungies.io