npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

moneroo

v0.1.1

Published

TypeScript SDK for the Moneroo API

Readme

moneroo

npm version npm downloads License: MIT

Official TypeScript SDK for the Moneroo payment API. Supports payments, payouts, and webhook verification. Works with Node.js 18+ out of the box — no external HTTP or crypto dependencies.

Built by Aboudou Zinsou · GitHub


Table of contents


Installation

npm install moneroo
# or
pnpm add moneroo
# or
yarn add moneroo

Requirements: Node.js 18+ (uses native fetch and node:crypto)


Quick start

import { Moneroo } from 'moneroo';

const moneroo = new Moneroo({
  secretKey: process.env.MONEROO_SECRET_KEY!,
  webhookSecret: process.env.MONEROO_WEBHOOK_SECRET, // optional — needed for webhook verification
});

Never expose your secretKey in client-side code. Always use it server-side via environment variables.


Payments

Payments follow a redirect flow: your server initializes a transaction, Moneroo returns a checkout URL, and you redirect your customer there.

Initialize a payment

const { data } = await moneroo.payments.initialize({
  amount: 5000,          // integer, smallest currency unit (e.g. 5000 XOF = 5000 CFA)
  currency: 'XOF',
  description: 'Order #123',
  return_url: 'https://yourapp.com/payments/callback',
  customer: {
    email: '[email protected]',
    first_name: 'John',
    last_name: 'Doe',
    phone: '+22951345020',  // optional
  },
  // optional: restrict to specific payment methods
  methods: ['mtn_bj', 'wave_sn', 'orange_ci'],
  // optional: pass through your own data (string values only)
  metadata: {
    order_id: '123',
    customer_id: '456',
  },
});

// Redirect your customer to the checkout page
redirect(data.checkout_url);
console.log(data.id); // save this to retrieve the transaction later

Retrieve a payment

const { data: payment } = await moneroo.payments.retrieve('PAYMENT_ID');

console.log(payment.id);
console.log(payment.status);          // 'initiated' | 'pending' | 'success' | 'failed' | 'cancelled'
console.log(payment.amount);
console.log(payment.currency.code);   // 'XOF'
console.log(payment.customer?.email);

Verify a payment

Always verify before crediting your customer. Check status, amount, and currency.

const { data: payment } = await moneroo.payments.verify('PAYMENT_ID');

if (
  payment.status === 'success' &&
  payment.amount >= expectedAmount &&
  payment.currency.code === expectedCurrency
) {
  // Safe to fulfill the order
}

Payouts

Payouts let you send money directly to a customer's mobile money account.

Initialize a payout

Each payout method has a required recipient field. Most methods use msisdn (phone number in international format). See Available payout methods.

const { data } = await moneroo.payouts.initialize({
  amount: 1000,
  currency: 'XOF',
  description: 'Order #123 refund',
  method: 'mtn_bj',                    // payout method shortcode
  customer: {
    email: '[email protected]',
    first_name: 'John',
    last_name: 'Doe',
  },
  recipient: {
    msisdn: '22951345020',             // MTN MoMo Benin account number
  },
  metadata: { order_id: '123' },
});

console.log(data.id); // track the payout with this ID

Retrieve / Verify a payout

const { data: payout } = await moneroo.payouts.retrieve('PAYOUT_ID');
// or — preferred before crediting your system
const { data: payout } = await moneroo.payouts.verify('PAYOUT_ID');

console.log(payout.status);      // 'initiated' | 'pending' | 'success' | 'failed'
console.log(payout.failed_at);   // null or ISO timestamp
console.log(payout.success_at);  // null or ISO timestamp

Webhooks

Moneroo sends POST requests to your webhook URL after every transaction status change. The request includes an X-Moneroo-Signature header you must verify.

Important: pass the raw body string (before JSON.parse) to the verification methods.

import { Moneroo } from 'moneroo';

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

// Express example — use express.raw() to get the raw body
app.post('/webhooks/moneroo', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-moneroo-signature'] as string;

  let event;
  try {
    event = moneroo.webhooks.constructEvent(req.body.toString(), signature);
  } catch {
    return res.sendStatus(403); // invalid signature
  }

  switch (event.event) {
    case 'payment.success':
      console.log('Payment succeeded:', event.data.id);
      // always re-verify via API before fulfilling
      break;
    case 'payment.failed':
      console.log('Payment failed:', event.data.id);
      break;
    case 'payout.success':
      console.log('Payout sent:', event.data.id);
      break;
    case 'payout.failed':
      console.log('Payout failed:', event.data.id);
      break;
  }

  res.sendStatus(200); // acknowledge within 3 seconds
});

Verify only (without parsing)

const isValid = moneroo.webhooks.verify(rawBody, signature);

Standalone helpers (without a client instance)

import { verifySignature, constructWebhookEvent } from 'moneroo';

const valid = verifySignature(rawBody, signature, process.env.MONEROO_WEBHOOK_SECRET!);
const event = constructWebhookEvent(rawBody, signature, process.env.MONEROO_WEBHOOK_SECRET!);

Webhook events

| Event | Trigger | |---|---| | payment.initiated | Customer starts a payment | | payment.success | Payment completed successfully | | payment.failed | Payment failed | | payment.cancelled | Payment cancelled | | payout.initiated | Payout queued | | payout.success | Payout delivered | | payout.failed | Payout failed |


Error handling

All API errors throw a specific subclass of MonerooError. Catch them individually or as a group.

import {
  AuthenticationError,
  MonerooError,
  NotFoundError,
  RateLimitError,
  ServerError,
  ValidationError,
} from 'moneroo';

try {
  const { data } = await moneroo.payments.retrieve('bad_id');
} catch (error) {
  if (error instanceof NotFoundError) {
    // 404 — transaction does not exist
    console.log('Not found');
  } else if (error instanceof ValidationError) {
    // 400 / 422 — bad parameters
    console.log('Validation errors:', error.errors);
  } else if (error instanceof AuthenticationError) {
    // 401 / 403 — invalid or missing API key
    console.log('Check your secret key');
  } else if (error instanceof RateLimitError) {
    // 429 — exceeded 120 req/min
    console.log(`Rate limited, retry in ${error.retryAfterMs}ms`);
    await new Promise((r) => setTimeout(r, error.retryAfterMs));
  } else if (error instanceof ServerError) {
    // 500 / 503 — Moneroo server error, safe to retry
    console.log(`Server error ${error.status}`);
  } else if (error instanceof MonerooError) {
    // catch-all for any other API error
    console.log(`API error ${error.status}: ${error.message}`);
  }
}

Error classes

| Class | HTTP | Cause | |---|---|---| | AuthenticationError | 401, 403 | Invalid or missing API key, insufficient permissions | | ValidationError | 400, 422 | Missing or invalid parameters | | NotFoundError | 404 | Resource does not exist | | RateLimitError | 429 | Over 120 requests/minute — retryAfterMs = 60000 | | ServerError | 500, 503 | Moneroo server error, safe to retry | | MonerooError | any | Base class — all errors above extend this |

All error instances expose:

  • error.status — HTTP status code
  • error.message — human-readable message from the API
  • error.errors — array of ApiErrorDetail objects or null

Payment statuses

| Status | Type | Description | |---|---|---| | initiated | Transitional | Awaiting customer action on checkout page | | pending | Transitional | Customer started paying, not completed yet | | success | Final | Payment completed successfully | | failed | Final | Payment failed | | cancelled | Final | Payment cancelled (payments only) |

Always re-verify a transaction via payments.verify() before fulfilling orders. Do not rely solely on webhooks.


Payout methods

Most methods require a recipient.msisdn field (phone number in international format, e.g. 22951345020).
The test method moneroo_payout_demo requires recipient.account_number.

Popular methods:

| Code | Method | Currency | Countries | |---|---|---|---| | mtn_bj | MTN MoMo Benin | XOF | BJ | | mtn_ci | MTN MoMo Côte d'Ivoire | XOF | CI | | wave_sn | Wave Senegal | XOF | SN | | wave_ci | Wave Côte d'Ivoire | XOF | CI | | orange_sn | Orange Money Senegal | XOF | SN | | orange_ci | Orange Money CI | XOF | CI | | mpesa_ke | M-Pesa Kenya | KES | KE | | mtn_gh | MTN MoMo Ghana | GHS | GH |

Full list available at docs.moneroo.io/payouts/available-methods or via GET /utils/payout/methods.


Sandbox & testing

Use sandbox API keys from your Moneroo dashboard → Developers → API Keys.

Test phone numbers for the default Moneroo Test Gateway:

| Phone | Scenario | |---|---| | (414) 951-8161 | Successful transaction | | (414) 951-8162 | Pending transaction | | (414) 951-8163 | Failed transaction |

Sandbox data is automatically deleted after 90 days.


TypeScript

All types are exported from the main entry point:

import type {
  // Client
  MonerooClientOptions,

  // Payments
  PaymentInitializeParams,
  PaymentInitializeData,
  PaymentResponse,
  PaymentStatus,
  CustomerInput,
  Customer,

  // Payouts
  PayoutInitializeParams,
  PayoutInitializeData,
  PayoutResponse,
  PayoutStatus,
  PayoutRecipient,

  // Webhooks
  WebhookEvent,
  WebhookEventType,
  WebhookPaymentData,
  WebhookPayoutData,

  // Common
  ApiResponse,
  ApiErrorDetail,
} from 'moneroo';

Contributing

See CONTRIBUTING.md.

License

MITAboudou Zinsou