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

1

Monieswitch Account

A Monieswitch account. Register at Monieswitch Dashboard.
2

API Keys

Your public and secret keys from the Monieswitch dashboard.
3

Web Application

A website or web application where you want to accept payments.

1. Setup

Add Monieswitch Library

Include this script in your HTML:
index.html
<script defer src="https://juju-inline.pages/inline.js"></script>

2. Direct Checkout (Simple)

Best for quick implementations and testing.
index.html
<!DOCTYPE html>
<html>
<head>
  <title>Monieswitch Payment</title>
  <script defer src="https://juju-inline.pages/inline.js"></script>
</head>
<body>
  <form id="paymentForm">
    <input type="email" id="email" placeholder="Email Address" required />
    <input type="number" id="amount" placeholder="Amount in Naira" min="100" required />
    <button type="submit">Pay Now</button>
  </form>

  <script>
    document.getElementById('paymentForm').addEventListener('submit', function(e) {
      e.preventDefault();

      const email = document.getElementById('email').value;
      const amount = document.getElementById('amount').value;

      PayWithMonieswitch.checkout({
        publicKey: 'YOUR_PUBLIC_KEY', // Replace with your public key
        reference: 'ref_' + Date.now(),
        amount: parseFloat(amount),
        email: email,
        currency: 'NGN',
        channels: ['BANK', 'CARD'],

        onClose: function() {
          console.log('Payment cancelled');
        },

        onError: function(error) {
          alert('Payment failed: ' + error.message);
        },

        onSuccess: function(response) {
          alert('Payment successful! Reference: ' + response.reference);
          // Always verify payment on your backend
        }
      });
    });
  </script>
</body>
</html>

More secure as payment details are initialized on your server.

Backend Setup

backend/server.js
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

index.html
<!DOCTYPE html>
<html>
<head>
  <title>Secure Payment</title>
  <script defer src="https://juju-inline.pages/inline.js"></script>
</head>
<body>
  <form id="checkoutForm">
    <input type="email" id="email" placeholder="Email Address" required />
    <input type="number" id="amount" placeholder="Amount in Naira" min="100" required />
    <button type="submit">Pay Securely</button>
  </form>

  <script>
    document.getElementById('checkoutForm').addEventListener('submit', async function(e) {
      e.preventDefault();

      const email = document.getElementById('email').value;
      const amount = document.getElementById('amount').value;

      try {
        // Initialize payment on your backend
        const response = await fetch('/api/checkout/initialize', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ email, amount })
        });

        const data = await response.json();

        // Continue with checkout
        PayWithMonieswitch.continueCheckout({
          checkoutCode: data.checkout.code,

          onClose: function() {
            console.log('Payment cancelled');
          },

          onError: function(error) {
            alert('Payment failed: ' + error.message);
          },

          onSuccess: function(response) {
            alert('Payment successful! Reference: ' + response.reference);
          }
        });

      } catch (error) {
        alert('Failed to initialize payment');
      }
    });
  </script>
</body>
</html>

4. React Example

page.tsx
import React, { useState } from 'react';

const PaymentForm = () => {
  const [email, setEmail] = useState('');
  const [amount, setAmount] = useState('');
  const [loading, setLoading] = useState(false);

  const handlePayment = (e) => {
    e.preventDefault();
    setLoading(true);

    window.PayWithMonieswitch.checkout({
      publicKey: process.env.REACT_APP_MONIESWITCH_PUBLIC_KEY,
      reference: 'ref_' + Date.now(),
      amount: parseFloat(amount),
      email: email,
      currency: 'NGN',
      channels: ['BANK', 'CARD'],

      onClose: () => {
        setLoading(false);
      },

      onError: (error) => {
        setLoading(false);
        alert('Payment failed: ' + error.message);
      },

      onSuccess: (response) => {
        setLoading(false);
        alert('Payment successful! Reference: ' + response.reference);
        setEmail('');
        setAmount('');
      }
    });
  };

  return (
    <form onSubmit={handlePayment}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email Address"
        required
      />
      <input
        type="number"
        value={amount}
        onChange={(e) => setAmount(e.target.value)}
        placeholder="Amount in Naira"
        min="100"
        required
      />
      <button type="submit" disabled={loading}>
        {loading ? 'Processing...' : 'Pay Now'}
      </button>
    </form>
  );
};

export default PaymentForm;

5. Payment Verification

Backend Verification

backend/server.js
// Verify payment after success callback
app.post('/api/verify-payment', async (req, res) => {
  try {
    const { reference } = req.body;

    const response = await axios.get(
      `https://nini.monieswitch.com/api/payments/${reference}`,
      {
        headers: {
          'Authorization': `Bearer ${process.env.MONIESWITCH_SECRET_KEY}`
        }
      }
    );

    const payment = response.data;

    if (payment.status === 'successful') {
      // 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' });
  }
});
backend/server.js
// 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
  1. Client-side: Only use your public key
  2. Server-side: Keep your secret key secure
  3. Verification: Always verify payments on your backend
  4. 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