A .NET Standard M-PESA API Helper Library for .NET Developers.
Platform | .NET Core | .NET Framework | Mono | Xamarin.iOS | Xamarin.Android | Xamarin.Mac | UWP |
---|---|---|---|---|---|---|---|
Min. Version | 2.0 | 4.6.1 | 5.4 | 10.14 | 8.0 | 3.8 | 10.0.16299 |
PM> Install-Package MpesaLib
>dotnet add package MpesaLib
Before you proceed kindly aquaint yourself with Mpesa Apis by going through the Docs in Safaricom's developer portal or Daraja if you like.
-
Obtain consumerKey, consumerSecret and Passkey (for Lipa Na Mpesa Online APIs) from daraja portal.
-
Ensure your project is running on the minimun supported versions of .Net
-
MpesaLib is dependency injection (DI) friendly and can be readily injected into your classes. You can read more on DI in Asp.Net core here. If you can't use DI you can always manually create a new instance of MpesaClient and pass in an httpClient instance in it's constructor. eg.
// When DI is not possible for your case don't give up just yet...
//create httpclient instance
var httpClient = new HttpClient();
httpClient.BaseAddress = RequestEndPoint.SandboxBaseAddress; //Use RequestEndPoint.LiveBaseAddress in production
//create Mpesa API client instance
var mpesaClient = new MpesaClient(httpClient); //make sure to pass httpclient intance as an argument
I would recommend the DI way of doing things though...
-
Install MpesaLib .Net Project via Nuget Package Manager Console or Nuget Package Manager GUI.
-
In Startup.cs add the namespace...
using MpesaLib;
- Inside ConfigureServices method add the following
services.AddHttpClient<IMpesaClient, MpesaClient>(options => options.BaseAddress = RequestEndPoint.SandboxBaseAddress);
Use RequestEndPoint.LiveBaseAddress
as base address/base url in production. You can do an environment check using the IHostingEnvironment property in asp.net core.
- Once the MpesaClient is registered, you can pass it and use it in your classes to make API calls to Mpesa Server as follows;
using MpesaLib; //Add MpesaLib namespace
public class Payments
{
private readonly IMpesaClient _mpesaClient;
public Payments(IMpesaCleint mpesaClient)
{
_mpesaClient = mpesaClient;
}
....
//code omitted for brevity
}
Mpesa APIs require authorization to use the APIs. The accesstoken (auth token) has to be used with each api call. The accesstoken expire after an hour so it is recommended that you use a caching strategy to refresh the token after every hour or less depending on how much traffic your site has.
- To get an accesstoken, invoke the
_mpesaClient.GetAuthTokenAsync(*args);
method. You have to await the Async call. use Non-Async method call provided if you cannot leverage async.
//Async
var accesstoken = await _mpesaClient.GetAuthTokenAsync(ConsumerKey, ConsumerSecret, RequestEndPoint.AuthToken);
Note that you have to pass in a consusmerKey, ConsumerSecret provided by Mpesa.
var RegisterC2BUrlObject = new CustomerToBusinessRegisterUrlDto(
"ShortCode",
"ResponseType",
"ConfirmationURL",
"ValidationURL"
);
var c2bRegisterUrlrequest = await _mpesaClient.RegisterC2BUrlAsync(RegisterC2BUrlObject, accesstoken, RequestEndPoint.RegisterC2BUrl);
//C2B Object
Var CustomerToBusinessSimulateObject = new CustomerToBusinessSimulateDto
(
"ShortCode",
"CommandID",
"Amount",
"Msisdn",
"BillRefNumber"
);
var c2brequest = await _mpesaClient.MakeC2BPaymentAsync(CustomerToBusinessSimulateObject, accesstoken, RequestEndPoint.CustomerToBusinessSimulate);
// initialize object with data
var MpesaExpressObject = new LipaNaMpesaOnlineDto
(
"BusinessShortCode",// businessShortCode
Timestamp, //Timestamp
"TransactionType", //transactionType
"Amount", // amount
"PartyA" ,// partyA
"PartyB" ,// partyB
"PhoneNumber", // phoneNumber
"CallBackURL", // callBackUrl
"AccountReference" ,//accountReference
"TransactionDesc" ,//transactionDescription
"Passkey" //passkey
);
//Make payment request
var paymentrequest = await _mpesaClient.MakeLipaNaMpesaOnlinePaymentAsync(MpesaExpressObject, accesstoken, RequestEndPoint.LipaNaMpesaOnline));
var QueryLipaNaMpesaTransactionObject = new LipaNaMpesaQueryDto
(
"174379", //BusinessShortCode
"CheckoutRequestID", //CheckoutRequestID
"Password", //Password
"Timestamp" //Timestamp
);
var stkpushquery = await _mpesaClient.QueryLipaNaMpesaTransactionAsync(QueryLipaNaMpesaTransactionObject, accesstoken, equestEndPoint.QueryLipaNaMpesaOnlieTransaction);
//B2C Object
var BusinessToCustomerObject = new BusinessToCustomerDto
(
"test",//Remarks
"1", //Amount
"BusinessPayment", //CommandID
"safaricom.15", //InitiatorName
"test", //Occasion
"603047", //PartyA
"254708374149", //PartyB
"https://blablabla/timeoutendpoint", //QueueTimeOutURL
"https://blablabla/resultendpoint", //ResultURL
"security credential" //SecurityCredential
);
var b2crequest = await _mpesaClient.MakeB2CPaymentAsync(BusinessToCustomerObject, accesstoken, RequestEndPoint.BusinessToCustomer);
var BusinessToBusinessObject = new BusinessToBusinessDto
(
"test", //AccountReference
"safaricom.13", //Initiator
"1500", //Amount
"603047", //PartyA
"600000", //PartyB
"BusinessPayBill",// Please use the correct command -usage depends on what is enabled for your shortcode
"https://blablabla/callback", //QueueTimeOutURL
"4", // RecieverIdentifierType - Read on receiver identifier types from daraja
"security credential", //SecurityCredential - Use MpesaLib.Helpers.Credentials class to generate security credential
"4", //SenderIdentifierType
"https://blablabla/callback", //ResultURL
"payment" //Remarks
);
var b2brequest = await _mpesaClient.MakeB2BPaymentAsync(BusinessToBusinessObject, accesstoken, RequestEndPoint.BusinessToBusiness);
var TransactionStatusObject = new MpesaTransactionStatusDto
(
"IdentifierType",//IdentifierType
"Initiator", //Initiator
"Occasion", //Occasion
"PartyA", //PartyA
"QueueTimeOutURL", //QueueTimeOutURL
"ResultURL", //ResultURL
"TransactionID", //TransactionID
"Remarks", //Remarks
"SecurityCredential" //SecurityCredential
);
var transactionrequest = await _mpesaClient.QueryMpesaTransactionStatusAsync(TransactionStatusObject, accesstoken, RequestEndPoint.QueryMpesaTransactionStatus);
var AccountBalanceObject = new AccountBalanceDto
(
"IdentifierType",// 4 for Paybill 2 for Till
"Initiator", //Initiator password
"PartyA",
"QueueTimeOutURL",
"ResultURL",
"remarks",
"security credential",
);
var accountbalancerequest = await _mpesaClient.QueryAccountBalanceAsync(AccountBalanceObject, accesstoken, RequestEndPoint.QueryAccountBalance); //async method
var TransactionReversalObject = new ReversalDto
(
"Initiator", //Initiator
"Occasion", //Occasion
"ReceiverParty", //ReceiverParty
"RecieverIdentifierType", //RecieverIdentifierType
"QueueTimeOutURL", //QueueTimeOutURL
"ResultURL", //ResultURL
"TransactionID", //TransactionID
"SecurityCredential", //SecurityCredential
"Remarks", //Remarks
);
var reversalrequest = await _mpesaClient.ReverseMpesaTransactionAsync(TransactionReversalObject, accesstoken, RequestEndPoint.ReverseMpesaTransaction);
The Security Credential helper class is in MpesaLib.Helpers namespace.
This class helps you generate the required credential to be used to authorize the above mentioned APIs.
using MpesaLib.Helpers; // add this to your class or namespace
//get path to Mpesa public certificate. There are different certs for development and for production, ensure to use the correct one)
string certificate = @"C:\Dev\MpesaLibSamples\WebApplication1\Certificate\prod.cer";
//generate security credential as follows...
var SecutityCredential = Credentials.EncryptPassword(certificate, "Initiator Password");
MpesaClient Throws MpesaApiException
whenever A 200 status code is not returned. It is your role as the developer to catch
the exception and continue processing in your aplication. Snippet below shows how you can catch the MpesaApiException.
using MpesaLib.Helpers.Exceptions; // add this to you class or namespace
try
{
return await _mpesaClient.MakeLipaNaMpesaOnlinePaymentAsync(MpesaPayment, accesstoken, RequestEndPoint.LipaNaMpesaOnline);
}
catch (MpesaApiException e)
{
_logger.LogError($"An Error Occured, Status Code {e.StatusCode}: {e.Content}");
//check the status code and return what is appropriate for your case. e.Content has the error message from Mpesa inform of a json string (not object) incase you do things like tying to transact 0 shillings or more than the 70k limit per transaction, or your shorcode is wrong or your accesstoken is not valid etc.
return BadRequest(); //I am just being lazy here.
}