daraja
Version:
A NodeJS library to simplify integration with Safaricom's Daraja M-Pesa API
573 lines (553 loc) • 16.4 kB
text/typescript
import * as moment from 'moment';
import { DarajaError } from './errors';
import * as logic from './logic';
import { Environment } from './types';
/**
*
* This class implements the M-Pesa Daraja API methods
*/
export class Mpesa {
private accessToken: string;
private expiryDate: moment.Moment;
/**
*
* Creates an instance of Mpesa
* @param {number} shortcode - organization shortcode
* @param {string} consumerKey - app's consumer key
* @param {string} consumerSecret - app's consumer secret
* @param {Environment} [environment='sandbox'] - application environment
* @memberof Mpesa
* @constructor
*/
constructor(
private shortcode: number,
private consumerKey: string,
private consumerSecret: string,
private environment: Environment = 'sandbox'
) {
this.accessToken = '';
this.expiryDate = moment();
}
/**
*
* Invoke the Lipa na M-Pesa Online Payment API. Use this method to initiate
* an online payment on behalf of a customer
* @param {number} amount - money that the customer pays to the shortcode
* @param {number} sender - phone number of the customer sending the money
* @param {number} recipient - organization shortcode to receive the funds
* @param {string} passkey - Lipa na M-Pesa Online Passkey
* @param {('CustomerPayBillOnline' | 'CustomerBuyGoodsOnline')} transactionType -
* transaction type that is used to identify the transaction when sending the
* request to M-Pesa
* @param {string} accountReference - alphanumeric parameter that is defined
* by your system as an Identifier of the transaction for
* CustomerPayBillOnline transaction type
* @param {string} transactionDescription - any additional
* information/comment that can be sent along with the request from your
* system
* @param {string} callbackUrl - valid secure URL that is used to receive
* notifications from M-Pesa API and is the endpoint to which the results
* will be sent by M-Pesa API
* @memberof Mpesa
* @throws {DarajaError}
* @async
* @example
* mpesa.mpesaExpressRequest(
* 100,
* 254712345678,
* 123456,
* 'bfb279f9aa9bdbcf15...',
* 'CustomerPayBillOnline',
* 'INV001',
* 'Regular payment',
* 'http://callbackurl.com'
* ).then(response => {
* // SUCCESS
* // do something with the response
* }).catch(error => {
* // FAILED
* // handle the error
* })
*/
public async mpesaExpressRequest(
amount: number,
sender: number,
recipient: number,
passkey: string,
transactionType: 'CustomerPayBillOnline' | 'CustomerBuyGoodsOnline',
accountReference: string,
transactionDescription: string,
callbackUrl: string
) {
try {
const { accessToken, expiryDate } = await logic.generateToken(
this.environment,
this.consumerKey,
this.consumerSecret,
this.accessToken,
this.expiryDate
);
this.accessToken = accessToken;
this.expiryDate = expiryDate;
return await logic.mpesaExpressRequest(
this.environment,
this.accessToken,
this.shortcode,
passkey,
transactionType,
amount,
sender,
recipient,
callbackUrl,
accountReference,
transactionDescription
);
} catch (error) {
throw new DarajaError(error.message);
}
}
/**
*
* Invoke the Lipa Na M-Pesa Query Request API. Use this method to check the
* status of a Lipa Na M-Pesa Online Payment
* @param {string} passkey - Lipa na M-Pesa Online Passkey
* @param {string} checkoutRequestId - global unique identifier of the
* processed checkout transaction request
* @see [Mpesa.mpesaExpressRequest()]{@link Mpesa#mpesaExpressRequest}
* @memberof Mpesa
* @throws {DarajaError}
* @async
* @example
* mpesa.mpesaExpressQuery(
* 'bfb279f9aa9bdbcf15...',
* 'ws_CO_DMZ_123212312_2342347678234'
* ).then(response => {
* // SUCCESS
* // do something with the response
* }).catch(error => {
* // FAILED
* // handle the error
* })
*/
public async mpesaExpressQuery(passkey: string, checkoutRequestId: string) {
try {
const { accessToken, expiryDate } = await logic.generateToken(
this.environment,
this.consumerKey,
this.consumerSecret,
this.accessToken,
this.expiryDate
);
this.accessToken = accessToken;
this.expiryDate = expiryDate;
return await logic.mpesaExpressQuery(
this.environment,
this.accessToken,
this.shortcode,
passkey,
checkoutRequestId
);
} catch (error) {
throw new DarajaError(error.message);
}
}
/**
*
* Invoke the C2B Register URL API. Use this method to register validation
* and confirmation URLs on M-Pesa
* @param {string} validationUrl - URL that receives the validation request
* from API upon payment submission
* @param {string} confirmationUrl - URL that receives the confirmation
* request from API upon payment completion
* @param {('Completed' | 'Canceled')} responseType - specifies what is to
* happen if for any reason the validation URL is nor reachable
* @memberof Mpesa
* @async
* @example
* mpesa.c2bRegisterUrl(
* 'http://validationurl.com',
* 'http://confirmationurl.com'
* 'Completed'
* ).then(response => {
* // SUCCESS
* // do something with the response
* }).catch(error => {
* // FAILED
* // handle the error
* })
*/
public async c2bRegisterUrl(
validationUrl: string,
confirmationUrl: string,
responseType: 'Completed' | 'Canceled'
) {
try {
const { accessToken, expiryDate } = await logic.generateToken(
this.environment,
this.consumerKey,
this.consumerSecret,
this.accessToken,
this.expiryDate
);
this.accessToken = accessToken;
this.expiryDate = expiryDate;
return await logic.c2bRegisterUrl(
this.environment,
this.accessToken,
this.shortcode,
validationUrl,
confirmationUrl,
responseType
);
} catch (error) {
throw new DarajaError(error.message);
}
}
/**
*
* Invoke the C2B Simulate Transaction API. Use this method to simulate a
* payment made from the client phone's STK/SIM Toolkit menu
* @param {number} amount - amount being transacted
* @param {number} sender - phone number initiating the C2B transaction
* @param {string} billReference - used on CustomerPayBillOnline option only
* and is where a customer is expected to enter a unique bill identifier,
* e.g an Account Number
* @memberof Mpesa
* @throws {DarajaError}
* @async
* @example
* mpesa.c2bSimulateTransaction(
* 100,
* 254712345678,
* '13123421'
* ).then(response => {
* // SUCCESS
* // do something with the response
* }).catch(error => {
* // FAILED
* // handle the error
* })
*/
public async c2bSimulateTransaction(
amount: number,
sender: number,
billReference: string
) {
try {
const { accessToken, expiryDate } = await logic.generateToken(
this.environment,
this.consumerKey,
this.consumerSecret,
this.accessToken,
this.expiryDate
);
this.accessToken = accessToken;
this.expiryDate = expiryDate;
return await logic.c2bSimulateTransaction(
this.environment,
this.accessToken,
this.shortcode,
sender,
amount,
billReference
);
} catch (error) {
throw new DarajaError(error.message);
}
}
/**
*
* Invoke the B2C Payment Request API. Use this method to transact between an
* M-Pesa short code to a phone number registered on M-Pesa
* @param {number} amount - amount of money being sent to the customer
* @param {number} recipient - customer mobile number to receive the amount
* @param {string} initiatorName - username of the M-Pesa B2C account API
* operator
* @param {string} initiatorPassword - password of the M-Pesa B2C account API
* operator
* @param {('SalaryPayment' | 'BusinessPayment' | 'PromotionPayment')} commandId -
* unique command that specifies B2C transaction type
* @param {string} remarks - any additional information to be associated with
* the transaction
* @param {string} occassion - any additional information to be associated
* with the transaction
* @param {string} resultUrl - URL that will be used by M-Pesa to send
* notification upon processing of the payment
* request
* @param {string} timeoutUrl - URL that will be used by API Proxy to send
* notification incase the payment request is timed out while awaiting
* processing in the queue
* @memberof Mpesa
* @throws {DarajaError}
* @async
* @example
* mpesa.b2cPaymentRequest(
* 100,
* 254712345678,
* 'initiator',
* 'p455w0rd',
* 'BusinessPayment',
* 'Remarks',
* 'Occassion',
* 'http://resulturl.com',
* 'http://timeouturl.com'
* ).then(response => {
* // SUCCESS
* // do something with the response
* }).catch(error => {
* // FAILED
* // handle the error
* })
*/
public async b2cPaymentRequest(
amount: number,
recipient: number,
initiatorName: string,
initiatorPassword: string,
commandId: 'SalaryPayment' | 'BusinessPayment' | 'PromotionPayment',
remarks: string,
occassion: string,
resultUrl: string,
timeoutUrl: string
) {
try {
const { accessToken, expiryDate } = await logic.generateToken(
this.environment,
this.consumerKey,
this.consumerSecret,
this.accessToken,
this.expiryDate
);
this.accessToken = accessToken;
this.expiryDate = expiryDate;
return await logic.b2cPaymentRequest(
this.environment,
this.accessToken,
this.shortcode,
recipient,
amount,
commandId,
initiatorName,
initiatorPassword,
remarks,
occassion,
timeoutUrl,
resultUrl
);
} catch (error) {
throw new DarajaError(error.message);
}
}
/**
*
* Invoke the Account Balance Request API. Use this method to enquire the
* balance on an M-Pesa shortcode
* @param {(1 | 2 | 4)} identifierType - Type of organization receiving the
* transaction. 1 - MSISDN, 2 - Till Number, 4 - Organization shortcode
* @param {string} initiatorName - name of Initiator to initiating the
* request
* @param {string} initiatorPassword - password of Initiator to initiating
* the request
* @param {string} remarks - comments that are sent along with the
* transaction
* @param {string} resultUrl - path that stores information of transaction
* @param {string} timeoutUrl - path that stores information of time out
* transaction
* @memberof Mpesa
* @throws {DarajaError}
* @async
* @example
* mpesa.accountBalanceRequest(
* 4,
* 'initiator',
* 'p455w0rd',
* 'Remarks',
* 'http://resulturl.com',
* 'http://timeouturl.com'
* ).then(response => {
* // SUCCESS
* // do something with the response
* }).catch(error => {
* // FAILED
* // handle the error
* })
*/
public async accountBalanceRequest(
identifierType: 1 | 2 | 4,
initiatorName: string,
initiatorPassword: string,
remarks: string,
resultUrl: string,
timeoutUrl: string
) {
try {
const { accessToken, expiryDate } = await logic.generateToken(
this.environment,
this.consumerKey,
this.consumerSecret,
this.accessToken,
this.expiryDate
);
this.accessToken = accessToken;
this.expiryDate = expiryDate;
return await logic.accountBalanceRequest(
this.environment,
this.accessToken,
this.shortcode,
identifierType,
initiatorName,
initiatorPassword,
remarks,
timeoutUrl,
resultUrl
);
} catch (error) {
throw new DarajaError(error.message);
}
}
/**
*
* Invoke the Transaction Status Request API. Use this method to check the
* transaction status
* @param {string} transactionId - unique identifier to identify a
* transaction on M-Pesa
* @param {(1 | 2 | 4)} identifierType - type of organization receiving the
* transaction
* @param {string} initiatorName - name of Initiator initiating the request
* @param {string} initiatorPassword - password of Initiator initiating the
* request
* @param {string} remarks - comments that are sent along with the
* transaction
* @param {string} occassion - optional parameter
* @param {string} resultUrl - path that stores information of transaction
* @param {string} timeoutUrl - path that stores information of time out
* transaction
* @memberof Mpesa
* @async
* @example
* mpesa.transactionStatusRequest(
* 'MX000000000',
* 4,
* 'initiator',
* 'p455w0rd',
* 'Remarks',
* 'Occassion',
* 'http://resulturl.com',
* 'http://timeouturl.com'
* ).then(response => {
* // SUCCESS
* // do something with the response
* }).catch(error => {
* // FAILED
* // handle the error
* })
*/
public async transactionStatusRequest(
transactionId: string,
identifierType: 1 | 2 | 4,
initiatorName: string,
initiatorPassword: string,
remarks: string,
occassion: string,
resultUrl: string,
timeoutUrl: string
) {
try {
const { accessToken, expiryDate } = await logic.generateToken(
this.environment,
this.consumerKey,
this.consumerSecret,
this.accessToken,
this.expiryDate
);
this.accessToken = accessToken;
this.expiryDate = expiryDate;
return await logic.transactionStatusRequest(
this.environment,
this.accessToken,
this.shortcode,
identifierType,
initiatorName,
initiatorPassword,
transactionId,
remarks,
occassion,
timeoutUrl,
resultUrl
);
} catch (error) {
throw new DarajaError(error.message);
}
}
/**
*
* Invoke the Reversal Request API. Use this method to reverse an M-Pesa
* transaction
* @param {string} transactionId - unique identifier to identify a
* transaction on M-Pesa
* @param {string} initiatorName - name of initiator initiating the request
* @param {string} initiatorPassword - password of the initiator initiating
* the request
* @param {string} remarks - comments that are sent along with the
* transaction
* @param {string} occassion - optional parameter
* @param {string} resultUrl - path that stores information of the
* transaction
* @param {string} timeoutUrl - path that stores information of time out
* transaction
* @memberof Mpesa
* @throws {DarajaError}
* @async
* @example
* mpesa.reversalRequest(
* 'MX000000000',
* 'initiator',
* 'p455w0rd',
* 'Remarks',
* 'Occassion',
* 'http://resulturl.com',
* 'http://timeouturl.com'
* ).then(response => {
* // SUCCESS
* // do something with the response
* }).catch(error => {
* // FAILED
* // handle the error
* })
*/
public async reversalRequest(
transactionId: string,
initiatorName: string,
initiatorPassword: string,
remarks: string,
occassion: string,
resultUrl: string,
timeoutUrl: string
) {
try {
const { accessToken, expiryDate } = await logic.generateToken(
this.environment,
this.consumerKey,
this.consumerSecret,
this.accessToken,
this.expiryDate
);
this.accessToken = accessToken;
this.expiryDate = expiryDate;
return await logic.reversalRequest(
this.environment,
this.accessToken,
this.shortcode,
initiatorName,
initiatorPassword,
transactionId,
remarks,
occassion,
timeoutUrl,
resultUrl
);
} catch (error) {
throw new DarajaError(error.message);
}
}
}