Liberte360Pay 1.2.0

dotnet add package Liberte360Pay --version 1.2.0
                    
NuGet\Install-Package Liberte360Pay -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Liberte360Pay" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Liberte360Pay" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Liberte360Pay" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Liberte360Pay --version 1.2.0
                    
#r "nuget: Liberte360Pay, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Liberte360Pay@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Liberte360Pay&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Liberte360Pay&version=1.2.0
                    
Install as a Cake Tool

Liberte 360Pay .NET SDK

NuGet License: MIT

Official .NET SDK for the 360Pay Merchant API - A fluent API client for payments, disbursements, and account verification in Ghana.

✨ Features

  • Fluent API Design - Intuitive method chaining for building requests
  • Async/Await Support - Full async support with cancellation tokens
  • Dependency Injection - First-class DI support with AddLiberte360Pay()
  • Multi-Targeting - Supports .NET 8.0 and .NET Standard 2.0
  • Type Safety - Strongly-typed request and response models
  • Comprehensive Error Handling - Detailed exceptions with error codes
  • Production Ready - Supports both UAT and Production environments

📦 Installation

Via NuGet Package Manager

dotnet add package Liberte360Pay

Via Package Manager Console

Install-Package Liberte360Pay

🚀 Quick Start

Without Dependency Injection

using Liberte360Pay;
using Liberte360Pay.Configuration;
using Liberte360Pay.Models.BulkDisbursement;
using Liberte360Pay.Models.BulkNameVerify;
using Liberte360Pay.Utilities;

// Configure the client
var options = new Liberte360PayOptions
{
    ApiKey = "your-api-key-here",
    BaseUrl = "https://uat-360pay-merchant-api.libertepay.com" // UAT
    // BaseUrl = "https://360pay-merchant-api.libertepay.com" // Production
};

var client = new Liberte360PayClient(options);

// Verify account name using InstitutionCode enum
var verifyResponse = await client.NameVerify()
    .WithAccountNumber("233XXXXXXXXX")
    .WithInstitutionCode(InstitutionCode.Mtn)
    .ExecuteAsync();

Console.WriteLine($"Account Name: {verifyResponse.Data.AccountName}");

// Make a disbursement using InstitutionCode enum
var disbursementResponse = await client.Disbursement()
    .WithAccountName(verifyResponse.Data.AccountName)
    .WithAccountNumber("233XXXXXXXXX")
    .WithAmount(100.00m)
    .WithInstitutionCode(InstitutionCode.Mtn)
    .WithTransactionId(Guid.NewGuid().ToString())
    .WithReference("Payment for services")
    .ExecuteAsync();

Console.WriteLine($"Transaction ID: {disbursementResponse.Data.TransactionId}");
Console.WriteLine($"Message: {disbursementResponse.Data.TransactionMessage}");
Program.cs / Startup.cs
using Liberte360Pay.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Method 1: Using configuration action
builder.Services.AddLiberte360Pay(options =>
{
    options.ApiKey = builder.Configuration["Liberte360Pay:ApiKey"];
    options.BaseUrl = builder.Configuration["Liberte360Pay:BaseUrl"];
    options.DefaultCurrency = "GHS";
    options.TimeoutSeconds = 30;
});

// Method 2: Quick setup with API key
builder.Services.AddLiberte360Pay(
    apiKey: "your-api-key-here",
    baseUrl: "https://uat-360pay-merchant-api.libertepay.com"
);

var app = builder.Build();
appsettings.json
{
  "Liberte360Pay": {
    "ApiKey": "your-api-key-here",
    "BaseUrl": "https://uat-360pay-merchant-api.libertepay.com",
    "DefaultCurrency": "GHS",
    "TimeoutSeconds": 30
  }
}
Usage in Controllers/Services
using Microsoft.AspNetCore.Mvc;
using Liberte360Pay;

[ApiController]
[Route("api/[controller]")]
public class PaymentsController : ControllerBase
{
    private readonly ILiberte360PayClient _threeSixtyPayClient;

    public PaymentsController(ILiberte360PayClient threeSixtyPayClient)
    {
        _threeSixtyPayClient = threeSixtyPayClient;
    }

    [HttpPost("verify")]
    public async Task<IActionResult> VerifyAccount(
        [FromBody] NameVerifyRequest request,
        CancellationToken cancellationToken)
    {
        try
        {
            var response = await _threeSixtyPayClient.NameVerify()
                .WithAccountNumber(request.AccountNumber)
                .WithInstitutionCode(request.InstitutionCode)
                .ExecuteAsync(cancellationToken);

            return Ok(new
            {
                accountName = response.Data.AccountName,
                accountNumber = response.Data.AccountNumber,
                verified = true
            });
        }
        catch (Exception ex)
        {
            return BadRequest(new { error = ex.Message });
        }
    }

    [HttpPost("disburse")]
    public async Task<IActionResult> Disburse(
        [FromBody] DisbursementRequest request,
        CancellationToken cancellationToken)
    {
        try
        {
            var response = await _threeSixtyPayClient.Disbursement()
                .WithAccountName(request.AccountName)
                .WithAccountNumber(request.AccountNumber)
                .WithAmount(request.Amount)
                .WithInstitutionCode(request.InstitutionCode)
                .WithTransactionId(request.TransactionId)
                .WithReference(request.Reference)
                .ExecuteAsync(cancellationToken);

            return Ok(new
            {
                transactionId = response.Data.TransactionId,
                message = response.Data.TransactionMessage,
                status = response.Status
            });
        }
        catch (Exception ex)
        {
            return BadRequest(new { error = ex.Message });
        }
    }
}

📚 Sample Application

For a complete working example demonstrating all SDK features, you can clone our sample repository:

git clone https://github.com/SWD-DEV/SampleLiberte360PayTesting.git

The sample includes:

  • Complete examples for all API endpoints
  • Dependency injection setup
  • Error handling patterns
  • Metrics collection examples
  • Best practices implementation

📘 API Reference

Name Verification

Verify the account name before making any transaction. This is mandatory before disbursements.

using Liberte360Pay.Utilities;

var response = await client.NameVerify()
    .WithAccountNumber("233XXXXXXXXX")  // Required: 12 digits for mobile money
    .WithInstitutionCode(InstitutionCode.Mtn)  // Required: Use enum for type safety
    .ExecuteAsync(cancellationToken);   // Optional: Pass cancellation token

// Access response
string accountName = response.Data.AccountName;
string accountNumber = response.Data.AccountNumber;
bool isSuccess = response.IsSuccess;
string code = response.Code;
string message = response.Message;

Disbursement

Send money to a mobile money or bank account.

using Liberte360Pay.Utilities;

var response = await client.Disbursement()
    .WithAccountName("John Doe")                    // Required: From NameVerify
    .WithAccountNumber("233XXXXXXXXX")              // Required: 12 digits for mobile money
    .WithAmount(100.00m)                            // Required: Amount in GHS
    .WithInstitutionCode(InstitutionCode.Mtn)      // Required: Use enum for type safety
    .WithTransactionId(Guid.NewGuid().ToString())   // Required: Your unique transaction ID
    .WithCurrency("GHS")                            // Optional: Defaults to GHS
    .WithReference("Payment for services")          // Optional: Transaction description
    .AddMetaData("invoice_id", "INV-12345")        // Optional: Add metadata
    .AddMetaData("customer_id", "CUST-67890")      // Optional: Chain multiple metadata
    .ExecuteAsync(cancellationToken);               // Optional: Pass cancellation token

// Access response
string transactionId = response.Data.TransactionId;
string message = response.Data.TransactionMessage;
bool isSuccess = response.IsSuccess;
Complete Disbursement Example
try
{
    // Step 1: Verify the account first (mandatory)
    var verifyResponse = await client.NameVerify()
        .WithAccountNumber("233XXXXXXXXX")
        .WithInstitutionCode(InstitutionCode.Mtn)
        .ExecuteAsync();

    if (!verifyResponse.IsSuccess)
    {
        throw new Exception($"Verification failed: {verifyResponse.Message}");
    }

    Console.WriteLine($"Verified: {verifyResponse.Data.AccountName}");

    // Step 2: Make the disbursement
    var disbursementResponse = await client.Disbursement()
        .WithAccountName(verifyResponse.Data.AccountName)
        .WithAccountNumber("233XXXXXXXXX")
        .WithAmount(150.50m)
        .WithInstitutionCode(InstitutionCode.Mtn)
        .WithTransactionId($"TXN-{DateTime.UtcNow.Ticks}")
        .WithReference("Salary Payment - November")
        .AddMetaData("employee_id", "EMP001")
        .AddMetaData("department", "Engineering")
        .ExecuteAsync();

    if (disbursementResponse.IsSuccess)
    {
        Console.WriteLine($" Disbursement successful!");
        Console.WriteLine($"Transaction ID: {disbursementResponse.Data.TransactionId}");
        Console.WriteLine($"Message: {disbursementResponse.Data.TransactionMessage}");
    }
}
catch (ValidationException ex)
{
    Console.WriteLine($" Validation Error: {ex.Message}");
    Console.WriteLine($"Parameter: {ex.ParameterName}");
}
catch (ApiException ex)
{
    Console.WriteLine($" API Error: {ex.Message}");
    Console.WriteLine($"Status Code: {ex.StatusCode}");
    Console.WriteLine($"Response Code: {ex.ResponseCode}");
    Console.WriteLine($"Response Content: {ex.ResponseContent}");
}
catch (Liberte360PayException ex)
{
    Console.WriteLine($" SDK Error: {ex.Message}");
}

Collections

Debit money from a customer's mobile money or bank account.

using Liberte360Pay.Utilities;

var response = await client.Collection()
    .WithAccountName("John Doe")                    // Required: From NameVerify
    .WithAccountNumber("233XXXXXXXXX")              // Required: 12 digits for mobile money
    .WithAmount(100.00m)                            // Required: Amount in GHS
    .WithInstitutionCode(InstitutionCode.Mtn)      // Required: Institution code
    .WithTransactionId(Guid.NewGuid().ToString())   // Required: Your unique transaction ID
    .WithCurrency("GHS")                            // Optional: Defaults to GHS
    .WithReference("Payment for services")          // Optional: Transaction description
    .AddMetaData("invoice_id", "INV-12345")        // Optional: Add metadata
    .AddMetaData("customer_id", "CUST-67890")       // Optional: Chain multiple metadata
    .ExecuteAsync(cancellationToken);               // Optional: Pass cancellation token

// Access response
string transactionId = response.Data.TransactionId;
string message = response.Data.TransactionMessage;
bool isSuccess = response.IsSuccess;
Complete Collection Example
try
{
    // Step 1: Verify the account first (mandatory)
    var verifyResponse = await client.NameVerify()
        .WithAccountNumber("233XXXXXXXXX")
        .WithInstitutionCode(InstitutionCode.Mtn)
        .ExecuteAsync();

    if (!verifyResponse.IsSuccess)
    {
        throw new Exception($"Verification failed: {verifyResponse.Message}");
    }

    Console.WriteLine($"Verified: {verifyResponse.Data.AccountName}");

    // Step 2: Collect payment
    var collectionResponse = await client.Collection()
        .WithAccountName(verifyResponse.Data.AccountName)
        .WithAccountNumber("233XXXXXXXXX")
        .WithAmount(150.50m)
        .WithInstitutionCode(InstitutionCode.Mtn)
        .WithTransactionId($"TXN-{DateTime.UtcNow.Ticks}")
        .WithReference("Invoice Payment - INV-001")
        .AddMetaData("invoice_id", "INV-001")
        .AddMetaData("customer_id", "CUST-001")
        .ExecuteAsync();

    if (collectionResponse.IsSuccess)
    {
        Console.WriteLine($" Collection successful!");
        Console.WriteLine($"Transaction ID: {collectionResponse.Data.TransactionId}");
        Console.WriteLine($"Message: {collectionResponse.Data.TransactionMessage}");
    }
}
catch (ValidationException ex)
{
    Console.WriteLine($"Validation Error: {ex.Message}");
}
catch (ApiException ex)
{
    Console.WriteLine($"API Error: {ex.Message}");
}

Bulk Disbursement

Send money to multiple recipients in a single API call. Perfect for payroll, batch payments, or sending to multiple customers.

// Build disbursement items from collection (recommended for large batches)
var disbursementItems = new List<BulkDisbursementItem>
{
    new BulkDisbursementItem
    {
        AccountName = "John Doe",
        AccountNumber = "233XXXXXXXXX",
        Amount = 100.00m,
        InstitutionCode = "300591",
        TransactionId = Guid.NewGuid().ToString(),
        Currency = "GHS",
        Reference = "Payment 1",
        MetaData = new Dictionary<string, string>
        {
            { "employee_id", "EMP001" }
        }
    },
    new BulkDisbursementItem
    {
        AccountName = "Jane Smith",
        AccountNumber = "233YYYYYYYYY",
        Amount = 200.00m,
        InstitutionCode = "300591",
        TransactionId = Guid.NewGuid().ToString(),
        Currency = "GHS",
        Reference = "Payment 2",
        MetaData = new Dictionary<string, string>
        {
            { "employee_id", "EMP002" }
        }
    }
};

var response = await client.BulkDisbursement()
    .WithDisbursements(disbursementItems)
    .ExecuteAsync(cancellationToken);

// Access response
string bulkTransactionId = response.Data.BulkTransactionId;
foreach (var result in response.Data.Results)
{
    Console.WriteLine($"Transaction ID: {result.TransactionId}");
    Console.WriteLine($"Status: {result.StatusDesc}");
    Console.WriteLine($"Message: {result.Message}");
}
Complete Bulk Disbursement Example
try
{
    // Step 1: Verify accounts first (recommended)
    var verify1 = await client.NameVerify()
        .WithAccountNumber("233XXXXXXXXX")
        .WithInstitutionCode(InstitutionCode.Mtn)
        .ExecuteAsync();

    var verify2 = await client.NameVerify()
        .WithAccountNumber("233YYYYYYYYY")
        .WithInstitutionCode(InstitutionCode.Mtn)
        .ExecuteAsync();

    // Step 2: Build disbursement items from collection
    var disbursementItems = new List<BulkDisbursementItem>
    {
        new BulkDisbursementItem
        {
            AccountName = verify1.Data!.AccountName,
            AccountNumber = "233XXXXXXXXX",
            Amount = 100.00m,
            InstitutionCode = InstitutionCode.Mtn.GetCodeString(),
            TransactionId = $"TXN-{Guid.NewGuid()}",
            Currency = "GHS",
            Reference = "Salary Payment",
            MetaData = new Dictionary<string, string>
            {
                { "department", "Sales" }
            }
        },
        new BulkDisbursementItem
        {
            AccountName = verify2.Data!.AccountName,
            AccountNumber = "233YYYYYYYYY",
            Amount = 200.00m,
            InstitutionCode = InstitutionCode.Mtn.GetCodeString(),
            TransactionId = $"TXN-{Guid.NewGuid()}",
            Currency = "GHS",
            Reference = "Bonus Payment"
        }
    };

    // Step 3: Execute bulk disbursement
    var bulkResponse = await client.BulkDisbursement()
        .WithDisbursements(disbursementItems)
        .ExecuteAsync();

    Console.WriteLine($"Bulk Disbursement submitted!");
    Console.WriteLine($"   Bulk Transaction ID: {bulkResponse.Data.BulkTransactionId}");
    
    foreach (var result in bulkResponse.Data.Results)
    {
        Console.WriteLine($"   - {result.TransactionId}: {result.StatusDesc} - {result.Message}");
    }
}
catch (ValidationException ex)
{
    Console.WriteLine($"Validation Error: {ex.Message}");
}
catch (ApiException ex)
{
    Console.WriteLine($"API Error: {ex.Message}");
}
Large Batch Example (100+ Items)

For large batches, build items programmatically:

// Get employees from database/CSV/etc.
var employees = GetEmployeesFromDatabase(); // 100+ items

// Build disbursement items
var disbursementItems = employees.Select(emp => new BulkDisbursementItem
{
    AccountName = emp.VerifiedName,
    AccountNumber = emp.AccountNumber,
    Amount = emp.Salary,
    InstitutionCode = "300591",
    TransactionId = $"TXN-{emp.Id}-{DateTime.UtcNow.Ticks}",
    Currency = "GHS",
    Reference = $"Salary Payment - {emp.Name}",
    MetaData = new Dictionary<string, string>
    {
        { "employee_id", emp.Id.ToString() },
        { "department", emp.Department }
    }
}).ToList();

// Execute bulk disbursement
var bulkResponse = await client.BulkDisbursement()
    .WithDisbursements(disbursementItems)
    .ExecuteAsync();

Bulk Name Verify

Verify multiple account names in a single API call. Perfect for verifying large batches of accounts before processing payments.

// Build verification items from collection (recommended for large batches)
var verificationItems = new List<BulkNameVerifyItem>
{
    new BulkNameVerifyItem
    {
        AccountNumber = "233XXXXXXXXX",
        InstitutionCode = "300591"
    },
    new BulkNameVerifyItem
    {
        AccountNumber = "233YYYYYYYYY",
        InstitutionCode = "300591"
    }
};

var response = await client.BulkNameVerify()
    .WithVerifications(verificationItems)
    .ExecuteAsync(cancellationToken);

// Access response
foreach (var result in response.Data)
{
    Console.WriteLine($"Account: {result.AccountNumber}");
    Console.WriteLine($"Name: {result.AccountName}");
    Console.WriteLine($"Status: {result.StatusDesc}");
}
Complete Bulk Name Verify Example
try
{
    // Build verification items from collection
    var verificationItems = new List<BulkNameVerifyItem>
    {
        new BulkNameVerifyItem
        {
            AccountNumber = "233XXXXXXXXX",
            InstitutionCode = InstitutionCode.Mtn.GetCodeString()
        },
        new BulkNameVerifyItem
        {
            AccountNumber = "233YYYYYYYYY",
            InstitutionCode = InstitutionCode.Mtn.GetCodeString()
        },
        new BulkNameVerifyItem
        {
            AccountNumber = "233ZZZZZZZZZ",
            InstitutionCode = InstitutionCode.AtMoney.GetCodeString()
        }
    };

    var bulkVerifyResponse = await client.BulkNameVerify()
        .WithVerifications(verificationItems)
        .ExecuteAsync();

    Console.WriteLine($"Bulk Name Verify completed!");
    
    foreach (var result in bulkVerifyResponse.Data)
    {
        if (result.StatusDesc?.ToLowerInvariant() == "success")
        {
            Console.WriteLine($"  {result.AccountNumber}: {result.AccountName}");
        }
        else
        {
            Console.WriteLine($"  {result.AccountNumber}: {result.Message}");
        }
    }
}
catch (ValidationException ex)
{
    Console.WriteLine($" Validation Error: {ex.Message}");
}
catch (ApiException ex)
{
    Console.WriteLine($" API Error: {ex.Message}");
}
Large Batch Example (100+ Items)

For large batches, build items programmatically:

// Get account numbers from database/CSV/etc.
var accounts = GetAccountsFromDatabase(); // 100+ items

// Build verification items
var verificationItems = accounts.Select(acc => new BulkNameVerifyItem
{
    AccountNumber = acc.AccountNumber,
    InstitutionCode = acc.InstitutionCode
}).ToList();

// Execute bulk name verify
var bulkVerifyResponse = await client.BulkNameVerify()
    .WithVerifications(verificationItems)
    .ExecuteAsync();

Bulk Disbursement Status Check

Check the status of a bulk disbursement transaction. Returns an array of transaction statuses.

var response = await client.BulkDisbursementStatus()
    .WithBulkTransactionId("BULK-TXN-12345")         // Required: Bulk transaction ID
    .ExecuteAsync(cancellationToken);

// Access response - Data is a list of transaction statuses
foreach (var item in response.Data)
{
    Console.WriteLine($"Transaction ID: {item.TransactionId}");
    Console.WriteLine($"External Transaction ID: {item.ExternalTransactionId}");
    Console.WriteLine($"Account Name: {item.AccountName}");
    Console.WriteLine($"Account Number: {item.AccountNumber}");
    Console.WriteLine($"Amount: {item.Amount}");
    Console.WriteLine($"Date Created: {item.DateCreated}");
    Console.WriteLine($"Status Code: {item.StatusCode}");
    Console.WriteLine($"Is Reversed: {item.IsReversed}");
}
Complete Bulk Disbursement Status Check Example
try
{
    var statusResponse = await client.BulkDisbursementStatus()
        .WithBulkTransactionId("BULK-TXN-12345")
        .ExecuteAsync();

    if (statusResponse.IsSuccess && statusResponse.Data != null)
    {
        Console.WriteLine($"Bulk Disbursement Status Retrieved!");
        Console.WriteLine($"Total Transactions: {statusResponse.Data.Count}\n");
        
        foreach (var item in statusResponse.Data)
        {
            Console.WriteLine($"Transaction ID: {item.TransactionId}");
            Console.WriteLine($"  External Transaction ID: {item.ExternalTransactionId}");
            Console.WriteLine($"  Account: {item.AccountName} ({item.AccountNumber})");
            Console.WriteLine($"  Amount: {item.Amount}");
            Console.WriteLine($"  Date Created: {item.DateCreated}");
            Console.WriteLine($"  Status Code: {item.StatusCode}");
            Console.WriteLine($"  Message: {item.Message ?? "N/A"}");
            Console.WriteLine($"  Is Reversed: {item.IsReversed}");
            Console.WriteLine($"  Bulk Transaction ID: {item.BulkTransactionId}");
            Console.WriteLine();
        }
    }
    else
    {
        Console.WriteLine($"Status Check Failed: {statusResponse.Message}");
    }
}
catch (ValidationException ex)
{
    Console.WriteLine($"Validation Error: {ex.Message}");
}
catch (ApiException ex)
{
    Console.WriteLine($"API Error: {ex.Message}");
}

Transaction Status Check

Check the status of an individual transaction (disbursement or collection).

var response = await client.TransactionStatus()
    .WithTransactionId("TXN-12345")                    // Required: Transaction ID
    .ExecuteAsync(cancellationToken);

// Access response
string accountName = response.Data.AccountName;
string accountNumber = response.Data.AccountNumber;
string amount = response.Data.Amount;
string dateCreated = response.Data.DateCreated;
string externalTransactionId = response.Data.ExternalTransactionId;
bool isReversed = response.Data.IsReversed;
string message = response.Data.Message;
string statusCode = response.Data.StatusCode;
string transactionId = response.Data.TransactionId;
Complete Transaction Status Check Example
try
{
    var statusResponse = await client.TransactionStatus()
        .WithTransactionId("TXN-12345")
        .ExecuteAsync();

    if (statusResponse.IsSuccess)
    {
        Console.WriteLine($" Transaction Status Retrieved!\n");
        Console.WriteLine($" Transaction ID: {statusResponse.Data.TransactionId}");
        Console.WriteLine($" External Transaction ID: {statusResponse.Data.ExternalTransactionId}");
        Console.WriteLine($" Account Name: {statusResponse.Data.AccountName}");
        Console.WriteLine($" Account Number: {statusResponse.Data.AccountNumber}");
        Console.WriteLine($" Amount: {statusResponse.Data.Amount}");
        Console.WriteLine($" Date Created: {statusResponse.Data.DateCreated}");
        Console.WriteLine($" Status Code: {statusResponse.Data.StatusCode}");
        Console.WriteLine($" Message: {statusResponse.Data.Message}");
        Console.WriteLine($" Is Reversed: {statusResponse.Data.IsReversed}");
    }
    else
    {
        Console.WriteLine($" Status Check Failed: {statusResponse.Message}");
        Console.WriteLine($"   Code: {statusResponse.Code}");
    }
}
catch (ValidationException ex)
{
    Console.WriteLine($"Validation Error: {ex.Message}");
}
catch (ApiException ex)
{
    Console.WriteLine($"API Error: {ex.Message}");
    Console.WriteLine($"   Status Code: {ex.StatusCode}");
    Console.WriteLine($"   Error Code: {ex.ErrorCode}");
}

Transaction Status Check By Reference

Check the status of a transaction using its reference. This endpoint provides detailed transaction information including fees, total amount, and transaction action.

var response = await client.TransactionStatusByReference()
    .WithReference("wqIxrr6K3I")                    // Required: Transaction reference
    .ExecuteAsync(cancellationToken);

// Access response
string transactionId = response.Data.TransactionId;
string transactionStatus = response.Data.TransactionStatus;
decimal amount = response.Data.Amount;
decimal totalAmount = response.Data.TotalAmount;
decimal fee = response.Data.Fee;
string currency = response.Data.Currency;
string customerEmail = response.Data.CustomerEmail;
string transactionAction = response.Data.TransactionAction;
int status = response.Data.Status;
string reference = response.Data.Reference;
Dictionary<string, object>? metaData = response.Data.MetaData;
Complete Transaction Status By Reference Example
try
{
    var statusResponse = await client.TransactionStatusByReference()
        .WithReference("wqIxrr6K3I")
        .ExecuteAsync();

    if (statusResponse.IsSuccess)
    {
        Console.WriteLine(" Transaction Status Retrieved!\n");
        Console.WriteLine($" Transaction ID: {statusResponse.Data.TransactionId}");
        Console.WriteLine($" Reference: {statusResponse.Data.Reference}");
        Console.WriteLine($" Transaction Status: {statusResponse.Data.TransactionStatus}");
        Console.WriteLine($" Status Code: {statusResponse.Data.Status}");
        Console.WriteLine($" Amount: {statusResponse.Data.Amount} {statusResponse.Data.Currency}");
        Console.WriteLine($" Fee: {statusResponse.Data.Fee} {statusResponse.Data.Currency}");
        Console.WriteLine($" Total Amount: {statusResponse.Data.TotalAmount} {statusResponse.Data.Currency}");
        Console.WriteLine($" Transaction Action: {statusResponse.Data.TransactionAction}");
        Console.WriteLine($" Customer Email: {statusResponse.Data.CustomerEmail}");
        
        if (statusResponse.Data.MetaData != null)
        {
            Console.WriteLine($" Metadata: {System.Text.Json.JsonSerializer.Serialize(statusResponse.Data.MetaData)}");
        }
    }
    else
    {
        Console.WriteLine($" Status Check Failed: {statusResponse.Message}");
        Console.WriteLine($"   Code: {statusResponse.Code}");
    }
}
catch (ValidationException ex)
{
    Console.WriteLine($"Validation Error: {ex.Message}");
    Console.WriteLine($"   Parameter: {ex.ParameterName}");
}
catch (ApiException ex)
{
    Console.WriteLine($"API Error: {ex.Message}");
    Console.WriteLine($"   Status Code: {ex.StatusCode}");
    Console.WriteLine($"   Error Code: {ex.ErrorCode}");
}

Disbursement Balance Check

Check the available balance in your disbursement account.

var response = await client.DisbursementBalance()
    .ExecuteAsync(cancellationToken);

// Access response
string accountName = response.Data.AccountName;
string accountNumber = response.Data.AccountNumber;
string accountType = response.Data.AccountType;
decimal availableBalance = response.Data.AvailableBalance;
string currency = response.Data.Currency;
Complete Disbursement Balance Check Example
try
{
    var balanceResponse = await client.DisbursementBalance()
        .ExecuteAsync();

    if (balanceResponse.IsSuccess)
    {
        Console.WriteLine(" Balance Retrieved!\n");
        Console.WriteLine($" Account Name: {balanceResponse.Data.AccountName}");
        Console.WriteLine($" Account Number: {balanceResponse.Data.AccountNumber}");
        Console.WriteLine($" Account Type: {balanceResponse.Data.AccountType}");
        Console.WriteLine($" Available Balance: {balanceResponse.Data.AvailableBalance:N2} {balanceResponse.Data.Currency}");
    }
    else
    {
        Console.WriteLine($" Balance Check Failed: {balanceResponse.Message}");
        Console.WriteLine($"   Code: {balanceResponse.Code}");
        Console.WriteLine($"   Status: {balanceResponse.Status}");
    }
}
catch (ApiException ex)
{
    Console.WriteLine($" API Error: {ex.Message}");
    Console.WriteLine($" HTTP Status: {ex.StatusCode}");
    Console.WriteLine($" Response Code: {ex.ResponseCode}");
}
catch (Liberte360PayException ex)
{
    Console.WriteLine($" SDK Error: {ex.Message}");
}

Checkout Initialize

Initialize a new checkout session for payment collection.

var response = await client.Checkout()
    .WithEmail("customer@example.com")              // Required: Customer email
    .WithAmount(100.00m)                            // Required: Amount to be paid
    .WithPhoneNumber("233XXXXXXXXX")                // Optional: Phone number
    .WithPaymentSlug("payment-slug")                 // Optional: Payment slug
    .ExecuteAsync(cancellationToken);

// Access response
string accessCode = response.Data.AccessCode;
string paymentUrl = response.Data.PaymentUrl;
string reference = response.Data.Reference;
Complete Checkout Initialize Example
try
{
    var checkoutResponse = await client.Checkout()
        .WithEmail("customer@example.com")
        .WithAmount(100.00m)
        .WithPhoneNumber("2330246089019")
        .WithPaymentSlug("store-payment")
        .ExecuteAsync();

    if (checkoutResponse.IsSuccess)
    {
        Console.WriteLine($" Checkout Session Created!\n");
        Console.WriteLine($" Access Code: {checkoutResponse.Data.AccessCode}");
        Console.WriteLine($" Payment URL: {checkoutResponse.Data.PaymentUrl}");
        Console.WriteLine($" Reference: {checkoutResponse.Data.Reference}");
        Console.WriteLine($"\n Redirect customer to: {checkoutResponse.Data.PaymentUrl}");
    }
    else
    {
        Console.WriteLine($" Checkout Failed: {checkoutResponse.Message}");
        Console.WriteLine($"   Code: {checkoutResponse.Code}");
    }
}
catch (ValidationException ex)
{
    Console.WriteLine($"Validation Error: {ex.Message}");
    Console.WriteLine($"   Parameter: {ex.ParameterName}");
}
catch (ApiException ex)
{
    Console.WriteLine($"API Error: {ex.Message}");
    Console.WriteLine($"   Status Code: {ex.StatusCode}");
    Console.WriteLine($"   Error Code: {ex.ErrorCode}");
}

🏦 Institution Codes

The SDK provides a strongly-typed InstitutionCode enum for all supported institutions. This ensures type safety and IntelliSense support when working with institution codes.

Using the InstitutionCode Enum

using Liberte360Pay.Utilities;

// Use the enum directly - type-safe and IntelliSense supported
var response = await client.NameVerify()
    .WithAccountNumber("233XXXXXXXXX")
    .WithInstitutionCode(InstitutionCode.Mtn)
    .ExecuteAsync();

// Or use it in disbursements
var disbursementResponse = await client.Disbursement()
    .WithAccountName("John Doe")
    .WithAccountNumber("233XXXXXXXXX")
    .WithAmount(100.00m)
    .WithInstitutionCode(InstitutionCode.Mtn)
    .WithTransactionId(Guid.NewGuid().ToString())
    .ExecuteAsync();

Available Institution Codes

The enum includes all supported institutions organized by type:

Mobile Network Operators (MNO)
InstitutionCode.Mtn                    // 300591 - MTN Mobile Money
InstitutionCode.AtMoney                // 300592 - AT Money (AirtelTigo)
InstitutionCode.TelecelCash           // 300594 - Telecel Cash
InstitutionCode.GMoney                // 300574 - G-Money
InstitutionCode.Ghanapay              // 300595 - GHANAPAY
InstitutionCode.YupGhanaLimited      // 300597 - YUP GHANA LIMITED
InstitutionCode.ZeepayGhanaLimited    // 300479 - ZEEPAY GHANA LIMITED
Major Banks
InstitutionCode.StandardCharteredBank      // 300302 - STANDARD CHARTERED BANK
InstitutionCode.AbsaBankGhanaLimited       // 300303 - ABSA BANK GHANA LIMITED
InstitutionCode.GcbBankLimited             // 300304 - GCB BANK LIMITED
InstitutionCode.EcobankGhanaLtd            // 300312 - ECOBANK GHANA LTD
InstitutionCode.CalBankLimited              // 300313 - CAL BANK LIMITED
InstitutionCode.StanbicBank                 // 300318 - STANBIC BANK
InstitutionCode.FidelityBankLimited         // 300323 - FIDELITY BANK LIMITED
InstitutionCode.AccessBankLtd               // 300329 - ACCESS BANK LTD
InstitutionCode.ConsolidatedBankGhana       // 300331 - CONSOLIDATED BANK GHANA
// ... and many more
Third-Party Payment Providers (3PP)
InstitutionCode.Eranzact                    // 300380 - ETRANZACT
InstitutionCode.Junipay                     // 300437 - JUNIPAY
InstitutionCode.Alpay                      // 300442 - ALPAY
InstitutionCode.Korba                      // 300458 - KORBA
InstitutionCode.Hubtel                     // 300466 - HUBTEL
InstitutionCode.Payswitch                  // 300485 - PAYSWITCH
InstitutionCode.Slydepay                   // 300487 - SLYDEPAY
InstitutionCode.Bigpay                    // 300489 - BIGPAY
// ... and many more

Complete Example with Enum

using Liberte360Pay;
using Liberte360Pay.Utilities;

// Step 1: Verify account using enum
var verifyResponse = await client.NameVerify()
    .WithAccountNumber("233XXXXXXXXX")
    .WithInstitutionCode(InstitutionCode.Mtn)
    .ExecuteAsync();

if (verifyResponse.IsSuccess)
{
    // Step 2: Make disbursement using enum
    var disbursementResponse = await client.Disbursement()
        .WithAccountName(verifyResponse.Data.AccountName)
        .WithAccountNumber("233XXXXXXXXX")
        .WithAmount(100.00m)
        .WithInstitutionCode(InstitutionCode.Mtn)
        .WithTransactionId(Guid.NewGuid().ToString())
        .WithReference("Payment")
        .ExecuteAsync();
    
    Console.WriteLine($"Transaction ID: {disbursementResponse.Data.TransactionId}");
}

Benefits of Using the Enum

  1. Type Safety: Compile-time checking prevents invalid institution codes
  2. IntelliSense Support: Auto-completion in your IDE
  3. Self-Documenting: Clear institution names instead of magic strings
  4. Refactoring Friendly: Easy to find and update all usages
  5. Discoverability: See all available institutions in one place

Getting the Code String

The enum provides an extension method GetCodeString() to convert the enum value to the API-required string format. However, you typically don't need to call this manually - the WithInstitutionCode() method accepts the enum directly and handles the conversion internally:

// Recommended: Use the enum directly 
.WithInstitutionCode(InstitutionCode.Mtn)

// If you need the string value for other purposes:
string mtnCode = InstitutionCode.Mtn.GetCodeString();           // "300591"
string ecobankCode = InstitutionCode.EcobankGhanaLtd.GetCodeString(); // "300312"

All Available Institutions

The InstitutionCode enum includes 60+ institutions covering:

  • Banks: All major banks in Ghana (Standard Chartered, ABSA, GCB, Ecobank, etc.)
  • Mobile Money: MTN, AirtelTigo, Telecel, G-Money, and more
  • Payment Providers: ETRANZACT, JUNIPAY, HUBTEL, PAYSWITCH, and many others

For the complete list, explore the InstitutionCode enum in your IDE or refer to the official API documentation.

⚠ Error Handling

The SDK provides three main exception types:

Exception Hierarchy

Liberte360PayException (Base)
├── ValidationException (Request validation errors)
└── ApiException (API communication errors)

ValidationException

Thrown when request parameters fail validation before sending to the API.

try
{
    var response = await client.Disbursement()
        .WithAmount(-10) // Invalid amount
        .ExecuteAsync();
}
catch (ValidationException ex)
{
    Console.WriteLine($"Validation Error: {ex.Message}");
    Console.WriteLine($"Parameter: {ex.ParameterName}");
    // Output: "Amount must be greater than 0"
}

ApiException

Thrown when the API returns an error response or communication fails.

try
{
    var response = await client.NameVerify()
        .WithAccountNumber("233XXXXXXXXX")
        .WithInstitutionCode(InstitutionCode.Mtn)
        .ExecuteAsync();
}
catch (ApiException ex)
{
    Console.WriteLine($"API Error: {ex.Message}");
    Console.WriteLine($"HTTP Status: {ex.StatusCode}");
    Console.WriteLine($"Response Code: {ex.ResponseCode}");
    Console.WriteLine($"Content: {ex.ResponseContent}");
}

Comprehensive Error Handling

try
{
    var response = await client.Disbursement()
        .WithAccountName("John Doe")
        .WithAccountNumber("233XXXXXXXXX")
        .WithAmount(100.00m)
        .WithInstitutionCode(InstitutionCode.Mtn)
        .WithTransactionId(Guid.NewGuid().ToString())
        .ExecuteAsync();

    // Check response status
    if (!response.IsSuccess)
    {
        Console.WriteLine($"Transaction failed: {response.Message}");
        Console.WriteLine($"Code: {response.Code}");
    }
}
catch (ValidationException ex)
{
    // Handle validation errors
    Console.WriteLine($" Validation Error: {ex.Message} ({ex.ParameterName})");
}
catch (ApiException ex)
{
    // Handle API errors
    Console.WriteLine($" API Error: {ex.Message}");
    
    // Map response codes to actions
    switch (ex.ResponseCode)
    {
        case "401":
        case "407":
            Console.WriteLine("Authentication failed. Check your API key.");
            break;
        case "404":
            Console.WriteLine("Account not found.");
            break;
        case "410":
            Console.WriteLine("Insufficient funds.");
            break;
        case "422":
            Console.WriteLine("Request not processable. Check your data.");
            break;
        default:
            Console.WriteLine($"Error code: {ex.ResponseCode}");
            break;
    }
}
catch (Liberte360PayException ex)
{
    // Handle other SDK errors
    Console.WriteLine($"SDK Error: {ex.Message}");
}
catch (Exception ex)
{
    // Handle unexpected errors
    Console.WriteLine($"Unexpected Error: {ex.Message}");
}

Common Response Codes

Code Description Action
200 Success Success
202 Request is being processed Processing
401/407 Unauthorized Check API key
404 Account not found Verify account number
410 Insufficient funds Retry later
419 Pending completion Pending
422 Not processable Check request data
491 Pending authorization User needs to authorize on phone
500 System error Retry later

🔧 Advanced Configuration

Custom Timeout

builder.Services.AddLiberte360Pay(options =>
{
    options.ApiKey = "your-api-key";
    options.TimeoutSeconds = 60; // 60 seconds timeout
});

Production Environment

var options = new Liberte360PayOptions
{
    ApiKey = "your-production-api-key",
    BaseUrl = "https://360pay-merchant-api.libertepay.com", // Production URL
    DefaultCurrency = "GHS"
};

Metrics Collection

The SDK supports collecting performance and usage metrics for API calls. Metrics are disabled by default and stored in-memory.

Basic Usage
using Liberte360Pay.Metrics;

builder.Services.AddLiberte360Pay(options =>
{
    options.ApiKey = "your-api-key";
    
    // Enable metrics collection
    options.Metrics = new MetricsOptions
    {
        EnableMetrics = true
    };
});

// Access metrics
var metricsCollector = serviceProvider.GetRequiredService<IMetricsCollector>();
var metrics = metricsCollector.GetMetrics();

foreach (var kvp in metrics)
{
    Console.WriteLine($"Endpoint: {kvp.Key}");
    Console.WriteLine($"  Total Calls: {kvp.Value.TotalCalls}");
    Console.WriteLine($"  Successful: {kvp.Value.SuccessfulCalls} | Failed: {kvp.Value.FailedCalls}");
    
    if (kvp.Value.TotalCalls > 0)
    {
        var successRate = (double)kvp.Value.SuccessfulCalls / kvp.Value.TotalCalls * 100;
        Console.WriteLine($"  Success Rate: {successRate:F2}%");
        Console.WriteLine($"  Average Duration: {kvp.Value.AverageDurationMs:F2}ms");
        Console.WriteLine($"  Avg Request Size: {kvp.Value.AverageRequestSize:N0} bytes");
        Console.WriteLine($"  Avg Response Size: {kvp.Value.AverageResponseSize:N0} bytes");
    }
    
    if (kvp.Value.ErrorCount > 0)
    {
        Console.WriteLine($"  Errors: {kvp.Value.ErrorCount}");
        Console.WriteLine($"  Error Codes: {string.Join(", ", kvp.Value.ErrorCodes)}");
    }
}
Persisting Metrics

Metrics are stored in-memory by default. To persist them, read the metrics and save them yourself:

// Example: Save metrics to file periodically
var metricsCollector = serviceProvider.GetRequiredService<IMetricsCollector>();

// In a background service or timer
var metrics = metricsCollector.GetMetrics();
var json = JsonSerializer.Serialize(metrics, new JsonSerializerOptions { WriteIndented = true });
await File.WriteAllTextAsync("metrics.json", json);
Available Metrics

The ApiCallMetrics class provides:

  • TotalCalls: Total number of API calls
  • SuccessfulCalls: Number of successful calls
  • FailedCalls: Number of failed calls
  • TotalDurationMs: Total duration in milliseconds
  • AverageDurationMs: Average call duration (computed property)
  • TotalRequestSize / TotalResponseSize: Total payload sizes
  • AverageRequestSize / AverageResponseSize: Average payload sizes (computed properties)
  • ErrorCount: Total error count
  • ErrorCodes: Set of error codes encountered
Accessing Metrics in Your Application
using Liberte360Pay.Metrics;

[ApiController]
[Route("api/[controller]")]
public class MetricsController : ControllerBase
{
    private readonly IMetricsCollector _metricsCollector;

    public MetricsController(IMetricsCollector metricsCollector)
    {
        _metricsCollector = metricsCollector;
    }

    [HttpGet("api-metrics")]
    public IActionResult GetApiMetrics()
    {
        var metrics = _metricsCollector.GetMetrics();
        
        var summary = metrics.Select(kvp => new
        {
            Endpoint = kvp.Key,
            TotalCalls = kvp.Value.TotalCalls,
            SuccessRate = kvp.Value.TotalCalls > 0 
                ? (double)kvp.Value.SuccessfulCalls / kvp.Value.TotalCalls * 100 
                : 0,
            AverageDurationMs = kvp.Value.AverageDurationMs,
            AverageRequestSize = kvp.Value.AverageRequestSize,
            AverageResponseSize = kvp.Value.AverageResponseSize,
            ErrorCount = kvp.Value.ErrorCount,
            ErrorCodes = kvp.Value.ErrorCodes.ToArray()
        });

        return Ok(summary);
    }
}

Note: If metrics are disabled, GetMetrics() returns an empty dictionary. Always check if metrics are enabled before accessing them.

Using Cancellation Tokens

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));

try
{
    var response = await client.Disbursement()
        .WithAccountName("John Doe")
        .WithAccountNumber("233XXXXXXXXX")
        .WithAmount(100.00m)
        .WithInstitutionCode(InstitutionCode.Mtn)
        .WithTransactionId(Guid.NewGuid().ToString())
        .ExecuteAsync(cts.Token);
}
catch (OperationCanceledException)
{
    Console.WriteLine("Request was cancelled or timed out");
}

📝 Best Practices

  1. Always Verify Before Disbursement: Call NameVerify() before making any disbursement to validate the account and get the correct account name.

  2. Use Unique Transaction IDs: Generate unique transaction IDs (e.g., using GUIDs or timestamp-based IDs) to avoid duplicate transactions.

  3. Handle Async Operations: The API endpoints are asynchronous, especially disbursements. Implement proper status checking for pending transactions.

  4. Error Handling: Always wrap API calls in try-catch blocks and handle specific exception types.

  5. Use Dependency Injection: In ASP.NET Core applications, use the AddLiberte360Pay() extension for proper lifecycle management.

  6. Secure API Keys: Never hardcode API keys. Use configuration files, environment variables, or Azure Key Vault.

  7. Timeout Configuration: Set appropriate timeouts based on your use case. Network operations in Ghana may require longer timeouts.

  8. Metadata Usage: Use metadata to store additional transaction information for reconciliation and auditing.

🌍 Environments

UAT (Testing)

  • Base URL: https://uat-360pay-merchant-api.libertepay.com
  • Portal: https://uat-360pay-merchant-portal.libertepay.com

Production

  • Base URL: https://360pay-merchant-api.libertepay.com
  • Portal: https://360pay-merchant-portal.libertepay.com

📄 License

This project is licensed under the MIT License.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📞 Support

For API-related issues and questions:

For SDK issues:

  • Open an issue on GitHub
  • Check the documentation

🎯 Roadmap

Phase 1 (Current):

  • ✅ Name Verification
  • ✅ Disbursement
  • ✅ Fluent API Design
  • ✅ Dependency Injection Support

Phase 2 (Completed):

  • ✅ Collections API
  • ✅ Bulk Disbursement
  • ✅ Bulk Name Verify
  • ✅ Bulk Disbursement Status Check
  • ✅ Transaction Status Check
  • ✅ Transaction Status Check By Reference
  • ✅ Disbursement Balance Check
  • ✅ Checkout Initialize

Made with ❤️ for the .NET community

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.2.0 138 1/20/2026
1.1.9 489 12/17/2025
1.1.8 263 12/15/2025
1.1.7 158 12/14/2025
1.1.6 150 12/14/2025
1.1.5 150 12/14/2025
1.1.4 174 12/13/2025
1.1.3 210 12/12/2025 1.1.3 is deprecated because it has critical bugs.
1.1.2 167 12/11/2025 1.1.2 is deprecated because it has critical bugs.
1.1.1 474 12/11/2025 1.1.1 is deprecated because it has critical bugs.
1.0.0 767 12/10/2025 1.0.0 is deprecated because it has critical bugs.

Initial release with Name Verify and Disbursement endpoints