This project demonstrates integration with Safaricom's Daraja API for M-Pesa payment services, specifically focused on STK Push and QR code generation using the Daraja sandbox environment.
- M-Pesa STK Push initiation
- QR Code generation for payments
- Firebase Cloud Messaging for push notifications
- Token storage and management
- Transaction logging and retrieval
- Callback URL handling
- Docker containerization
- Load tested and optimized for high traffic
- Node.js (v20 recommended)
- MongoDB
- Safaricom Daraja API credentials (consumer key, consumer secret, passkey)
- Firebase Admin SDK setup for push notifications
Create a .env
file in the root directory with the following variables:
PORT=5050
MPESA_PAYBILL=your_paybill_number
MPESA_CONSUMER_KEY=your_consumer_key
MPESA_CONSUMER_SECRET=your_consumer_secret
MPESA_PASSKEY=your_passkey
DATABASE_URI=your_mongodb_connection_string
CALLBACK_URL=your_callback_url
- Clone the repository
- Install dependencies:
npm install
- Place your Firebase Admin SDK JSON file in the root directory
- Start the application:
npm start
A Dockerfile is included for containerization:
docker build -t mpesa-node-app .
docker run -p 5050:5050 --env-file .env mpesa-node-app
POST /api/stk
Body: {
"amount": "1",
"phone": "254XXXXXXXXX"
}
POST /api/generateqr
Body: {
"amount": 100,
"AccountReference": "REF123"
}
POST /save-token
Body: {
"token": "firebase_token",
"userId": "user_id"
}
POST /send-notification
Body: {
"title": "Notification Title",
"body": "Notification Body",
"userId": "user_id"
}
POST /api/myCallBack
- Callback URL for M-PesaGET /api/allTransactions
- Fetch all transactionsGET /api/oneTransaction/:id
- Fetch specific transactionPOST /api/stkpushquery
- Query STK push statusPOST /api/register
- Register URLs with M-PesaPOST /api/c2b/v1/confirm
- C2B confirmation URLPOST /api/c2b/v1/validate
- C2B validation URL
The project includes K6 scripts for load testing different scenarios:
- Basic STK push test
- Combined STK push and query test with various load stages
To run the tests:
k6 run tests/load-test.js
The application has been spike and stress tested with excellent results under normal conditions. However, under extremely high load, the Daraja API may return 429 (Too Many Requests) errors. Key observations:
- The application performs well under moderately high load
- At peak stress levels, some requests may fail with 429 errors
- No performance degradation was observed in the application itself
- Database connections remained stable during high-load periods
To handle rate limiting (429 errors):
- Implement exponential backoff and retry logic
- Add request queuing for high-traffic periods
- Consider implementing a circuit breaker pattern
- Monitor API usage to stay within Safaricom's limits
- Add logging for failed requests to track patterns
The code includes a Firebase Cloud Messaging integration for sending push notifications to users. Tokens are stored in MongoDB and associated with user IDs.
The API includes proper error handling for:
- Failed token generation
- Invalid tokens (auto-deletion from database)
- Failed notifications
- Invalid M-Pesa responses
- Rate limiting (429) errors
- Store sensitive credentials in environment variables
- Use HTTPS in production
- Validate all input data
- Handle errors gracefully without exposing sensitive information
- Implement proper rate limiting to prevent abuse
This project is intended for learning purposes. Please check Safaricom's terms of service before using in production.