A Next.js application with custom Midtrans payment integration using Core API instead of the default Snap UI.
- β¨ Custom payment UI with modern, responsive design
- π³ QRIS payment support (GoPay, ShopeePay, OVO, DANA)
- β±οΈ Real-time payment status checking
- π Automatic QR code generation and display
- π‘οΈ Secure payment processing with Midtrans Core API
- π± Mobile-friendly interface
- Node.js 14.x or higher
- MongoDB database
- Midtrans account and API keys
Create a .env.local file in the root directory:
MONGODB_URI=your_mongodb_connection_string
MIDTRANS_SERVER_KEY=your_midtrans_server_key
MIDTRANS_PRODUCTION=false
MIDTRANS_CLIENT_KEY=your_midtrans_client_key
# Install dependencies
npm install
# Run development server
npm run dev-
User Information Collection
- Collects name and email through
UserInfoModal - Creates user record in database
- Collects name and email through
-
Service Selection
- User selects service type (portfolio, landing, custom)
- Each service type has predefined pricing
-
Payment Processing
- Creates order in database
- Generates QRIS payment code via Midtrans Core API
- Displays QR code in custom
PaymentModal
-
Payment Status Checking
- Automatic polling every 15 seconds
- Manual checking via "I've completed the payment" button
- Shows success/failure messages based on payment status
-
Pending Payment Handling
- Detects and manages existing pending payments
- Allows users to complete or cancel pending transactions
PaymentModal: Displays payment QR code and handles status checkingPendingPaymentModal: Manages existing pending paymentsUserInfoModal: Collects user information before payment
/api/payment/create: Creates a new payment transaction with Midtrans/api/payment/check: Checks payment status with Midtrans/api/payment/check-pending: Checks for existing pending payments/api/payment/cancel: Cancels pending payments
// Creating a payment order
const createOrder = async (serviceType) => {
try {
const response = await fetch("/api/payment/create", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
userId: userData._id,
serviceType, // 'portfolio', 'landing', or 'custom'
}),
});
const data = await response.json();
if (response.ok) {
// Show payment modal with QR code
setOrderData(data.order);
setPaymentModalOpen(true);
}
} catch (error) {
console.error("Error creating order:", error);
}
};Modify the prices in create.js:
const PRICES = {
portfolio: 100000, // IDR 100K
landing: 250000, // IDR 250K
custom: 400000, // IDR 400K
};You can customize the payment modal appearance by editing the components in src/components/modals/.
- Payment expiration: 15 minutes from creation
- Supported payment methods: All QRIS-compatible apps (GoPay, ShopeePay, OVO, DANA, etc.)
- Order IDs format:
ORDER-[timestamp]-[random]
Contributions, issues, and feature requests are welcome!
This project is MIT licensed.