mpesa-nodejs-sdk-unofficial-version
v1.0.0
Published
A Node.js SDK for M-Pesa API integration
Downloads
5
Maintainers
Readme
M-Pesa Node.js SDK
A comprehensive Node.js SDK for integrating with the M-Pesa payment API. This library provides easy-to-use methods for all major M-Pesa operations including C2B, B2C, B2B transactions, transaction status queries, reversals, and customer name queries.
Table of Contents
- Installation
- Quick Start
- Configuration
- API Methods
- Error Handling
- Utilities
- Examples
- API Reference
- Contributing
- License
Installation
npm install mpesa-nodejs-sdkQuick Start
const Mpesa = require('mpesa-nodejs-sdk');
// Initialize the client
const mpesa = new Mpesa({
apiKey: 'your-api-key',
publicKey: 'your-public-key',
baseUrl: 'https://api.sandbox.vm.co.mz', // Use sandbox for testing
ssl: true
});
// Make a C2B transaction
async function makePayment() {
try {
const result = await mpesa.c2b({
input_TransactionReference: 'T12344C',
input_CustomerMSISDN: '258843330333',
input_Amount: '10.00',
input_ThirdPartyReference: Mpesa.generateThirdPartyReference(),
input_ServiceProviderCode: '171717'
});
console.log('Transaction successful:', result.isSuccess);
console.log('Transaction ID:', result.output_TransactionID);
} catch (error) {
console.error('Transaction failed:', error.message);
}
}
makePayment();Configuration
The SDK requires the following configuration parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| apiKey | string | Yes | Your M-Pesa API key |
| publicKey | string | Yes | Your M-Pesa public key |
| baseUrl | string | No | API base URL (defaults to sandbox) |
| environment | string | No | API environment (
SANDBOX or PRODUCTION, defaults to SANDBOX) |
| ssl | boolean | No | Enable SSL (default: true) |
| origin | string | No | CORS origin (default: developer.mpesa.vm.co.mz) |
| timeout | number | No | Request timeout in ms (default: 30000) |
Environment Configuration
You can specify the environment parameter in the configuration to switch between SANDBOX and PRODUCTION.
// For Sandbox environment (default)
const mpesaSandbox = new Mpesa({
apiKey: process.env.MPESA_SANDBOX_API_KEY,
publicKey: process.env.MPESA_SANDBOX_PUBLIC_KEY,
environment: 'SANDBOX' // Optional, as it's the default
});
// For Production environment
const mpesaProduction = new Mpesa({
apiKey: process.env.MPESA_PRODUCTION_API_KEY,
publicKey: process.env.MPESA_PRODUCTION_PUBLIC_KEY,
environment: 'PRODUCTION'
});If the environment parameter is not provided, it defaults to SANDBOX.
API Methods
Customer to Business (C2B)
Initiate a payment from a customer to your business.
const result = await mpesa.c2b({
input_TransactionReference: 'T12344C',
input_CustomerMSISDN: '258843330333',
input_Amount: '10.00',
input_ThirdPartyReference: 'unique-ref-123',
input_ServiceProviderCode: '171717'
});Business to Customer (B2C)
Send money from your business to a customer.
const result = await mpesa.b2c({
input_TransactionReference: 'T12345C',
input_CustomerMSISDN: '258843330333',
input_Amount: '15.50',
input_ThirdPartyReference: 'unique-ref-124',
input_ServiceProviderCode: '171717'
});Business to Business (B2B)
Transfer money between business accounts.
const result = await mpesa.b2b({
input_TransactionReference: 'T12346C',
input_Amount: '100.00',
input_ThirdPartyReference: 'unique-ref-125',
input_PrimaryPartyCode: '171717',
input_ReceiverPartyCode: '979797'
});Query Transaction Status
Check the status of a transaction.
const result = await mpesa.queryTransactionStatus({
input_ThirdPartyReference: 'unique-ref-123',
input_QueryReference: '5C1400CVRO',
input_ServiceProviderCode: '171717'
});
console.log('Status:', result.output_ResponseTransactionStatus);Transaction Reversal
Reverse a completed transaction.
const result = await mpesa.reversal({
input_TransactionID: '49XCDF6',
input_SecurityCredential: 'your-security-credential',
input_InitiatorIdentifier: 'your-initiator-id',
input_ThirdPartyReference: 'unique-ref-126',
input_ServiceProviderCode: '171717',
input_ReversalAmount: '10.00' // Optional for partial reversal
});Query Customer Masked Name
Get the masked name of a customer.
const result = await mpesa.queryCustomerMaskedName({
input_CustomerMSISDN: '258843330333',
input_ThirdPartyReference: 'unique-ref-127',
input_ServiceProviderCode: '171717'
});
console.log('Customer name:', result.output_CustomerName);Error Handling
The SDK provides comprehensive error handling with specific error types for different scenarios.
Error Types
- MpesaError: Base error class for all M-Pesa related errors
- MpesaAuthenticationError: Authentication and authorization errors
- MpesaValidationError: Input validation errors
- MpesaApiError: API response errors
- MpesaNetworkError: Network and connectivity errors
Error Handling Example
const { MpesaError, MpesaAuthenticationError, MpesaValidationError } = require('mpesa-nodejs-sdk/lib/utils/errors');
try {
const result = await mpesa.c2b({
input_TransactionReference: 'T12344C',
input_CustomerMSISDN: '258843330333',
input_Amount: '10.00',
input_ThirdPartyReference: 'unique-ref-123',
input_ServiceProviderCode: '171717'
});
} catch (error) {
if (error instanceof MpesaAuthenticationError) {
console.error('Authentication failed:', error.message);
// Handle authentication error
} else if (error instanceof MpesaValidationError) {
console.error('Validation error:', error.message);
console.error('Field:', error.field);
// Handle validation error
} else if (error instanceof MpesaError) {
console.error('M-Pesa error:', error.message);
console.error('Code:', error.code);
console.error('Response:', error.response);
// Handle other M-Pesa errors
} else {
console.error('Unexpected error:', error.message);
// Handle unexpected errors
}
}Response Codes
The SDK automatically parses API response codes and provides human-readable descriptions:
| Code | Description | |------|-------------| | INS-0 | Request processed successfully | | INS-1 | Internal Error | | INS-2 | Invalid API Key | | INS-4 | User is not active | | INS-5 | Transaction cancelled by customer | | INS-6 | Transaction Failed | | INS-9 | Request timeout | | INS-10 | Duplicate Transaction | | INS-13 | Invalid Shortcode Used | | INS-14 | Invalid Reference Used | | INS-15 | Invalid Amount Used |
For a complete list of response codes, see the API Reference section.
Utilities
The SDK includes several utility functions to help with common operations.
Static Methods
// Generate unique references
const thirdPartyRef = Mpesa.generateThirdPartyReference(); // Returns: "A1B2C3"
const transactionRef = Mpesa.generateTransactionReference(); // Returns: "T12A34B5"
// Format and validate data
const formattedMSISDN = Mpesa.formatMSISDN('843330333'); // Returns: "258843330333"
const formattedAmount = Mpesa.formatAmount('10'); // Returns: "10.00"
// Validation
const isValidMSISDN = Mpesa.validateMSISDN('258843330333'); // Returns: true
const isValidAmount = Mpesa.validateAmount('10.50'); // Returns: trueHelper Functions
const {
getResponseDescription,
isSuccessResponse,
formatMSISDN,
generateTransactionReference
} = require('mpesa-nodejs-sdk/lib/utils/helpers');
// Get description for response code
const description = getResponseDescription('INS-0'); // Returns: "Request processed successfully"
// Check if response indicates success
const isSuccess = isSuccessResponse('INS-0'); // Returns: true
// Format MSISDN
const msisdn = formatMSISDN('843330333'); // Returns: "258843330333"
// Generate transaction reference
const ref = generateTransactionReference(); // Returns: "A1B2C3D4"Examples
Complete Transaction Flow
const Mpesa = require('mpesa-nodejs-sdk');
const mpesa = new Mpesa({
apiKey: 'your-api-key',
publicKey: 'your-public-key',
baseUrl: 'https://api.sandbox.vm.co.mz'
});
async function completeTransactionFlow() {
try {
// Step 1: Initiate C2B transaction
const thirdPartyRef = Mpesa.generateThirdPartyReference();
const c2bResult = await mpesa.c2b({
input_TransactionReference: 'ORDER-001',
input_CustomerMSISDN: '258843330333',
input_Amount: '25.00',
input_ThirdPartyReference: thirdPartyRef,
input_ServiceProviderCode: '171717'
});
if (c2bResult.isSuccess) {
console.log('Payment initiated successfully');
console.log('Transaction ID:', c2bResult.output_TransactionID);
// Step 2: Query transaction status
const statusResult = await mpesa.queryTransactionStatus({
input_ThirdPartyReference: thirdPartyRef,
input_QueryReference: c2bResult.output_TransactionID,
input_ServiceProviderCode: '171717'
});
console.log('Transaction Status:', statusResult.output_ResponseTransactionStatus);
// Step 3: If needed, reverse the transaction
if (statusResult.output_ResponseTransactionStatus === 'Completed') {
const reversalResult = await mpesa.reversal({
input_TransactionID: c2bResult.output_TransactionID,
input_SecurityCredential: 'your-security-credential',
input_InitiatorIdentifier: 'your-initiator-id',
input_ThirdPartyReference: Mpesa.generateThirdPartyReference(),
input_ServiceProviderCode: '171717'
});
if (reversalResult.isSuccess) {
console.log('Transaction reversed successfully');
}
}
}
} catch (error) {
console.error('Transaction flow failed:', error.message);
}
}
completeTransactionFlow();Batch Processing
async function processBatchPayments(payments) {
const results = [];
for (const payment of payments) {
try {
const result = await mpesa.b2c({
input_TransactionReference: payment.reference,
input_CustomerMSISDN: payment.msisdn,
input_Amount: payment.amount,
input_ThirdPartyReference: Mpesa.generateThirdPartyReference(),
input_ServiceProviderCode: '171717'
});
results.push({
reference: payment.reference,
success: result.isSuccess,
transactionId: result.output_TransactionID,
error: null
});
// Add delay between requests to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 1000));
} catch (error) {
results.push({
reference: payment.reference,
success: false,
transactionId: null,
error: error.message
});
}
}
return results;
}
// Usage
const payments = [
{ reference: 'PAY-001', msisdn: '258843330333', amount: '10.00' },
{ reference: 'PAY-002', msisdn: '258843330334', amount: '15.00' },
{ reference: 'PAY-003', msisdn: '258843330335', amount: '20.00' }
];
processBatchPayments(payments).then(results => {
console.log('Batch processing results:', results);
});API Reference
Constructor
new Mpesa(config)
Creates a new M-Pesa client instance.
Parameters:
config(Object): Configuration objectapiKey(string): Your M-Pesa API keypublicKey(string): Your M-Pesa public keybaseUrl(string, optional): API base URL (default: sandbox)ssl(boolean, optional): Enable SSL (default: true)origin(string, optional): CORS origintimeout(number, optional): Request timeout in milliseconds
Instance Methods
mpesa.c2b(params)
Initiates a Customer to Business transaction.
Parameters:
input_TransactionReference(string): Transaction referenceinput_CustomerMSISDN(string): Customer mobile number (format: 258XXXXXXXXX)input_Amount(string): Transaction amountinput_ThirdPartyReference(string): Unique third party referenceinput_ServiceProviderCode(string): Service provider code
Returns: Promise - API response with transaction details
mpesa.b2c(params)
Initiates a Business to Customer transaction.
Parameters:
input_TransactionReference(string): Transaction referenceinput_CustomerMSISDN(string): Customer mobile numberinput_Amount(string): Transaction amountinput_ThirdPartyReference(string): Unique third party referenceinput_ServiceProviderCode(string): Service provider code
Returns: Promise - API response with transaction details
mpesa.b2b(params)
Initiates a Business to Business transaction.
Parameters:
input_TransactionReference(string): Transaction referenceinput_Amount(string): Transaction amountinput_ThirdPartyReference(string): Unique third party referenceinput_PrimaryPartyCode(string): Primary party (sender) codeinput_ReceiverPartyCode(string): Receiver party code
Returns: Promise - API response with transaction details
mpesa.queryTransactionStatus(params)
Queries the status of a transaction.
Parameters:
input_ThirdPartyReference(string): Third party referenceinput_QueryReference(string): Transaction ID or Conversation IDinput_ServiceProviderCode(string): Service provider code
Returns: Promise - API response with transaction status
mpesa.reversal(params)
Reverses a completed transaction.
Parameters:
input_TransactionID(string): Transaction ID to reverseinput_SecurityCredential(string): Security credentialinput_InitiatorIdentifier(string): Initiator identifierinput_ThirdPartyReference(string): Unique third party referenceinput_ServiceProviderCode(string): Service provider codeinput_ReversalAmount(string, optional): Amount to reverse (partial reversal)
Returns: Promise - API response with reversal details
mpesa.queryCustomerMaskedName(params)
Queries the masked name of a customer.
Parameters:
input_CustomerMSISDN(string): Customer mobile numberinput_ThirdPartyReference(string): Unique third party referenceinput_ServiceProviderCode(string): Service provider code
Returns: Promise - API response with customer name
Static Methods
Mpesa.generateThirdPartyReference()
Generates a unique third party reference.
Returns: string - 6-character uppercase alphanumeric string
Mpesa.generateTransactionReference()
Generates a unique transaction reference.
Returns: string - 8-character uppercase alphanumeric string
Mpesa.formatMSISDN(msisdn)
Formats an MSISDN to the standard format.
Parameters:
msisdn(string): Mobile number to format
Returns: string - Formatted MSISDN (258XXXXXXXXX)
Mpesa.formatAmount(amount)
Formats an amount to the standard format.
Parameters:
amount(string|number): Amount to format
Returns: string - Formatted amount with 2 decimal places
Mpesa.validateMSISDN(msisdn)
Validates an MSISDN format.
Parameters:
msisdn(string): Mobile number to validate
Returns: boolean - True if valid, false otherwise
Mpesa.validateAmount(amount)
Validates an amount format.
Parameters:
amount(string|number): Amount to validate
Returns: boolean - True if valid, false otherwise
Response Object Structure
All API methods return a response object with the following structure:
{
// Original API response fields
output_ConversationID: "AG_20180206_00005e7dccc6da08efa8",
output_TransactionID: "4XDF12345",
output_ResponseDesc: "Request processed successfully",
output_ResponseCode: "INS-0",
output_ThirdPartyReference: "11114",
// Additional fields added by SDK
isSuccess: true,
responseDescription: "Request processed successfully"
}Complete Response Codes Reference
| HTTP Status | Code | Description | |-------------|------|-------------| | 200/201 | INS-0 | Request processed successfully | | 500 | INS-1 | Internal Error | | 401 | INS-2 | Invalid API Key | | 401 | INS-4 | User is not active | | 401 | INS-5 | Transaction cancelled by customer | | 401 | INS-6 | Transaction Failed | | 408 | INS-9 | Request timeout | | 409 | INS-10 | Duplicate Transaction | | 400 | INS-13 | Invalid Shortcode Used | | 400 | INS-14 | Invalid Reference Used | | 400 | INS-15 | Invalid Amount Used | | 503 | INS-16 | Unable to handle the request due to a temporary overloading | | 400 | INS-17 | Invalid Transaction Reference. Length Should Be Between 1 and 20. | | 400 | INS-18 | Invalid TransactionID Used | | 400 | INS-19 | Invalid ThirdPartyReference Used | | 400 | INS-20 | Not All Parameters Provided. Please try again. | | 400 | INS-21 | Parameter validations failed. Please try again. | | 400 | INS-22 | Invalid Operation Type | | 400 | INS-23 | Unknown Status. Contact M-Pesa Support | | 400 | INS-24 | Invalid InitiatorIdentifier Used | | 400 | INS-25 | Invalid SecurityCredential Used | | 400 | INS-26 | Not authorized | | 400 | INS-993 | Direct Debit Missing | | 400 | INS-994 | Direct Debit Already Exists | | 400 | INS-995 | Customer's Profile Has Problems | | 400 | INS-996 | Customer Account Status Not Active | | 400 | INS-997 | Linking Transaction Not Found | | 400 | INS-998 | Invalid Market | | 400 | INS-2001 | Initiator authentication error. | | 400 | INS-2002 | Receiver invalid. | | 422 | INS-2006 | Insufficient balance | | 400 | INS-2051 | MSISDN invalid. | | 400 | INS-2057 | Language code invalid. |
Transaction Status Values
| Status | Description | |--------|-------------| | Cancelled | Transaction was cancelled | | Completed | Transaction completed successfully | | Expired | Transaction expired | | N/A | Status not available |
Best Practices
Security
Never expose credentials in client-side code
// ❌ Don't do this const mpesa = new Mpesa({ apiKey: 'your-api-key-here', // Exposed in client code publicKey: 'your-public-key-here' }); // ✅ Do this instead const mpesa = new Mpesa({ apiKey: process.env.MPESA_API_KEY, publicKey: process.env.MPESA_PUBLIC_KEY });Use environment variables for configuration
# .env file MPESA_API_KEY=your-api-key MPESA_PUBLIC_KEY=your-public-key MPESA_BASE_URL=https://api.sandbox.vm.co.mzValidate input data before making API calls
if (!Mpesa.validateMSISDN(customerMSISDN)) { throw new Error('Invalid MSISDN format'); } if (!Mpesa.validateAmount(amount)) { throw new Error('Invalid amount'); }
Error Handling
Always wrap API calls in try-catch blocks
try { const result = await mpesa.c2b(params); // Handle success } catch (error) { // Handle error console.error('Transaction failed:', error.message); }Implement retry logic for network errors
async function retryTransaction(params, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await mpesa.c2b(params); } catch (error) { if (error instanceof MpesaNetworkError && i < maxRetries - 1) { await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); continue; } throw error; } } }
Performance
Reuse client instances
// ✅ Create once, use multiple times const mpesa = new Mpesa(config); // Use the same instance for multiple transactions await mpesa.c2b(params1); await mpesa.b2c(params2);Implement rate limiting for batch operations
async function processBatch(items, delayMs = 1000) { for (const item of items) { await processItem(item); await new Promise(resolve => setTimeout(resolve, delayMs)); } }Use connection pooling for high-volume applications
const mpesa = new Mpesa({ ...config, timeout: 30000, // Adjust timeout based on your needs });
Contributing
We welcome contributions to the M-Pesa Node.js SDK! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development Setup
# Clone the repository
git clone https://github.com/your-username/mpesa-nodejs-sdk.git
cd mpesa-nodejs-sdk
# Install dependencies
npm install
# Run tests
npm test
# Run examples
node examples.jsTesting
Before submitting a pull request, ensure all tests pass:
npm testLicense
This project is licensed under the MIT License - see the LICENSE file for details.
Support
For support and questions:
- Create an issue on GitHub
- Check the M-Pesa Developer Portal for API documentation
- Review the examples in this README and the
examples.jsfile
Changelog
Version 1.0.0
- Initial release
- Support for all major M-Pesa API operations
- Comprehensive error handling
- Utility functions for common operations
- Full TypeScript support (coming soon)
Disclaimer: This SDK is not officially endorsed by Vodacom or M-Pesa. Use at your own risk and ensure compliance with M-Pesa's terms of service.
