ValuePay Checkout for React/Next.js (Script)
Introduction
Welcome to the ValuePay integration guide! This documentation will help you integrate ValuePay's payment gateway into your React or Next.js application to accept payments from your customers.
Prerequisites
Before you begin, make sure you have:
- A ValuePay merchant account
- Your ValuePay public key
- A React or Next.js application
- Node.js version 16 or higher
Installation
1. No SDK Installation Required
ValuePay uses inline script integration, so no npm package installation is needed. The ValuePay JavaScript library is loaded dynamically.
2. Environment Setup
Create a .env.local file in your project root:
NEXT_PUBLIC_VALUEPAY_PUBLIC_KEY=KP_your_public_key_hereQuick Start
1. Create a Script Loading Hook
app/hooks/useScripts.ts
// app/hooks/useScripts.ts
import { useEffect } from "react";
const useScript = (src: string) => {
useEffect(() => {
if (!src) return;
const script = document.createElement("script");
script.src = src;
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, [src]);
};
export default useScript;2. Add TypeScript Declarations
// Add this to your component or a global types file
declare global {
interface Window {
ValuepayCheckout: (input: unknown) => void;
}
}3. Create a Payment Component
components/CheckoutForm.tsx
// components/CheckoutForm.tsx
"use client";
import { MouseEvent, useState } from "react";
import useScript from "../hooks/useScripts";
import { makeId } from "../helper/makeid";
declare global {
interface Window {
ValuepayCheckout: (input: unknown) => void;
}
}
export default function CheckoutForm() {
const [amount, setAmount] = useState<number | null>(null);
useScript(
"https://www.valuepayng.com/js/vp-v1.js?v=1.000436060005554300660040066"
);
const handleSubmit = (e: MouseEvent) => {
if (
typeof window === "undefined" ||
window.ValuepayCheckout === undefined
) {
return;
}
e.preventDefault();
if (amount && !isNaN(amount) && amount > 0) {
const paymentData = {
public_key: process.env.NEXT_PUBLIC_VALUEPAY_PUBLIC_KEY,
transactionRef: makeId(15),
amount: amount,
currency: "NGN",
channels: ["card", "transfer", "qrcode", "ussd"],
redirect_url: "https://your-domain.com/payment/success",
customer: {
email: "customer@example.com",
firstName: "John",
lastName: "Doe",
},
onclose: function () {
console.log("Payment modal closed");
},
customisedCheckout: {
title: "Complete Your Payment",
description:
"Thank you for your purchase. Please complete your payment to proceed.",
logoLink: "https://your-domain.com/logo.png",
},
};
window.ValuepayCheckout(paymentData);
} else {
alert("Please enter a valid amount");
}
};
return (
<div className="max-w-md mx-auto p-6 bg-white rounded-lg shadow-md">
<h2 className="text-2xl font-bold mb-4">Complete Your Payment</h2>
<div className="mb-4">
<label className="block text-sm font-medium mb-2">Amount (NGN)</label>
<input
type="number"
value={amount != null && amount > 0 ? amount : ""}
onChange={(e) => setAmount(Number(e.target.value))}
className="w-full px-3 py-2 border border-gray-300 rounded-md"
placeholder="0.00"
step="0.01"
min="0"
/>
</div>
<button
onClick={handleSubmit}
disabled={!amount || amount <= 0}
className="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 disabled:opacity-50"
>
Pay Now
</button>
</div>
);
}4. Create a Helper for Transaction References
app/helper/makeid.ts
// app/helper/makeid.ts
export const makeId = (length = 24) => {
let text = "";
const possible =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};5. Use the Component in Your Page
app/page.tsx
// app/page.tsx
import CheckoutForm from "@/components/CheckoutForm";
export default function Home() {
return (
<div className="min-h-screen bg-gray-50 py-12">
<div className="container mx-auto">
<h1 className="text-3xl font-bold text-center mb-8">
ValuePay Integration Demo
</h1>
<CheckoutForm />
</div>
</div>
);
}Basic Integration
Payment Object Structure
interface PaymentData {
public_key: string;
transactionRef: string;
amount: number;
currency: string;
channels: string[];
redirect_url: string;
customer: {
email: string;
firstName: string;
lastName: string;
};
onclose?: () => void;
customisedCheckout?: {
title: string;
description: string;
logoLink: string;
};
callback?: (data: any) => void;
onsuccess?: (data: any) => void;
}Available Payment Channels
const channels = [
"card", // Credit/Debit cards
"transfer", // Bank transfers
"qrcode", // QR code payments
"ussd", // USSD payments
];Handling Payment Responses
components/PaymentHandler.tsx
// components/PaymentHandler.tsx
"use client";
import { useEffect } from "react";
export default function PaymentHandler() {
useEffect(() => {
const handlePaymentSuccess = (event: MessageEvent) => {
if (event.data.type === "valuepay_payment_success") {
console.log("Payment successful:", event.data);
}
};
const handlePaymentFailure = (event: MessageEvent) => {
if (event.data.type === "valuepay_payment_failed") {
console.log("Payment failed:", event.data);
}
};
window.addEventListener("message", handlePaymentSuccess);
window.addEventListener("message", handlePaymentFailure);
return () => {
window.removeEventListener("message", handlePaymentSuccess);
window.removeEventListener("message", handlePaymentFailure);
};
}, []);
return null;
}Advanced Features
1. Custom Styling and Branding
const paymentData = {
customisedCheckout: {
title: "Complete Your Order",
description: "You're just one step away from completing your purchase.",
logoLink: "https://your-domain.com/assets/logo.png",
},
};2. Multiple Payment Channels
const channels = ["card", "transfer"];
const allChannels = ["card", "transfer", "qrcode", "ussd"];3. Callback Functions
const paymentData = {
callback: function (data: any) {
console.log("Payment callback:", data);
},
onsuccess: function (data: any) {
window.location.href = "/payment/success";
},
onclose: function () {
console.log("Payment modal closed");
},
};API Reference
window.ValuepayCheckout(paymentData: PaymentData): void
See the Payment Object Structure above for the full interface.
Payment Response
interface PaymentResponse {
transactionRef: string;
status: "success" | "failed" | "pending";
amount: number;
currency: string;
customer: { email: string; firstName: string; lastName: string };
paymentMethod: string;
timestamp: string;
}Best Practices
- Never expose your secret key in client-side code
- Always verify webhook signatures
- Use HTTPS in production
- Validate all input data
- Generate unique transaction references
- Show loading states during script loading
- Provide clear error messages
const generateTransactionRef = () => {
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2, 15);
return `TXN_${timestamp}_${random}`;
};Troubleshooting
"ValuepayCheckout is not defined" Error
- Ensure the script is loaded before calling the function
- Check if the script URL is accessible
- Verify the script is loaded in the correct order
Script Not Loading
- Check network connectivity
- Verify the script URL is correct
- Ensure no Content Security Policy (CSP) blocking the script
Payment Modal Not Opening
- Check browser console for JavaScript errors
- Verify all required fields are provided
- Ensure the public key is valid
Need help? Check out the Merchant Onboarding guide or Authentication docs.
ON THIS PAGE
© Copyright 2026