- ✓A Next.js 14/15 project using the App Router
- ✓Fonepay merchant test credentials from merchant.fonepay.com
- ✓A client-side QR rendering library (e.g. 'qrcode.react')
🚀 What You Will Learn & Build
- ▸How Fonepay dynamic QR generation works via their Merchant API
- ▸Creating a Next.js Server Route Handler (/api/fonepay/generate-qr)
- ▸Rendering dynamic QR codes on the frontend using SVG
- ▸Implementing client-side status polling until payment is verified
1. The Fonepay Dynamic QR Architecture
2. Next.js Server Route Handler (app/api/fonepay/qr/route.ts)
import { NextResponse } from "next/server";
import crypto from "crypto";
export async function POST(req: Request) {
try {
const { amount, orderId } = await req.json();
const merchantCode = process.env.FONEPAY_MERCHANT_CODE || "FNPLTEST";
const secretKey = process.env.FONEPAY_SECRET_KEY || "fonepay_test_key";
// Format timestamp
const dateStr = new Date().toISOString().replace(/[-:T.Z]/g, "").slice(0, 14);
// Hash fields for Fonepay API signature
const hashData = `${merchantCode},${orderId},${amount},${dateStr}`;
const signature = crypto.createHmac("sha512", secretKey).update(hashData).digest("hex");
// Call Fonepay Dynamic QR API
const res = await fetch("https://dev-clientapi.fonepay.com/api/merchant/merchantDetailsForThirdParty/thirdPartyMerchantQR", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
merchantCode,
amount,
remarks1: `Order ${orderId}`,
prn: orderId,
date: dateStr,
signature
})
});
const data = await res.json();
return NextResponse.json({ success: true, qrString: data.qrMessage });
} catch (error) {
return NextResponse.json({ error: "Failed to generate QR" }, { status: 500 });
}
}✨ Expected Output & Verification
A high-conversion checkout screen displaying a dynamic QR code that automatically updates to 'Payment Verified' when scanned.
🧪 How to Test the Implementation
- 1Send a POST request to /api/fonepay/qr with amount and orderId
- 2Render the returned qrMessage string in a React QRCode component
- 3Simulate payment using Fonepay developer sandbox portal
⚠️ Common Errors & How to Fix Them
Root Cause: Fonepay uses SHA512 (not SHA256) with specific parameter order.
Fix: Verify that crypto.createHmac('sha512', key) is used with the exact merchant code and timestamp.
🛡️ Security Considerations & Best Practices
- !Always verify payment status on the server before fulfilling digital downloads or credits.
❓ Frequently Asked Questions (FAQ)
Yes, over 50 commercial, development, and microfinance banks in Nepal are members of the Fonepay network.
📌 Summary of Key Takeaways
Dynamic Fonepay QR integration in Next.js allows customers to pay with any Nepali bank app without leaving your website.
Official References & Further Reading
Written by Manoj Neupane
AuthorSoftware developer and programming instructor, Nepal
Building software systems and SaaS platforms with Laravel, Next.js, and Node.js. Passionate about helping students and developers in Nepal master practical, real-world development skills.