DEV Community

Cover image for Building a React Native NPM Library for Moniepoint POS SDK - Transforming Revenue Collection in Nigeria
Kigbu Amekalo
Kigbu Amekalo

Posted on

Building a React Native NPM Library for Moniepoint POS SDK - Transforming Revenue Collection in Nigeria

Building a React Native NPM Library for Moniepoint POS SDK: A Journey from Field Agents to Open Source

🎯 The Problem We Solved

At Flopay, we're revolutionizing revenue collection and remittance across Nigeria. As a product by I-Tech Platform Limited, we help government bodies, schools, churches, and enterprises streamline their revenue management — from informal market levies to formal tax remittances.

Our field agents use the Flopay Agent Mobile App to process payments on behalf of organizations. They collect everything from school fees to government taxes, serving millions of payers across multiple states including Adamawa, Yobe, Borno, and Taraba.

But we faced a critical challenge: How do we enable seamless card payments and provide instant printed receipts as proof of payment in the field?

Enter Moniepoint — Africa's fastest-growing financial institution and Nigeria's largest merchant acquirer, processing $17 billion monthly for over 10 million business and individual accounts.


💡 Why Moniepoint POS?

Moniepoint powers most of Nigeria's Point of Sale (POS) transactions. Their PaaP SDK (Payment as a Platform) allows developers to deploy custom applications directly to Moniepoint POS terminals, enabling:

  • Card Payment Processing — Accept debit/credit cards seamlessly
  • Receipt Printing — Print branded receipts with logos, QR codes, and custom formatting
  • POS Transfer Acceptance — Handle bank transfers at the terminal
  • Terminal Data Access — Get device info for audit trails
  • NFC Support — Read ID cards and loyalty cards

This was perfect for our use case: Field agents collecting revenue with instant payment processing and receipt printing.


🏗️ The Challenge: Making It Reusable

Initially, we integrated the Moniepoint PaaP SDK directly into our Flopay Agent App (written in React Native). The integration worked beautifully, but we realized:

"Other businesses in Nigeria face the same challenge. What if we could package this into a reusable npm library?"

We decided to create react-native-moniepoint-pos-sdk — an open-source npm package that any React Native developer can install and use to deploy their apps to Moniepoint POS terminals.


📦 Introducing react-native-moniepoint-pos-sdk

Installation

npm install react-native-moniepoint-pos-sdk
Enter fullscreen mode Exit fullscreen mode

Quick Example

import MoniepointPosSdk, {
  ReceiptItemType,
} from 'react-native-moniepoint-pos-sdk';

// 1️⃣ Process a card payment (amount in Naira)
const handlePayment = async () => {
  try {
    const result = await MoniepointPosSdk.makeCardPayment('5000'); // ₦5,000
    console.log('Payment approved:', result);
  } catch (error) {
    console.error('Payment failed:', error.message);
  }
};

// 2️⃣ Print a branded receipt with logo and QR code
const handlePrintReceipt = async () => {
  const receipt = [
    {type: ReceiptItemType.IMAGE, value: 'base64EncodedLogo...'},
    {type: ReceiptItemType.LABEL, value: 'FLOPAY AGENT'},
    {type: ReceiptItemType.TITLE, value: 'PAYMENT RECEIPT'},
    {type: ReceiptItemType.SEPARATOR},
    {type: ReceiptItemType.KEY_VALUE, key: 'Amount:', value: '₦5,000.00'},
    {
      type: ReceiptItemType.KEY_VALUE,
      key: 'Date:',
      value: new Date().toLocaleDateString(),
    },
    {type: ReceiptItemType.KEY_VALUE, key: 'Status:', value: 'PAID'},
    {type: ReceiptItemType.SEPARATOR},
    {type: ReceiptItemType.QR, value: 'https://flopay.net/receipt/TXN123456'},
    {type: ReceiptItemType.LABEL, value: 'Thank you for your payment'},
  ];

  await MoniepointPosSdk.printReceipt(receipt);
};

// 3️⃣ Get terminal information (for audit trails)
const getTerminalInfo = async () => {
  const info = await MoniepointPosSdk.getTerminalData();
  console.log('Terminal ID:', info.terminalId);
  console.log('Serial No:', info.serialNo);
};
Enter fullscreen mode Exit fullscreen mode

🚀 Real-World Use Cases in Nigeria

Based on Moniepoint's official documentation and our experience with Flopay, here are powerful use cases for this SDK:

1. 🏛️ Government Revenue Collection (Our Use Case!)

Scenario: Field agents collect market levies, property taxes, or license fees.

Implementation:

// Accept card payment for government levy
const collectTax = async (payerName, amount, levyType) => {
  try {
    const result = await MoniepointPosSdk.makeCardPayment(amount);

    // Print official government receipt
    const receipt = [
      {type: ReceiptItemType.LABEL, value: 'TARABA STATE GOVERNMENT'},
      {type: ReceiptItemType.TITLE, value: 'TAX RECEIPT'},
      {type: ReceiptItemType.SEPARATOR},
      {type: ReceiptItemType.KEY_VALUE, key: 'Payer Name', value: payerName},
      {type: ReceiptItemType.KEY_VALUE, key: 'Levy Type', value: levyType},
      {type: ReceiptItemType.KEY_VALUE, key: 'Amount', value: `₦${amount}`},
      {type: ReceiptItemType.KEY_VALUE, key: 'Txn Ref', value: result},
      {type: ReceiptItemType.SEPARATOR},
      {
        type: ReceiptItemType.LABEL,
        value: 'Authorized Signature: _____________',
      },
    ];

    await MoniepointPosSdk.printReceipt(receipt);
  } catch (error) {
    console.error('Tax collection failed:', error);
  }
};
Enter fullscreen mode Exit fullscreen mode

Business Value:

  • ✅ Transparent audit trail with transaction references
  • ✅ Instant printed proof of payment reduces disputes
  • ✅ Digital records improve compliance

2. 🏫 School Fees Collection

Scenario: Schools accept tuition payments directly on campus.

const collectSchoolFees = async (studentName, studentClass, term, amount) => {
  const result = await MoniepointPosSdk.makeCardPayment(amount);

  const receipt = [
    {type: ReceiptItemType.LABEL, value: 'SUNRISE COLLEGE'},
    {type: ReceiptItemType.TITLE, value: 'SCHOOL FEES RECEIPT'},
    {type: ReceiptItemType.SEPARATOR},
    {type: ReceiptItemType.KEY_VALUE, key: 'Student', value: studentName},
    {type: ReceiptItemType.KEY_VALUE, key: 'Class', value: studentClass},
    {type: ReceiptItemType.KEY_VALUE, key: 'Term', value: term},
    {type: ReceiptItemType.KEY_VALUE, key: 'Amount', value: `₦${amount}`},
    {type: ReceiptItemType.LABEL, value: 'Thank you for your payment'},
  ];

  await MoniepointPosSdk.printReceipt(receipt);
};
Enter fullscreen mode Exit fullscreen mode

3. ⛪ Church Revenue Management

Scenario: Digitize tithes, offerings, and event registrations across branches.

const recordOffering = async (memberName, offeringType, amount) => {
  const result = await MoniepointPosSdk.makeCardPayment(amount);

  const receipt = [
    {type: ReceiptItemType.LABEL, value: 'CHURCH OF CHRIST IN NATIONS'},
    {type: ReceiptItemType.TITLE, value: 'OFFERING RECEIPT'},
    {type: ReceiptItemType.SEPARATOR},
    {type: ReceiptItemType.KEY_VALUE, key: 'Member', value: memberName},
    {type: ReceiptItemType.KEY_VALUE, key: 'Type', value: offeringType},
    {type: ReceiptItemType.KEY_VALUE, key: 'Amount', value: `₦${amount}`},
    {type: ReceiptItemType.LABEL, value: 'God bless you!'},
  ];

  await MoniepointPosSdk.printReceipt(receipt);
};
Enter fullscreen mode Exit fullscreen mode

4. 🏥 Healthcare & Pharmacy Billing

Scenario: Hospitals and clinics process patient payments with detailed receipts.

const processPatientBilling = async (patientName, services, totalAmount) => {
  const result = await MoniepointPosSdk.makeCardPayment(totalAmount);

  const receipt = [
    {type: ReceiptItemType.IMAGE, value: hospitalLogoBase64},
    {type: ReceiptItemType.LABEL, value: 'Sunrise Medical Center'},
    {type: ReceiptItemType.TITLE, value: 'Patient Billing Receipt'},
    {type: ReceiptItemType.SEPARATOR},
    {type: ReceiptItemType.KEY_VALUE, key: 'Patient', value: patientName},
    ...services.map(service => ({
      type: ReceiptItemType.KEY_VALUE,
      key: service.name,
      value: `₦${service.cost}`,
    })),
    {type: ReceiptItemType.SEPARATOR},
    {type: ReceiptItemType.KEY_VALUE, key: 'Total', value: `₦${totalAmount}`},
    {
      type: ReceiptItemType.QR,
      value: `https://hospital.com/receipt/${patientId}`,
    },
  ];

  await MoniepointPosSdk.printReceipt(receipt);
};
Enter fullscreen mode Exit fullscreen mode

5. 🛒 Retail POS with Inventory Sync

Scenario: Small businesses process checkout with card payments and printed receipts.

const processCheckout = async (items, total) => {
  const result = await MoniepointPosSdk.makeCardPayment(total);

  const receipt = [
    {type: ReceiptItemType.IMAGE, value: storeLogoBase64},
    {type: ReceiptItemType.LABEL, value: 'YOUR STORE NAME'},
    {type: ReceiptItemType.SEPARATOR},
    {type: ReceiptItemType.TITLE, value: 'SALES RECEIPT'},
    ...items.map(item => ({
      type: ReceiptItemType.KEY_VALUE,
      key: item.name,
      value: `₦${item.price}`,
    })),
    {type: ReceiptItemType.SEPARATOR},
    {type: ReceiptItemType.KEY_VALUE, key: 'Total', value: `₦${total}`},
    {type: ReceiptItemType.LABEL, value: 'Thank you for shopping with us!'},
  ];

  await MoniepointPosSdk.printReceipt(receipt);
};
Enter fullscreen mode Exit fullscreen mode

🔧 How We Built It

1️⃣ Native Android Module (Kotlin)

We bridged the Moniepoint PaaP SDK to React Native using Kotlin:

class MoniepointPosModule(
    private val reactContext: ReactApplicationContext,
    private val moniepointPaapSdk: MoniepointPaapSdk
) : ReactContextBaseJavaModule(reactContext) {

    @ReactMethod
    fun makeCardPayment(amount: String, promise: Promise) {
        try {
            val amountInKobo = (amount.toDouble() * 100).toLong()
            moniepointPaapSdk.cardPaymentService.makeCardPayment(amountInKobo) { response ->
                if (response.responseCode == "00") {
                    promise.resolve(response.reference)
                } else {
                    promise.reject("PAYMENT_FAILED", response.message)
                }
            }
        } catch (e: Exception) {
            promise.reject("PAYMENT_ERROR", e.message)
        }
    }

    @ReactMethod
    fun printReceipt(items: ReadableArray, promise: Promise) {
        try {
            val receiptItems = parseReceiptItems(items)
            moniepointPaapSdk.printerService.print(receiptItems)
            promise.resolve("Receipt printed successfully")
        } catch (e: Exception) {
            promise.reject("PRINT_ERROR", e.message)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

2️⃣ JavaScript Interface

We created a clean JavaScript API with TypeScript definitions:

export declare class MoniepointPosSdk {
  static makeCardPayment(amount: string | number): Promise<string>;
  static printReceipt(items: ReceiptItem[]): Promise<void>;
  static getTerminalData(): Promise<TerminalData>;
  static acceptPosTransfer(reference: string): Promise<void>;
}

export type ReceiptItemType =
  | 'IMAGE'
  | 'LABEL'
  | 'TITLE'
  | 'KEY_VALUE'
  | 'SEPARATOR'
  | 'SPACING'
  | 'QR';
Enter fullscreen mode Exit fullscreen mode

3️⃣ Secure Credential Management

Moniepoint requires Maven repository credentials. We made this flexible:

Option A: local.properties (Development)

moniepointRepoUrl=https://open-repository.moniepoint.com/repository/public
moniepointUsername=your_username
moniepointPassword=your_password
moniepointSdkVersion=1.0.10
Enter fullscreen mode Exit fullscreen mode

Option B: Environment Variables (CI/CD)

export MONIEPOINT_REPO_URL=https://...
export MONIEPOINT_USERNAME=...
export MONIEPOINT_PASSWORD=...
Enter fullscreen mode Exit fullscreen mode

The SDK's build.gradle reads from both sources:

def localProperties = new Properties()
def localPropertiesFile = file("../../local.properties")
if (localPropertiesFile.exists()) {
    localPropertiesFile.withInputStream { stream -> localProperties.load(stream) }
}

def repoUrl = localProperties.getProperty("moniepointRepoUrl")
    ?: project.findProperty("moniepointRepoUrl")
    ?: System.getenv("MONIEPOINT_REPO_URL")
Enter fullscreen mode Exit fullscreen mode

📊 Business Impact for Flopay

Since deploying our app to Moniepoint POS terminals, we've achieved:

  • ₦36 billion in revenue processed
  • Over 1.2 million student registrations processed
  • 100,000+ payers enumerated across multiple states
  • Zero disputes over payment receipts (printed proof eliminates conflicts)
  • Faster collections — agents no longer need separate card readers

Our field agents now carry a single Moniepoint POS terminal that runs the Flopay Agent App, processes card payments, and prints official receipts — all in one device.


🇳🇬 Why This Matters for Nigerian Businesses

Nigeria's economy thrives on informal sector transactions. According to Moniepoint's 2024 Informal Economy Report, millions of businesses operate outside traditional banking infrastructure.

The react-native-moniepoint-pos-sdk democratizes access to:

  1. Digital Payment Acceptance — Move from cash-only to card payments
  2. Financial Inclusion — Serve customers in remote areas
  3. Trust Through Receipts — Printed receipts build credibility
  4. Business Growth — Access to Moniepoint's 10M+ user network

Whether you're building solutions for:

  • 🏛️ Government revenue collection
  • 🏫 School fee management
  • ⛪ Church finance digitization
  • 🏥 Healthcare billing
  • 🛒 Retail POS systems
  • 🚚 Logistics and delivery

...you can now deploy your React Native app to Moniepoint POS terminals in minutes instead of weeks.


🎁 Open Source & Community

We've published react-native-moniepoint-pos-sdk to npm under a permissive license. Check it out:

Installation Guide

# 1. Install the package
npm install react-native-moniepoint-pos-sdk

# 2. Configure Moniepoint credentials (android/local.properties)
moniepointRepoUrl=https://open-repository.moniepoint.com/repository/public
moniepointUsername=your_username
moniepointPassword=your_password
moniepointSdkVersion=1.0.10

# 3. Initialize the SDK in MainApplication.kt
import com.moniepoint.paap.sdk.MoniepointPaapSdk
import com.moniepoint.paap.sdk.MoniepointPaapConfig
import com.moniepointpossdk.MoniepointPosPackage

val config = MoniepointPaapConfig.Builder()
    .enableCardPayment(true)
    .enablePrinting(true)
    .enableInAppPrinting(true)
    .build()

val moniepointSdk = MoniepointPaapSdk.initialize(this, config)

// Add to packages list
packages.add(MoniepointPosPackage(moniepointSdk))

# 4. Start building!
Enter fullscreen mode Exit fullscreen mode

Full documentation and examples are included in the package README.


💭 Lessons Learned

1. React Native's Autolinking Had to Be Disabled

The Moniepoint SDK requires initialization with a configuration object. React Native's automatic package linking doesn't support constructor arguments, so we:

  • Disabled autolinking via react-native.config.js
  • Manually registered the package in MainApplication.kt with the initialized SDK instance

2. Credential Management is Critical

Developers need Moniepoint Maven credentials to download the SDK. We made this flexible:

  • Development: Use local.properties (gitignored)
  • CI/CD: Use environment variables
  • Team Sharing: Use gradle.properties.example as a template

3. Receipt Printing Requires Base64 Encoding

Moniepoint's printer accepts images as Base64 strings. We documented how to convert logos:

import {readFile} from 'react-native-fs';

const logoBase64 = await readFile('path/to/logo.png', 'base64');
Enter fullscreen mode Exit fullscreen mode

4. TypeScript Definitions Matter

We provided full TypeScript definitions for better developer experience:

  • Autocomplete in VS Code
  • Type safety for receipt items
  • Clear error messages

🚀 What's Next?

We're working on:

  • iOS Support — Currently Android-only, iOS support coming soon
  • POS Transfer Support — Accept bank transfers at the terminal
  • NFC Card Reading — Read ID cards and loyalty cards
  • Example Apps — More real-world implementation examples
  • Video Tutorials — Step-by-step integration guides

🤝 Join the Movement

If you're building fintech solutions in Nigeria or across Africa, we'd love to collaborate!

  • Try the SDK: npm install react-native-moniepoint-pos-sdk
  • Share Your Use Case: What are you building? Let us know in the comments!
  • Contribute: Found a bug or have a feature request? PRs welcome!
  • Learn More About Flopay: https://flopay.net/
  • Explore Moniepoint: https://moniepoint.com/

📌 Key Takeaways

  1. Moniepoint POS SDK enables custom apps on POS terminals — a game-changer for Nigerian businesses
  2. react-native-moniepoint-pos-sdk packages this power into an easy-to-use npm library
  3. Flopay's success story (₦36B processed, 1.2M+ registrations) proves the business value
  4. Open source wins — by sharing our work, we're accelerating fintech innovation in Africa

🔗 Useful Links


🙏 Acknowledgments

  • I-Tech Platform Limited — For building Flopay and supporting this open-source initiative
  • Moniepoint — For providing an excellent PaaP SDK and comprehensive documentation
  • Our Field Agents — For the invaluable feedback that shaped this solution
  • The React Native Community — For the amazing tools and ecosystem

Have questions or want to share your implementation? Drop a comment below! 👇


Tags: #ReactNative #Android #Fintech #Nigeria #OpenSource #Moniepoint #Flopay #POS #MobilePayments #AfricanTech


About the Author:
I'm a software engineer at I-Tech Platform Limited, working on Flopay — Nigeria's leading revenue collection and remittance platform. We're transforming how governments, schools, churches, and enterprises manage their finances across Africa.

Connect with Flopay:

  • Website: https://flopay.net/
  • Trusted by: Adamawa State Govt, Yobe State Govt, COCIN, WAEC, Borno State IRS, Taraba State IRS, University of Maiduguri, and more.

© 2025 I-Tech Platform Limited. All rights reserved.

Top comments (0)