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://monieswitch-staging-checkout-inline.pages.dev/inline.js"
></script>

2. Direct Checkout (Simple)

Best for quick implementations and testing.
index.html
<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>

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 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

backend/server.js
// 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" });
  }
});
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