STK Push
The StkPush
class provides functionality to initiate Lipa Na M-Pesa Online (STK Push) payments, allowing you to prompt customers to make payments directly from their M-Pesa accounts via their mobile phones.
Class: StkPush
class StkPush {
constructor(
auth: Auth,
sandbox?: boolean
);
public async sendStkPush(
amount: number,
transactionDesc: string,
accountReference: string,
businessShortCode?: string,
passkey?: string,
phoneNumber?: string,
callbackUrl?: string
): Promise<StkPushResponse>;
}
Constructor
Creates a new instance of the StkPush class for initiating M-Pesa STK Push payment requests.
Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
auth | Auth | Yes | - | An instance of the Auth class for token generation |
sandbox | boolean | No | MPESA_SANDBOX env var | Whether to use sandbox environment |
Examples
// Using environment variables with default sandbox mode
const auth = new Auth();
const stkPush = new StkPush(auth);
// Explicit initialization for production
const auth = new Auth(
'your-consumer-key',
'your-consumer-secret',
false
);
const stkPush = new StkPush(auth, false);
// Mixed usage
const auth = new Auth();
const stkPush = new StkPush(
auth,
process.env.NODE_ENV !== 'production'
);
Methods
sendStkPush()
Initiates an STK Push transaction to request payment from a customer.
public async sendStkPush(
amount: number,
transactionDesc: string,
accountReference: string,
businessShortCode?: string,
passkey?: string,
phoneNumber?: string,
callbackUrl?: string
): Promise<StkPushResponse>;
Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
amount | number | Yes | - | The amount to be paid (must be greater than 0) |
transactionDesc | string | Yes | - | Description of the transaction (max 13 chars) |
accountReference | string | Yes | - | Reference for the transaction (max 12 chars) |
businessShortCode | string | No | MPESA_BUSINESS_SHORTCODE env var | The business short code |
passkey | string | No | MPESA_PASSKEY env var | The passkey for generating the password |
phoneNumber | string | No | MPESA_PHONE_NUMBER env var | The customerās phone number (must start with 251 and be 12 digits) |
callbackUrl | string | No | MPESA_CALLBACK_URL env var | The HTTPS URL where payment results will be sent |
Returns
Property | Type | Description |
---|---|---|
MerchantRequestID | string | Unique identifier for the merchant request |
CheckoutRequestID | string | Unique identifier for the checkout/payment request |
ResponseCode | string | Response code from M-Pesa API (0 indicates success) |
ResponseDescription | string | Description of the response status |
CustomerMessage | string | Message that can be displayed to the customer |
Examples
// Basic STK Push request
try {
const result = await stkPush.sendStkPush(
100, // amount
'Payment for services', // transaction description
'INV123456789', // account reference
);
console.log('Payment initiated successfully!');
console.log('Checkout Request ID:', result.CheckoutRequestID);
} catch (error) {
console.error('Payment request failed:', error.message);
}
// With all parameters specified
try {
const result = await stkPush.sendStkPush(
500.50,
'Coffee payment',
'ORD98765',
'174379', // business short code
'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919', // passkey
'251712345678', // phone number
'https://example.com/mpesa/callback' // callback URL
);
// Store the checkout request ID for later status check
saveCheckoutRequestId(result.CheckoutRequestID);
} catch (error) {
handlePaymentError(error);
}
Error Handling
The StkPush
class can throw several types of errors:
ValidationError
Thrown when input parameters fail validation checks.
try {
await stkPush.sendStkPush(amount, desc, ref, businessCode, passkey, phone, callback);
} catch (error) {
if (error instanceof ValidationError) {
console.error(`Validation failed for ${error.field}: ${error.message}`);
// Handle specific validation errors
if (error.field === 'phoneNumber') {
alert('Please provide a valid phone number in the format 251XXXXXXXXX');
} else if (error.field === 'amount') {
alert('Amount must be greater than zero');
}
}
}
StkPushError
Thrown when the M-Pesa API returns an error response for the STK Push request.
try {
await stkPush.sendStkPush(amount, desc, ref);
} catch (error) {
if (error instanceof StkPushError) {
console.error(`STK Push error: ${error.message}`);
console.error(`Error code: ${error.errorCode}`);
// Handle specific STK Push errors
if (error.errorCode === '500.001.1001') {
console.error('Invalid credentials');
}
}
}
NetworkError
Thrown when network connectivity issues occur.
try {
await stkPush.sendStkPush(amount, desc, ref);
} catch (error) {
if (error instanceof NetworkError) {
console.error('Network issue - implementing retry logic');
// Implement retry with exponential backoff
setTimeout(() => retryPayment(amount, desc, ref), 5000);
}
}
MpesaError
Base error type for all other M-Pesa related errors.
try {
await stkPush.sendStkPush(amount, desc, ref);
} catch (error) {
if (error instanceof MpesaError) {
console.error('M-Pesa error occurred:', error.message);
} else {
console.error('Unexpected error:', error);
}
}
Best Practices
1. Proper Error Handling
Implement robust error handling to provide clear feedback:
const initiatePayment = async (amount, description, reference, phone) => {
try {
const result = await stkPush.sendStkPush(
amount,
description,
reference,
undefined, // Use environment variable for business code
undefined, // Use environment variable for passkey
phone
);
return {
success: true,
checkoutRequestId: result.CheckoutRequestID,
message: 'Payment request sent successfully'
};
} catch (error) {
if (error instanceof ValidationError) {
return {
success: false,
field: error.field,
message: error.message
};
} else if (error instanceof NetworkError) {
return {
success: false,
retry: true,
message: 'Network issue occurred. Please try again.'
};
} else if (error instanceof StkPushError) {
return {
success: false,
errorCode: error.errorCode,
message: 'Payment service error: ' + error.message
};
} else {
return {
success: false,
message: 'An unexpected error occurred'
};
}
}
};
2. Environment-Based Configuration
Use different configurations for development and production:
const auth = new Auth();
const stkPush = new StkPush(
auth,
process.env.NODE_ENV !== 'production'
);
3. Secure Parameter Handling
Use environment variables for sensitive information:
// In your .env file
MPESA_BUSINESS_SHORTCODE=174379
MPESA_PASSKEY=bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919
MPESA_CALLBACK_URL=https://example.com/mpesa/callback
// In your code
const stkPush = new StkPush(auth);
const result = await stkPush.sendStkPush(
amount,
description,
reference
);
4. Rate Limiting
The StkPush class includes built-in rate limiting to prevent API abuse. Payment requests are automatically rate-limited based on M-Pesaās guidelines.
Integration Examples
Express.js Route Handler
Example of using StkPush in an Express.js route:
// payment.controller.ts
import { Request, Response } from 'express';
import { Auth, StkPush, ValidationError, StkPushError, NetworkError } from 'mpesajs';
const auth = new Auth();
const stkPush = new StkPush(auth);
export const initiatePayment = async (req: Request, res: Response) => {
const { amount, phoneNumber, description, reference } = req.body;
try {
const result = await stkPush.sendStkPush(
amount,
description,
reference,
undefined,
undefined,
phoneNumber
);
res.status(200).json({
success: true,
checkoutRequestId: result.CheckoutRequestID,
message: 'Payment request sent successfully'
});
} catch (error) {
if (error instanceof ValidationError) {
res.status(400).json({
success: false,
field: error.field,
message: error.message
});
} else if (error instanceof NetworkError) {
res.status(503).json({
success: false,
message: 'Service temporarily unavailable. Please try again.'
});
} else if (error instanceof StkPushError) {
res.status(400).json({
success: false,
errorCode: error.errorCode,
message: error.message
});
} else {
res.status(500).json({
success: false,
message: 'An unexpected error occurred'
});
}
}
};
React Hook
Example of a React hook for using STK Push:
// useMpesaPayment.ts
import { useState } from 'react';
import { Auth, StkPush } from 'mpesajs';
const auth = new Auth(process.env.REACT_APP_MPESA_CONSUMER_KEY, process.env.REACT_APP_MPESA_CONSUMER_SECRET);
const stkPush = new StkPush(auth);
export const useMpesaPayment = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [result, setResult] = useState(null);
const initiatePayment = async (amount, phoneNumber, description, reference) => {
setLoading(true);
setError(null);
try {
const response = await fetch('/api/mpesa/initiate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount,
phoneNumber,
description,
reference
}),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || 'Payment initiation failed');
}
setResult(data);
return data;
} catch (err) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
};
return {
initiatePayment,
loading,
error,
result
};
};