LibertePay.Core.Sdk
1.0.0-beta
See the version list below for details.
dotnet add package LibertePay.Core.Sdk --version 1.0.0-beta
NuGet\Install-Package LibertePay.Core.Sdk -Version 1.0.0-beta
<PackageReference Include="LibertePay.Core.Sdk" Version="1.0.0-beta" />
<PackageVersion Include="LibertePay.Core.Sdk" Version="1.0.0-beta" />
<PackageReference Include="LibertePay.Core.Sdk" />
paket add LibertePay.Core.Sdk --version 1.0.0-beta
#r "nuget: LibertePay.Core.Sdk, 1.0.0-beta"
#addin nuget:?package=LibertePay.Core.Sdk&version=1.0.0-beta&prerelease
#tool nuget:?package=LibertePay.Core.Sdk&version=1.0.0-beta&prerelease
LibertePay SDK
LibertePay SDK is a comprehensive payment integration solution that provides seamless access to LibertePay's payment processing services. The SDK simplifies the integration of payment features into your .NET applications with a clean, intuitive API.
Features
💳 Payment Processing
- Mobile Money Collections
- Bank Account Transfers
- Card Payments (coming soon)
💸 Disbursements
- Mobile Money Wallets
- Bank Accounts
- Bulk Payments (Mobile Money & Bank Account)
🔄 Transaction Management
- Status Tracking
- Reversals (coming soon)
- Reconciliation (coming soon)
👤 Account Services
- Name Enquiry (Banks & Mobile Money)
- Balance Checking
- KYC Verification (coming soon)
📈 Advanced Features
- Built-in Telemetry
- High Performance
- Thread-safe Token Management
- Dependency Injection Support
- Type-safe Institution Codes
- Automatic Callback Handling
Installation
Install the LibertePay SDK via NuGet:
dotnet add package LibertePay.Core.Sdk --version 1.0.0-alpha
Configuration
Basic Configuration
Add the LibertePay configuration to your appsettings.json
:
{
"LibertePay": {
"BaseUrl": "https://app-base-url/",
"Username": "your-username",
"Password": "your-password",
"HttpClientTimeoutSeconds": 30,
"CallbackUrl": "https://your-domain.com/webhook",
"TelemetryApiUrl": "https://your-telemetry-service.com/" // Optional
}
}
Service Registration
Register the LibertePay services in your Program.cs
or Startup.cs
:
using LibertePay.Core.DependencyInjection;
// ...
services.AddLibertePay(configuration);
Usage Guide
1. Name Enquiry Services
Bank Account Name Enquiry (Single & Bulk)
public class PaymentService
{
private readonly ILibertePayClient _client;
public PaymentService(ILibertePayClient client) => _client = client;
[HttpGet("VerifyBankAccount")]
public async Task<IActionResult> VerifyBankAccountAsync()
{
var request = new NameEnquiryRequest
{
AccountNumber = "1020820171412", // test account number
PaymentChannel = Channels.INTERBANK,
Institution = InstitutionCodes.TestGhanaLimited, //this is a test institution code
TransactionId = Guid.NewGuid().ToString("N")
};
var response = await _client.NameEnquiry.GetNameEnquiryAsync(request);
return Ok(response.Data?.AccountName ?? response.StatusDescription);
}
[HttpGet("VerifyBulkBankAccountAsync", Name = "VerifyBulkBankAccountAsync")]
public async Task<IActionResult> VerifyBulkBankAccountAsync()
{
var requestBulkNameCheck = new BulkNameEnquiryRequest
{
BatchTransactionId = Guid.NewGuid().ToString("N"),
BulkNameEnquiryData =
[
new BulkNameEnquiryItem
{
AccountNumber = "1020820171412",
Institution = InstitutionCodes.TestGhanaLimited
},
new BulkNameEnquiryItem
{
AccountNumber = "1020820171412",
Institution = InstitutionCodes.TestGhanaLimited
}
]
};
var response = await _client.NameEnquiry.GetBulkNameEnquiryAsync(requestBulkNameCheck);
if (response.IsSuccess)
{
return Ok(response!.Data!.BatchTransactionId);
}
return Ok($"Bulk Name Enquiry : {response.StatusDescription}");
}
}
Mobile Money Name Enquiry (Single & Bulk)
[HttpGet("VerifyMobileMoneyAsync", Name = "VerifyMobileMoneyAsync")]
public async Task<IActionResult> VerifyMobileMoneyAsync()
{
var request = new NameEnquiryRequest
{
AccountNumber = "233246089019", //test phone number
PaymentChannel = Channels.INTERBANK,
Institution = InstitutionCodes.Mtn, // e.g., "300591" for MTN
TransactionId = Guid.NewGuid().ToString("N")
};
var response = await _client.NameEnquiry.GetNameEnquiryAsync(request);
if (response.IsSuccess)
{
return Ok(response!.Data!.AccountName);
}
return Ok($"Name Enquiry : {response.StatusDescription}");
}
[HttpGet("VerifyBulkMobileMoneyAsync", Name = "VerifyBulkMobileMoneyAsync")]
public async Task<IActionResult> VerifyBulkMobileMoneyAsync()
{
var requestBulkNameCheck = new BulkNameEnquiryRequest
{
BatchTransactionId = Guid.NewGuid().ToString("N"),
BulkNameEnquiryData =
[
new BulkNameEnquiryItem
{
AccountNumber = TestPhoneNumber,
Institution = InstitutionCodes.TestGhanaLimited
},
new BulkNameEnquiryItem
{
AccountNumber = TestPhoneNumber,
Institution = InstitutionCodes.Mtn
}
]
};
var response = await _client.NameEnquiry.GetBulkNameEnquiryAsync(requestBulkNameCheck);
if (response.IsSuccess)
{
return Ok(response!.Data!.BatchTransactionId);
}
return Ok($"Bulk Name Enquiry : {response.StatusDescription}");
}
2. Payment Collections
Mobile Money Collection
[HttpGet("MobileMoneyCollection", Name = "MobileMoneyCollection")]
public async Task<IActionResult> MobileMoneyCollection(decimal amount, string description)
{
// Process the collection
var collectionRequest = new DebitMoneyRequest
{
AccountNumber = TestPhoneNumber,
AccountName = /* from the name enquiry*/,
Amount = amount,
PaymentChannel = Channels.MNO,
Institution = InstitutionCodes.Mtn, // e.g., "300591" for MTN
TransactionId = Guid.NewGuid().ToString("N"),
DebitNarration = description,
Currency = "GHS"
};
var response = await _client.Collections.DebitMoneyAsync(collectionRequest);
if (response.IsSuccess){
return Ok(response!.Data!.TransactionId);
}
return Ok(response.StatusDescription);
}
Bank Collection (Not available)
/* .. not available */
3. Disbursements
Bank Disbursement
/*** Single Disbursement ***/
public async Task<IActionResult> DisburseToBankAsync(decimal amount, string description)
{
var request = new DisbursementRequest
{
AccountNumber = "TEST_ACCOUNT_NUMBER",
AccountName = /* from the name enquiry*/,
Amount = amount,
PaymentChannel = Channels.INTERBANK,
Institution = InstitutionCodes.StandardCharteredBank,
TransactionId = Guid.NewGuid().ToString("N"),
CreditNarration = description,
Currency = "GHS"
};
var response = await _client.Disbursements.DisburseAsync(request);
if (response.IsSuccess){
return Ok(response!.Data!.TransactionId);
}
return Ok(response.StatusDescription);
}
/*** Bulk Disbursement ***/
[HttpGet("DisburseBulkToBank", Name = "DisburseBulkToBank")]
public async Task<IActionResult> ProcessBulkDisbursementAsync(decimal amount)
{
/* you can have your recipient come from the database */
var recipients = new List<Recipient>(){
new Recipient {
AccountNumber = "_acount_number_here,
AccountName = "_acount_name_from_entity_name_check",
BankInstitutionCode = "_code_from_entity_name_check"
}
/** more...... **/
}
var request = new BulkPaymentRequest
{
BatchTransactionId = Guid.NewGuid().ToString("N"),
BulkPaymentData = recipients.Select(r => new BulkPaymentItem
{
AccountNumber = r.AccountNumber,
AccountName = r.AccountName,
Amount = amount,
Institution = (InstitutionCodes) int.Parse(r.BankInstitutionCode),
Narration = "This is a Bulk Payment for mass employee"
}).ToList()!
};
var response = await _client.BulkTransactions.BulkDisbursementAsync(request);
if (response.IsSuccess){
return Ok(response!.Data);
}
return Ok(response.StatusDescription);
}
Mobile Money Disbursement
/*** Single Disbursement ***/
public async Task<IActionResult> DisburseToMobileMoneyAsync(decimal amount, string description)
{
var request = new DisbursementRequest
{
AccountNumber = SCAccountNumber,
AccountName = /* from the name enquiry*/,
Amount = amount,
PaymentChannel = Channels.INTERBANK,
Institution = InstitutionCodes.StandardCharteredBank,
TransactionId = Guid.NewGuid().ToString("N"),
CreditNarration = description,
Currency = "GHS"
};
var response = await _client.Disbursements.DisburseAsync(request);
if (response.IsSuccess){
return Ok(response!.Data!.TransactionId);
}
return Ok(response.StatusDescription);
}
/*** Bulk Disbursement ***/
public async Task<IActionResult> ProcessBulkMobileMoneyDisbursementAsync(decimal amount)
{
/* you can have your recipient come from the database */
var recipients = new List<Recipient>(){
new Recipient {
AccountNumber = "_acount_number_here,
AccountName = "_acount_name_from_entity_name_check",
MomoInstitutionCode = "_code_from_entity_name_check"
}
/** more...... **/
}
var request = new BulkPaymentRequest
{
BatchTransactionId = Guid.NewGuid().ToString("N"),
BulkPaymentData = recipients.Select(r => new BulkPaymentItem
{
AccountNumber = r.AccountNumber,
AccountName = r.AccountName,
Amount = amount,
Institution = (InstitutionCodes) int.Parse(r.MomoInstitutionCode),
Narration = "This is a Bulk Payment for mass employee"
}).ToList()!
};
var response = await _client.BulkTransactions.BulkDisbursementAsync(request);
if (response.IsSuccess){
return Ok(response!.Data!);
}
return Ok(response.StatusDescription);
}
4. Transaction Management
Check Transaction Status
public async Task<TransactionStatusResponse> CheckTransactionStatusAsync(
string transactionId,
string transactionType)
{
var request = new TransactionStatusRequest
{
TransactionId = transactionId,
TransactionType = transactionType // "DEBIT" or "CREDIT"
};
var response = await _client.Transactions.GetTransactionStatusAsync(request);
return response.Data!;
}
/* You can also have it as a job */
private async Task MonitorTransactionStatusAsync(
string transactionId, string transactionType,
CancellationToken cancellationToken)
{
const int maxAttempts = 10;
const int delayMilliseconds = 2000;
for (int attempt = 0; attempt < maxAttempts; attempt++)
{
var response = await _client.Transactions.GetTransactionStatusAsync(
new TransactionStatusRequest
{
TransactionId = transactionId,
TransactionType = transactionType
},
cancellationToken);
if (!ErrorCodes.IsPending(response.StatusCode))
{
if (response.IsSuccess)
{
_logger.LogInformation("Transaction {TransactionId} completed successfully", transactionId);
return;
}
_logger.LogError("Transaction {TransactionId} failed: {StatusDescription}",
transactionId, response.StatusDescription);
return;
}
await Task.Delay(delayMilliseconds, cancellationToken);
}
_logger.LogWarning("Transaction {TransactionId} status check timed out", transactionId);
}
Reverse Transaction (Coming Soon)
/* .... */
5. Account Services
Check Balance
public async Task<(decimal Available, decimal Current)> GetBalanceAsync()
{
var response = await _client.Balance.GetBalanceAsync();
return (response.Data.AvailableBalance, response.Data.CurrentBalance);
}
KYC Verification (Coming Soon)
public async Task<KycResponse> VerifyCustomerAsync(
string customerId,
string documentType)
{
var request = new KycRequest
{
CustomerId = customerId,
DocumentType = documentType
};
var response = await _client.Kyc.VerifyCustomerAsync(request);
return response.Data;
}
Error Handling
The SDK uses a consistent response format LibertePayResponse<T>
that includes:
IsSuccess
: Boolean indicating if the operation succeededStatusCode
: String status code from the APIStatusDesc
: Human-readable status descriptionData
: The actual response data (when successful)Message
: Error message (when unsuccessful)
Example Error Handling
try
{
var response = await _client.Collections.DebitMoneyAsync(request);
if (!response.IsSuccess)
{
_logger.LogError("Collection failed: {Message}", response.Message);
throw new PaymentException(response.Message);
}
return response.Data;
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error during collection");
throw;
}
Callback Implementation
LibertePay sends callbacks to notify your application about transaction and mandate status updates. Here's how to implement callbacks:
1. Configure Callback URL
First, set your callback URL in the configuration:
{
"LibertePay": {
"CallbackUrl": "https://your-domain.com/api/callback", /*Provided during libertey pay setup*/
}
}
2. Callback Types and Scenarios
Transaction Callbacks
The gateway providor sends the actual status and results of an asynchronous request to the consumer via the url that has been configured for the consumer during onboarding. The consumer is expected to respond to the callback request with a specific response to close the transaction end to end.
Transaction callbacks are sent for various payment scenarios:
Mobile Money Collection
- Sent when a mobile money payment is initiated
- Sent when payment status changes (pending, success, failed)
- Sent when payment is reversed
Bank Transfer
- Sent when bank transfer is initiated
- Sent when transfer status changes
- Sent when transfer is reversed
Bulk Payment
- Sent for each individual payment in a bulk transaction
- Sent when bulk payment batch status changes
Mandate Callbacks
Mandate callbacks are sent for recurring payment scenarios:
Mandate Creation
- Sent when a new mandate is created
- Sent when mandate creation fails
- Sent when mandate is cancelled
Recurring Payment
- Sent when a recurring payment is initiated
- Sent when recurring payment status changes
- Sent when recurring payment fails
3. Callback Payload Structure
Transaction Callback
{
"transactionId": "string",
"reference": "string",
"amount": 0.00,
"currency": "string",
"status": "string",
"statusCode": "string",
"statusDescription": "string",
"timestamp": "2024-03-20T10:00:00Z",
"channel": "string",
"institutionCode": "string",
"accountNumber": "string",
"accountName": "string",
"narration": "string",
"isSuccess": true,
"metadata": {
"key": "value"
}
}
Mandate Callback
{
"mandateId": "string",
"transactionId": "string",
"reference": "string",
"status": "string",
"statusCode": "string",
"statusDescription": "string",
"timestamp": "2024-03-20T10:00:00Z",
"customerId": "string",
"customerName": "string",
"accountNumber": "string",
"accountName": "string",
"institutionCode": "string",
"channel": "string",
"frequency": "string",
"startDate": "2024-03-20",
"endDate": "2024-03-20",
"isSuccess": true,
"metadata": {
"key": "value"
}
}
4. Create Callback Controller
[ApiController]
[Route("api/[controller]")]
public class CallbackController : ControllerBase
{
private readonly ILibertePayClient _libertePayClient;
private readonly ILogger<CallbackController> _logger;
public CallbackController(
ILibertePayClient libertePayClient,
ILogger<CallbackController> logger)
{
_libertePayClient = libertePayClient;
_logger = logger;
}
[HttpPost("transaction")]
public async Task<IActionResult> HandleTransactionCallback(
[FromBody] CallbackRequest request)
{
try
{
var response = await _libertePayClient.Callbacks.HandleTransactionCallbackAsync(
async (_, ct) =>
{
// Log callback details
_logger.LogInformation(
"Received transaction callback for {TransactionId} with status {Status}",
request.TransactionId,
request.Status);
// example
switch (request.StatusCode)
{
case "00": // Success
_logger.LogInformation("SUCCESS RESPONSE");
break;
case "01": // Pending
_logger.LogInformation("PENDING RESPONSE");
break;
case "02": // Failed
_logger.LogInformation("FAILED RESPONSE");
break;
case "03": // Reversed
_logger.LogInformation("REVERSED RESPONSE");
break;
default:
_logger.LogWarning("Unknown status code: {StatusCode}", request.StatusCode);
break;
}
return await Task.FromResult(new CallbackResponse
{
Status = "OK",
Message = $"Transaction {request.TransactionId} processed successfully"
});
});
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing transaction callback");
return StatusCode(500, new CallbackResponse { Status = "ERROR" });
}
}
[HttpPost("mandate")]
public async Task<IActionResult> HandleMandateCallback(
[FromBody] MandateCallbackRequest request)
{
try
{
_logger.LogInformation(
"Received mandate callback for TransactionId: {TransactionId}, MandateId: {MandateId}",
request.TransactionId,
request.MandateId);
var response = await _libertePayClient.Callbacks.HandleMandateCallbackAsync(
async (_, ct) =>
{
// Handle different mandate statuses
switch (request.Status)
{
case "ACTIVE":
_logger.LogInformation("ACTIVE RESPONSE");
break;
case "CANCELLED":
_logger.LogInformation("CANCELLED RESPONSE");
break;
case "EXPIRED":
_logger.LogInformation("EXPIRED RESPONSE");
break;
case "FAILED":
_logger.LogInformation("FAILED RESPONSE");
break;
default:
_logger.LogWarning("Unknown mandate status: {Status}", request.Status);
break;
}
return await Task.FromResult(new CallbackResponse
{
Status = "OK",
Message = $"Mandate {request.MandateId} processed successfully"
});
});
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing mandate callback");
return StatusCode(500, new CallbackResponse
{
Status = "ERROR",
Message = "Internal server error"
});
}
}
}
Institution Codes
The SDK provides a type-safe way to use institution codes through the InstitutionCodes
enum. This ensures:
- Compile-time checking of valid institution codes
- IntelliSense support for available institutions
- Automatic conversion to the correct string format for API calls
Available Institution Codes
Mobile Money Operators
InstitutionCodes.Mtn
(300591)InstitutionCodes.Vodafone
(300592)InstitutionCodes.AirtelTigo
(300593)- /* check InstitutionCodes Enum for more */
Banks
InstitutionCodes.GcbBankLimited
(300304)InstitutionCodes.EcobankGhanaLtd
(300312)InstitutionCodes.AgriculturalDevelopmentBank
(300307)InstitutionCodes.CalBankLimited
(300313)InstitutionCodes.FidelityBankLimited
(300323)InstitutionCodes.AccessBankLtd
(300329)InstitutionCodes.ZenithBankGhanaLtd
(300311)InstitutionCodes.GuarantyTrustBank
(300322)InstitutionCodes.UnitedBankOfAfrica
(300325)InstitutionCodes.StanbicBank
(300318)InstitutionCodes.RepublicBankLimited
(300310)InstitutionCodes.FirstBankOfNigeria
(300319)InstitutionCodes.AbsaBankGhanaLimited
(300303)InstitutionCodes.NationalInvestmentBank
(300305)InstitutionCodes.Omnibisic
(300324)InstitutionCodes.ConsolidatedBankGhana
(300331)- /* check InstitutionCodes Enum for more */
Using Institution Codes
// Direct enum usage
var request = new NameEnquiryRequest
{
AccountNumber = "1234567890",
InstitutionCode = InstitutionCodes.Mtn //example
};
// Get institution code as string
string code = InstitutionCodes.Mtn.ToString(); // Returns "300591"
Channel Types
INTERBANK
: For bank transactionsMNO
: For mobile money transactionsCARD
: For card payments (coming soon)
Support
For support, please contact:
- Email: michael.ameyaw@persol.com
- Documentation: https://docs.libertepay.com
- API Reference: https://api.libertepay.com
License
This SDK is licensed under the MIT License. See the LICENSE file for details.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Configuration.Abstractions (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
- System.Net.Http.Json (>= 8.0.0)
- System.Text.Json (>= 8.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated | |
---|---|---|---|
1.0.3 | 90 | 5/23/2025 | |
1.0.1-alpha | 182 | 5/22/2025 | |
1.0.0 | 104 | 5/23/2025 | |
1.0.0-beta | 147 | 5/23/2025 |