Moneroo TypeScript SDK: integrating Mobile Money payments in JavaScript

3 min readApril 29, 2026#moneroo#sdk#typescript#npm#afrique#paiement#open-source

GitHub →npm →


There was no TypeScript SDK for Moneroo. So I built one.

Moneroo is an African payment API — Mobile Money, cards, multiple countries, local currencies (XOF, XAF...).

If you're building a product for the Francophone African market, it's one of the few serious options. The problem: no TypeScript SDK existed.

To integrate Moneroo into a Node.js project, the only option was the raw REST API. Handling authorization headers by hand. Parsing errors by hand. Implementing HMAC webhook verification yourself. No types, no autocomplete, no safety net.

So I built the SDK.


What it is

moneroo — v0.1.1 — available on npm.

Source code: github.com/aboudou-cto-bloko/moneroo-tools

npm install moneroo

Zero external dependencies. Node.js 18+ has fetch natively and node:crypto for webhooks. No need for axios, no node-fetch, no third-party crypto libraries.


How it's used

import { Moneroo } from 'moneroo';
 
const moneroo = new Moneroo({
  secretKey: process.env.MONEROO_SECRET_KEY!,
  webhookSecret: process.env.MONEROO_WEBHOOK_SECRET,
});

Initializing a payment:

const { data } = await moneroo.payments.initialize({
  amount: 5000,     // XOF — no cents (see note below)
  currency: 'XOF',
  description: 'Order #123',
  return_url: 'https://myapp.com/confirmation',
  customer: {
    email: 'client@example.com',
    first_name: 'Koffi',
  },
});
 
// Redirect to data.checkout_url

XOF note: West African currencies (XOF, XAF, GNF, CDF) have no subunit. 5,000 FCFA is 5000. Not 500000. This is a mistake made by everyone coming from Stripe or PayPal. The full insight on this bug →

Verifying a payment before crediting:

const { data } = await moneroo.payments.verify('pay_xxx');
if (data.status === 'success') {
  // credit the account — never on the webhook alone
}

Webhooks — signature verification:

const event = moneroo.webhooks.constructEvent(rawBody, signature);
// Throws an error if the signature is invalid
// event.type === 'payment.success'

The architecture decisions

Zero dependencies. Node 18 has everything needed. One less dependency means one less potential attack surface, a lighter node_modules, and less maintenance overhead.

Dual ESM + CJS export. Whether you're on a modern ESM project or a legacy CommonJS setup — it works with no configuration needed.

"exports": {
  ".": {
    "import": "./dist/esm/index.js",
    "require": "./dist/cjs/index.cjs",
    "types": "./dist/types/index.d.ts"
  }
}

Strict TypeScript everywhere. The accepted payment methods (mtn_bj, wave_sn, orange_ci...), transaction statuses, payout structures — all typed. No any in the critical data paths.


What this changes in practice

With the SDK, the Moneroo code in a Next.js + Convex project boils down to business logic. The headers, error parsing, HMAC verification — all of that disappears.

If you want to see how to integrate this SDK into a complete payment flow with Next.js + Convex (mutation → action → webhook → confirmation), the full tutorial is here: Integrating Moneroo into Next.js + Convex →


Monorepo

The SDK lives inside moneroo-tools — a pnpm monorepo with two packages:

moneroo-tools/
├── packages/sdk/   → moneroo v0.1.1
└── packages/mcp/   → moneroo-mcp v0.4.2

The second package is an MCP server — a completely different interface for operating Moneroo from an AI assistant in natural language. What that enables →


This is v0.1.1. Payments, payouts, and webhooks are covered. If you run into an edge case that isn't handled — open an issue.