Who is this for?
Web developers who want to accept Naira payments using the Monieswitch
Checkout widget in their websites or web applications.
Overview
This guide covers:
- Direct Checkout (simple, client-side)
- Continued Checkout (secure, server-initialized)
- Payment verification with webhooks
- Basic error handling
Prerequisites
API Keys
Your public and secret keys from the Monieswitch dashboard.
Web Application
A website or web application where you want to accept payments.
1. Setup
Add Monieswitch Library
Include this script in your HTML:
<script
defer
src="https://monieswitch-staging-checkout-inline.pages.dev/inline.js"
></script>
2. Direct Checkout (Simple)
Best for quick implementations and testing.
<script
defer
src="https://monieswitch-staging-checkout-inline.pages.dev/inline.js"
></script>
<div class="container">
<div class="payment-section">
<h2 class="section-title">Direct Checkout</h2>
<form id="paymentForm">
<div class="form-group">
<label for="email-address">Email Address</label>
<input
type="email"
id="email-address"
placeholder="Enter your email"
required
/>
</div>
<div class="form-group">
<label for="amount">Amount (₦)</label>
<input
type="number"
id="amount"
placeholder="Enter amount"
min="1"
required
/>
</div>
<div class="form-group">
<label for="bearer">Bearer Type</label>
<select id="bearer" required>
<option value="">Select bearer type</option>
<option value="account">Account</option>
<option value="subaccount">Subaccount</option>
<option value="customer">Customer</option>
</select>
</div>
<div class="form-group">
<label for="subaccount">Subaccount ID (Optional)</label>
<input type="text" id="subaccount" placeholder="Enter subaccount ID" />
</div>
<button type="submit" class="btn-primary">Pay with Monieswitch</button>
</form>
</div>
</div>
<script>
const paymentForm = document.getElementById("paymentForm");
paymentForm.addEventListener("submit", function (e) {
e.preventDefault();
PayWithMonieswitch.checkout({
publicKey: "pk_test_fDWvDVIBEHoSLchxGx02JtxZYP4tC7qFeGhUtmkgdnML8ZRb",
reference: Date.now(),
amount: Number(document.getElementById("amount").value),
email: document.getElementById("email-address").value,
currency: "NGN",
channels: ["BANK"],
bearer: document.getElementById("bearer").value,
subaccountId: document.getElementById("subaccount").value,
redirectURL: "",
onClose: function () {},
onError: function (error) {
console.log("Error: ", error);
},
onSuccess: function (reference) {
console.log("Success: " + reference);
},
});
});
</script>
3. Continued Checkout (Recommended)
More secure as payment details are initialized on your server.
Backend Setup
require("dotenv").config();
const express = require("express");
const axios = require("axios");
const app = express();
app.use(express.json());
// Initialize checkout
app.post("/api/checkout/initialize", async (req, res) => {
try {
const { amount, email } = req.body;
const response = await axios.post(
"https://nini.monieswitch.com/checkout/initialize",
{
amount: parseFloat(amount),
email: email,
currency: "NGN",
},
{
headers: {
"x-access-token": process.env.MONIESWITCH_SECRET_KEY,
"x-pub-key": process.env.MONIESWITCH_PUBLIC_KEY,
},
}
);
res.json(response.data);
} catch (error) {
res.status(500).json({ error: "Failed to initialize payment" });
}
});
app.listen(3000);
Frontend Implementation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Monieswitch Continue Checkout</title>
<script
defer
src="https://monieswitch-staging-checkout-inline.pages.dev/inline.js"
></script>
</head>
<body>
<div class="container">
<div class="payment-section">
<h2 class="section-title">Continue Checkout</h2>
<form id="continuePaymentForm">
<div class="form-group">
<label for="code">Checkout Code</label>
<input
type="text"
id="code"
placeholder="Enter checkout code"
required
/>
</div>
<button type="submit" class="btn-primary">Continue Payment</button>
</form>
</div>
</div>
<script>
document
.getElementById("continuePaymentForm")
.addEventListener("submit", function (e) {
e.preventDefault();
PayWithMonieswitch.continueCheckout({
checkoutCode: document.getElementById("code").value,
onClose: function () {},
onError: function (error) {
console.log("Error: ", error);
},
onSuccess: function (reference) {
console.log("Success: " + reference);
},
});
});
</script>
</body>
</html>
5. Payment Verification
Backend Verification
// Verify payment status after success callback
app.get("/status", async (req, res) => {
try {
const { reference } = req.body;
const response = await axios.get(
`https://nini.monieswitch.com/checkout/status/${reference}`,
{
headers: {
Authorization: `Bearer ${process.env.MONIESWITCH_SECRET_KEY}`,
},
}
);
const payment = response.data;
if (payment.hasPaid) {
// Payment verified - update your database, send email, etc.
console.log("Payment verified:", payment);
}
res.json(payment);
} catch (error) {
res.status(500).json({ error: "Verification failed" });
}
});
Webhook Handler (Recommended)
// Handle webhook notifications
app.post("/webhooks/monieswitch", (req, res) => {
const event = req.body;
if (event.event === "payment.successful") {
const payment = event.data;
console.log("Payment received:", payment.reference);
// Update your database
// Send confirmation email
// Fulfill order
}
res.status(200).send("OK");
});
6. Environment Variables
Create a .env
file for your backend:
MONIESWITCH_PUBLIC_KEY=your_public_key_here
MONIESWITCH_SECRET_KEY=your_secret_key_here
Security Best Practices
- Never expose your SECRET_KEY in frontend code - Always verify payments
on your backend - Use webhooks for reliable payment notifications - Validate
all payment amounts server-side
- Client-side: Only use your public key
- Server-side: Keep your secret key secure
- Verification: Always verify payments on your backend
- Webhooks: Use webhooks for real-time payment updates
Common Payment Channels
The supported payment channels in Nigeria are:
- BANK - Bank transfer
- CARD - Debit/Credit cards
- USSD - USSD payments
channels: ["BANK", "CARD", "USSD"];
Error Handling
onError: function(error) {
// Handle different error types
if (error.code === 'PAYMENT_CANCELLED') {
console.log('User cancelled payment');
} else if (error.code === 'INSUFFICIENT_FUNDS') {
alert('Insufficient funds');
} else {
alert('Payment failed: ' + error.message);
}
}
Next Steps
- Set up webhooks for reliable payment notifications
- Add payment status tracking in your app
- Test with small amounts before going live
- Check the API Reference for more features