A robust, modern Node.js library for integrating with Safaricom's M-Pesa Daraja API. Built with TypeScript, comprehensive error handling, and extensive testing.
- 🚀 Modern TypeScript - Full TypeScript support with comprehensive type definitions
- 🔒 Secure - Built-in security credential generation and token management
- 🛡️ Error Handling - Comprehensive error handling and validation
- 📝 Well Documented - Extensive documentation and examples
- 🧪 Thoroughly Tested - 95%+ test coverage
- 🔄 Retry Logic - Built-in retry mechanism for network failures
- 📱 Phone Number Formatting - Automatic phone number formatting and validation
- 🌍 Environment Support - Support for both sandbox and production environments
- 📊 Callback Handling - Built-in utilities for handling M-Pesa callbacks
- ✅ STK Push (Lipa Na M-Pesa Online)
- ✅ STK Push Query (Check payment status)
- ✅ C2B Register URLs (Customer to Business)
- ✅ C2B Simulate (Test C2B payments)
- ✅ B2C Payment (Business to Customer)
- ✅ B2B Payment (Business to Business)
- ✅ Account Balance (Check account balance)
- ✅ Transaction Status (Query transaction status)
- ✅ Transaction Reversal (Reverse transactions)
npm install mpesalib
⚠️ Upgrading from v1.x? This is a complete rewrite with breaking changes. See the Migration Guide for detailed upgrade instructions.
Create a .env
file based on .env.example
:
MPESA_CONSUMER_KEY=your_consumer_key
MPESA_CONSUMER_SECRET=your_consumer_secret
MPESA_ENVIRONMENT=sandbox
MPESA_SHORT_CODE=174379
MPESA_PASSKEY=your_passkey
import { Mpesa } from 'mpesalib';
// Initialize from environment variables
const mpesa = Mpesa.fromEnv();
// Or initialize with config object
const mpesa = new Mpesa({
consumerKey: 'your_consumer_key',
consumerSecret: 'your_consumer_secret',
environment: 'sandbox',
shortCode: '174379',
passkey: 'your_passkey',
});
// STK Push (Customer Payment)
const response = await mpesa.paybillPayment(
1000, // Amount
'254712345678', // Phone number
'INV001', // Account reference
'Payment for services', // Description
'https://yourdomain.com/callback' // Callback URL
);
console.log(response);
Initiate a payment request to customer's phone:
// Paybill payment
const response = await mpesa.paybillPayment(
amount,
phoneNumber,
accountReference,
description,
callbackURL
);
// Buy goods payment
const response = await mpesa.buyGoodsPayment(
amount,
phoneNumber,
accountReference,
description,
callbackURL
);
// Custom STK Push
const response = await mpesa.stkPush({
BusinessShortCode: '174379',
TransactionType: 'CustomerPayBillOnline',
Amount: 1000,
PartyA: '254712345678',
PartyB: '174379',
PhoneNumber: '254712345678',
CallBackURL: 'https://yourdomain.com/callback',
AccountReference: 'TEST001',
TransactionDesc: 'Test payment',
});
Check the status of an STK Push request:
const status = await mpesa.stkPushQuery('ws_CO_12345678');
Register callback URLs and simulate C2B transactions:
// Register URLs
await mpesa.registerC2BUrls({
ShortCode: '600000',
ResponseType: 'Completed',
ConfirmationURL: 'https://yourdomain.com/confirmation',
ValidationURL: 'https://yourdomain.com/validation',
});
// Simulate C2B payment
await mpesa.simulateC2B({
ShortCode: '600000',
CommandID: 'CustomerPayBillOnline',
Amount: 1000,
Msisdn: '254712345678',
BillRefNumber: 'INV001',
});
Send money to customers:
// Business payment
await mpesa.businessPayment(
5000,
'254712345678',
'Business payment',
'https://yourdomain.com/timeout',
'https://yourdomain.com/result'
);
// Salary payment
await mpesa.salaryPayment(
50000,
'254712345678',
'Monthly salary',
'https://yourdomain.com/timeout',
'https://yourdomain.com/result'
);
// Custom B2C
await mpesa.b2cPayment({
InitiatorName: 'testapi',
SecurityCredential: 'credential',
CommandID: 'BusinessPayment',
Amount: 1000,
PartyA: '600000',
PartyB: '254712345678',
Remarks: 'Payment',
QueueTimeOutURL: 'https://yourdomain.com/timeout',
ResultURL: 'https://yourdomain.com/result',
});
Transfer money between businesses:
await mpesa.b2bPayment({
InitiatorName: 'testapi',
SecurityCredential: 'credential',
CommandID: 'BusinessPayBill',
Amount: 1000,
PartyA: '600000',
PartyB: '600001',
RecieverIdentifierType: 4,
Remarks: 'B2B Payment',
QueueTimeOutURL: 'https://yourdomain.com/timeout',
ResultURL: 'https://yourdomain.com/result',
AccountReference: 'TEST001',
});
Check account balance:
await mpesa.getAccountBalance({
InitiatorName: 'testapi',
SecurityCredential: 'credential',
CommandID: 'AccountBalance',
PartyA: '600000',
IdentifierType: '4',
Remarks: 'Balance inquiry',
QueueTimeOutURL: 'https://yourdomain.com/timeout',
ResultURL: 'https://yourdomain.com/result',
});
Query transaction status:
await mpesa.getTransactionStatus({
InitiatorName: 'testapi',
SecurityCredential: 'credential',
CommandID: 'TransactionStatusQuery',
TransactionID: 'OEI2AK4Q16',
PartyA: '600000',
IdentifierType: '4',
ResultURL: 'https://yourdomain.com/result',
QueueTimeOutURL: 'https://yourdomain.com/timeout',
Remarks: 'Status query',
});
Reverse a transaction:
await mpesa.reverseTransaction({
InitiatorName: 'testapi',
SecurityCredential: 'credential',
CommandID: 'TransactionReversal',
TransactionID: 'OEI2AK4Q16',
Amount: 1000,
ReceiverParty: '600000',
RecieverIdentifierType: '4',
ResultURL: 'https://yourdomain.com/result',
QueueTimeOutURL: 'https://yourdomain.com/timeout',
Remarks: 'Reversal',
});
Handle M-Pesa callbacks in your Express.js application:
import express from 'express';
const app = express();
app.use(express.json());
// STK Push callback
app.post('/mpesa/stkpush/callback', (req, res) => {
const callbackData = req.body;
if (callbackData.Body?.stkCallback?.ResultCode === 0) {
console.log('Payment successful!');
// Update your database
} else {
console.log('Payment failed:', callbackData.Body.stkCallback.ResultDesc);
}
res.status(200).json({ status: 'OK' });
});
// B2C result callback
app.post('/mpesa/b2c/result', (req, res) => {
const result = req.body.Result;
if (result.ResultCode === 0) {
console.log('B2C payment successful:', result.TransactionID);
} else {
console.log('B2C payment failed:', result.ResultDesc);
}
res.status(200).json({ status: 'OK' });
});
The library includes helpful utilities:
import { MpesaUtils } from 'mpesalib';
// Format phone numbers
const formatted = MpesaUtils.formatPhoneNumber('0712345678');
// Returns: '254712345678'
// Generate timestamp
const timestamp = MpesaUtils.generateTimestamp();
// Returns: '20231201120000'
// Generate password for STK Push
const password = MpesaUtils.generatePassword(
shortCode,
passkey,
timestamp
);
// Generate security credential
const credential = MpesaUtils.generateSecurityCredential(
initiatorPassword,
certificatePath
);
// Retry failed operations
const result = await MpesaUtils.retry(
async () => mpesa.stkPush(request),
3, // max retries
1000 // delay in ms
);
The library provides comprehensive error handling:
try {
const response = await mpesa.stkPush(request);
console.log('Success:', response);
} catch (error) {
if (error.status === 401) {
console.error('Authentication failed');
} else if (error.status === 400) {
console.error('Bad request:', error.data);
} else {
console.error('Network error:', error.message);
}
}
MPESA_CONSUMER_KEY=your_consumer_key
MPESA_CONSUMER_SECRET=your_consumer_secret
MPESA_ENVIRONMENT=sandbox|production
MPESA_SHORT_CODE=your_shortcode
MPESA_INITIATOR_NAME=your_initiator_name
MPESA_SECURITY_CREDENTIAL=your_security_credential
MPESA_CERTIFICATE_PATH=./path/to/certificate.cer
MPESA_PASSKEY=your_passkey
- Visit Daraja Portal
- Create an account and verify your email
- Login to the portal
- Go to "My Apps" section
- Click "Add a new app"
- Fill in app details:
- App Name: Your application name
- Description: Brief description of your app
- Select APIs: Choose the APIs you need (STK Push, C2B, B2C, etc.)
After creating the app, you'll get:
- Consumer Key: Used for authentication
- Consumer Secret: Used for authentication
For sandbox testing, use these test credentials:
- Short Code: 174379
- Test MSISDN: 254708374149
- Passkey: Get from Daraja portal
For production:
- Request production access from Safaricom
- Get production credentials
- Update your configuration to use production environment
Run the test suite:
npm test
Run tests with coverage:
npm run test:coverage
Run tests in watch mode:
npm run test:watch
- Fork the repository
- Create your feature branch:
git checkout -b feature/amazing-feature
- Make your changes and add tests
- Ensure tests pass:
npm test
- Commit your changes:
git commit -m 'Add amazing feature'
- Push to the branch:
git push origin feature/amazing-feature
- Submit a pull request
- ✨ Complete TypeScript rewrite
- ✨ Modern async/await API
- ✨ Comprehensive error handling
- ✨ Built-in retry mechanism
- ✨ Phone number formatting utilities
- ✨ 95%+ test coverage
- ✨ Updated Daraja API endpoints
- ✨ Environment variable support
- ✨ Callback handling utilities
- Basic JavaScript implementation
- Limited error handling
- No TypeScript support
This project is licensed under the MIT License - see the LICENSE file for details.
- Safaricom for providing the Daraja API
- M-Pesa for the mobile payment platform
- All contributors who have helped improve this library
- M-Pesa Express - Express.js middleware
- M-Pesa Laravel - Laravel package
- M-Pesa PHP - PHP SDK
Made with ❤️ by John Simiyu