Skip to main content

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