Skip to main content

Examples

πŸš€ Full-stack Sample Projects​

Next.js 15 Full-stack Example​

Key Features:

  • βœ… Server-side VNPay integration - All payment processing on server
  • βœ… Next.js 15 App Router with Server Actions and API Routes
  • βœ… IPN Handler - Webhook processing from VNPay
  • βœ… Types-only imports for frontend components
  • βœ… Responsive UI with Tailwind CSS
  • βœ… Demo sandbox environment with test data

Express MVC Example​

πŸ“‹ Basic Usage Examples​

Library Methods​

See examples of all library methods here

Express Implementation​

See a complete Express implementation example here

πŸ—οΈ Proper Full-stack Architecture​

⚠️ Important Principles​

WARNING

The VNPay library is designed for Node.js backends only! Cannot be used directly in React/Vue/Angular components because:

  • 🚫 Uses Node.js modules: fs, crypto, path
  • 🚫 Contains server-side logic to secure secureSecret
  • 🚫 Will cause build errors when imported in client components
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    API calls    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Frontend β”‚ ──────────────► β”‚ Backend β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β€’ React/Vue β”‚ β”‚ β€’ Node.js β”‚
β”‚ β€’ Types only β”‚ β”‚ β€’ VNPay library β”‚
β”‚ β€’ UI components β”‚ ◄────────────── β”‚ β€’ Payment logic β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ JSON response β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ’Ό Backend Example (Node.js/Express)​

// backend/routes/payment.ts
import { VNPay } from 'vnpay'; // βœ… Full import on backend

const vnpay = new VNPay({
tmnCode: process.env.VNP_TMNCODE!,
secureSecret: process.env.VNP_SECRET!,
testMode: true
});

// Create payment URL
app.post('/api/payments/create', async (req, res) => {
try {
const { amount, orderInfo } = req.body;

const paymentUrl = vnpay.buildPaymentUrl({
vnp_Amount: amount,
vnp_IpAddr: req.ip,
vnp_ReturnUrl: `${process.env.APP_URL}/payment/callback`,
vnp_TxnRef: `ORDER_${Date.now()}`,
vnp_OrderInfo: orderInfo,
});

res.json({ success: true, paymentUrl });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});

// Verify payment result
app.get('/api/payments/verify', (req, res) => {
const verification = vnpay.verifyReturnUrl(req.query);
res.json(verification);
});

🎨 Frontend Example (React/Next.js)​

// frontend/components/PaymentButton.tsx
import { useState } from 'react';
import type { VerifyReturnUrl } from 'vnpay/types-only'; // βœ… Types only

interface PaymentButtonProps {
amount: number;
orderInfo: string;
onPaymentResult?: (result: VerifyReturnUrl) => void;
}

export const PaymentButton: React.FC<PaymentButtonProps> = ({
amount,
orderInfo,
onPaymentResult
}) => {
const [loading, setLoading] = useState(false);

const handlePayment = async () => {
setLoading(true);

try {
// βœ… Call backend API instead of direct import
const response = await fetch('/api/payments/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ amount, orderInfo }),
});

const data = await response.json();

if (data.success) {
// Redirect to VNPay
window.location.href = data.paymentUrl;
} else {
alert('Payment creation failed');
}
} catch (error) {
console.error('Payment error:', error);
alert('Connection error');
} finally {
setLoading(false);
}
};

return (
<button
onClick={handlePayment}
disabled={loading}
className="bg-blue-600 text-white px-6 py-2 rounded hover:bg-blue-700"
>
{loading ? 'Processing...' : `Pay ${amount.toLocaleString()} VND`}
</button>
);
};

πŸ” IPN Handler Example​

// backend/routes/ipn.ts
app.post('/api/payment/ipn', (req, res) => {
try {
const verification = vnpay.verifyIpnCall(req.body);

if (verification.isSuccess) {
// βœ… Payment successful - update database
console.log('Payment successful:', verification.vnp_TxnRef);

// Update order status in database
// updateOrderStatus(verification.vnp_TxnRef, 'PAID');

res.status(200).json({ RspCode: '00', Message: 'success' });
} else {
// ❌ Payment failed
console.log('Payment failed:', verification.message);
res.status(200).json({ RspCode: '01', Message: 'fail' });
}
} catch (error) {
console.error('IPN processing error:', error);
res.status(500).json({ RspCode: '99', Message: 'error' });
}
});

🎯 Important Notes for Frontend​

❌ DON'T do this​

// 🚫 WILL CAUSE BUILD ERRORS!
import { VNPay } from 'vnpay';
// Error: Module not found: Can't resolve 'fs'

const MyComponent = () => {
const vnpay = new VNPay(config); // ❌ Cannot do this in browser!
return <div>Payment</div>;
};

βœ… CORRECT usage​

// βœ… Safe - import types only
import type {
VNPayConfig,
BuildPaymentUrl,
Bank,
VerifyReturnUrl
} from 'vnpay/types-only';

// Or use type import with main package
import type { VNPayConfig } from 'vnpay';

interface PaymentComponentProps {
config: VNPayConfig;
onPaymentResult: (result: VerifyReturnUrl) => void;
}

πŸ“š Additional Resources​