Introduction
Welcome to the KhusaPay API guide. You can use our API to access KhusaPay API endpoints, which can allow you to perform payment transactions within our eco-system.
We have language bindings in Shell, JAVA , PHP and Elixir for necessary endpoints. You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
Invoicing
Creating invoices is easy. KhusaPay allows you to do this using the available checkout iframe endpoint.
To do this you need an api_client_id, secret and key for generating a secure hash.
These (api_client_id, secret and key) are provided by KhusaPay Team. If you have issues with your credentials contact Our Support Team for assistance.
Secure Hash
<?php
$api_client_id= "my-client-id provided by KhusaPay";
$service_id = "my-client-id provided by KhusaPay";
$id_number = "Customer ID number";
$currency = "MWK";
$client_invoice_ref = "Ab-CD-EF-001";
$desc = "Description of invoice";
$name = "John Doe";
$secret = "my-secret";
$key = "my-key";
data_string = "$api_client_id"."$amount_expected"."$service_id"."$id_number"."$currency"."$client_invoice_ref"."$desc"."$name"."$secret";
secure_hash = base64_encode(hash_hmac('sha256', $data_string, $key));
echo "SecureHash : $secure_hash\n";
?>
generate_secure_hash("my-key",["1","100","124","12345678","MWK","REF-01-2024-XVBC","Some invoice","John Doe","my-secret"])
def generate_secure_hash(secret, hash_list) when is_list(hash_list) do
:crypto.hmac(:sha256, secret, hash_list |> Enum.map(&to_string(&1)))
|> Base.encode16()
|> String.downcase()
|> Base.encode64()
end
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.lang.*;
import java.io.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HttpsURLConnection;
public class Main {
private final String USER_AGENT = "Mozilla/5.0";
public static void main(String[] args) throws Exception {
Main m = new Main();
String hash = m.genSig();
System.out.println("\nHash - "+ hash);
}
// HTTP POST request
private String genSig() {
/**
* Validate Payment
* This endpoint validates a invoices or topups exist before payment is accepted.
* To generate your secure hash, use format below,
*
*/
String provided_hmac_secret = "your-key";
String api_client_id= "your-api-client-id";
String data_string = "[YOUR-DATA-STRING]";
return generate_signature(data_string, provided_hmac_secret);
}
static String generate_signature(String data_string, String secret){
try{
SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(),"HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(keySpec);
byte[] result = mac.doFinal(data_string.getBytes());
String encode_result = Base16Encoder.encode(result);
return Base64.getEncoder().encodeToString(encode_result.toLowerCase().getBytes());
} catch (Exception e) {
return "Cannot Process Signature";
}
}
}
class Base16Encoder {
private final static char[] HEX = new char[]{
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
/**
* Convert bytes to a base16 string.
*/
public static String encode(byte[] byteArray) {
StringBuffer hexBuffer = new StringBuffer(byteArray.length * 2);
for (int i = 0; i < byteArray.length; i++)
for (int j = 1; j >= 0; j--)
hexBuffer.append(HEX[(byteArray[i] >> (j * 4)) & 0xF]);
return hexBuffer.toString();
}
/**
* Convert a base16 string into a byte array.
*/
public static byte[] decode(String s) {
int len = s.length();
byte[] r = new byte[len / 2];
for (int i = 0; i < r.length; i++) {
int digit1 = s.charAt(i * 2), digit2 = s.charAt(i * 2 + 1);
if (digit1 >= '0' && digit1 <= '9')
digit1 -= '0';
else if (digit1 >= 'A' && digit1 <= 'F')
digit1 -= 'A' - 10;
if (digit2 >= '0' && digit2 <= '9')
digit2 -= '0';
else if (digit2 >= 'A' && digit2 <= 'F')
digit2 -= 'A' - 10;
r[i] = (byte) ((digit1 << 4) + digit2);
}
return r;
}
}
using System;
using System.Security.Cryptography;
using System.Text;
public class HelloWorld {
public static void Main(string[] args) {
var key = "[YOUR-KEY]";
var data_string = "[YOUR-DATA-STRING]";
byte[] res = hmacSHA256(data_string, key);
var enc = BitConverter.ToString(res).Replace("-", "").ToLower();
Console.WriteLine(Base64Encode(enc));
}
static byte[] hmacSHA256(String data, String key) {
using (HMACSHA256 hmac = new HMACSHA256(Encoding.ASCII.GetBytes(key)))
{
return hmac.ComputeHash(Encoding.ASCII.GetBytes(data));
}
}
public static string Base64Encode(string plainText) {
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
}
This segment explains or demonstrates how to generate a secure hash. To generate your secure hash for checkout purpose, the below fields are required:-
Expected Parameters
| Parameter | Mandatory | Description |
|---|---|---|
| apiClientID | Yes | Provided by KhusaPay |
| amountExpected | Yes | Amount to be paid |
| serviceID | Yes | Service ID Provided by KhusaPay |
| clientIDNumber | Yes | Customers ID Number |
| currency | Yes | Bill currency |
| billRefNumber | Yes | Unique client reference |
| billDesc | Yes | Description of bill |
| clientName | Yes | Customers Name |
| secret | Yes | Unique client secret provided by KhusaPay |
The above command returns a base64 encoded hash
Checkout
curl -H "Authorization: Bearer <TOKEN>" \
-d '<see sample payload in `php` or `elixir` tab >'
-XPOST "https://{UAT_SERVER_URL}/api/PaymentAPI/checkout"
<form method="post" action="https://{UAT_SERVER_URL}/api/PaymentAPI/checkout" target="some_iframe" id="some_form">
<input type="hidden" name="apiClientID" id="apiClientID" value="[apiClientID provided by KhusaPay]">
<input type="hidden" name="serviceID" id="serviceID" value="[serviceID provided by KhusaPay]">
<input type="hidden" name="billDesc" id="billDesc" value="Invoice for service X">
<input type="hidden" name="currency" id="currency" value="MWK">
<input type="hidden" name="billRefNumber" id="billRefNumber" value="Bill-bb9a0495-f586-40b6-b4a7-37f78f7e51a0">
<input type="hidden" name="clientMSISDN" id="clientMSISDN" value="2657XXXYYYZZ">
<input type="hidden" name="clientName" id="clientName" value="John Doe"/>
<input type="hidden" name="clientIDNumber" id="clientIDNumber" value="00"/>
<input type="hidden" name="clientEmail" id="clientEmail" value="some@gmail.com"/>
<input type="hidden" name="callBackURLOnSuccess" id="callBackURLOnSuccess" value="[Your webpage callback URL]"/>
<input type="hidden" name="amountExpected" id="amountExpected" value="1"/>
<input type="hidden" name="notificationURL" id="notificationURL" value="[Your notification URL]"/>
<input type="hidden" name="pictureURL" id="pictureURL" value=""/>
<input type="hidden" name="secureHash" id="secureHash" value="MmEwMWNlNDNkZWFmYTg4MmFkMTE0MWFkMmRjNjliZDU2Mzk4NTViNmRiMjFiMWY2MjRjNzFkMjVjYzdmYmI0MA=="/>
<input type="hidden" name="format" value="html"/>
<input type="hidden" name="sendSTK" value="false"/>
<input type="hidden" value="Submit"/>
</form>
<form method="post" action="https://{UAT_SERVER_URL}/api/PaymentAPI/checkout" target="some_iframe" id="some_form">
<input type="hidden" name="apiClientID" id="apiClientID" value="[apiClientID provided by KhusaPay]">
<input type="hidden" name="serviceID" id="serviceID" value="[serviceID provided by KhusaPay]">
<input type="hidden" name="billDesc" id="billDesc" value="Invoice for service X">
<input type="hidden" name="currency" id="currency" value="MWK">
<input type="hidden" name="billRefNumber" id="billRefNumber" value="Bill-bb9a0495-f586-40b6-b4a7-37f78f7e51a0">
<input type="hidden" name="clientMSISDN" id="clientMSISDN" value="2657XXXYYYZZ">
<input type="hidden" name="clientName" id="clientName" value="John Doe"/>
<input type="hidden" name="clientIDNumber" id="clientIDNumber" value="00"/>
<input type="hidden" name="clientEmail" id="clientEmail" value="some@gmail.com"/>
<input type="hidden" name="callBackURLOnSuccess" id="callBackURLOnSuccess" value="[Your webpage callback URL]"/>
<input type="hidden" name="amountExpected" id="amountExpected" value="1"/>
<input type="hidden" name="notificationURL" id="notificationURL" value="[Your notification URL]"/>
<input type="hidden" name="pictureURL" id="pictureURL" value=""/>
<input type="hidden" name="secureHash" id="secureHash" value="MmEwMWNlNDNkZWFmYTg4MmFkMTE0MWFkMmRjNjliZDU2Mzk4NTViNmRiMjFiMWY2MjRjNzFkMjVjYzdmYmI0MA=="/>
<input type="hidden" name="format" value="html"/>
<input type="hidden" name="sendSTK" value="false"/>
<input type="hidden" value="Submit"/>
</form>
The above will redirect or return a html page that allows your customer to make payment.
This endpoint creates a new invoice for a customer and redirects to the KhusaPay checkout page.
HTTP Request
Post data as form data
POST https://{UAT_SERVER_URL}/api/PaymentAPI/checkout
Expected Parameters
| Parameter | Mandatory | Description |
|---|---|---|
| apiClientID | Yes | Provided by KhusaPay |
| serviceID | Yes | Provided by KhusaPay |
| billRefNumber | Yes | Unique client transaction number |
| billDesc | Yes | Description of the invoice |
| clientMSISDN | Yes | Mobile number of whoever is receiving the invoice or bill |
| clientIDNumber | Yes | Customers ID Number |
| clientName | Yes | Customers Name |
| clientEmail | Yes | Customers Email |
| notificationURL | Yes | Clients endpoint URL to receive invoice updates on payment |
| pictureURL | No | URL of customers image to be displayed on checkout |
| callBackURLOnSuccess | Yes | Callback url to be invoked for redirection to merchant site on successful payment |
| currency | Yes | Currency for the invoice. This is based on the serviceID. |
| amountExpected | Yes | Invoice amount |
| format | No | Default format is 'html'. If you want to store the invoice number set this to 'json' |
| sendSTK | No | If you want the customer to receive Mobile Money STK set this to 'true' |
| secureHash | Yes | Hash generated to ensure validity of invoice |
Payments
This segment applies to Payment Aggregators and Banks and describes the API available on KhusaPay, to receive and process payment instructions for invoices paid at the aggregator or bank.
Validate Payment
curl -H "Content-Type: application/json" \
-XPOST -d '<see sample payload in `php` or `elixir` tab >' \
"https://{UAT_SERVER_URL}/api/payment/validate"
<?php
//Sample hash-generation
$secret="some-secret";
$key="some-key";
$api_client_id="your-id";
$invoice_number="invoice-number";
$amount="some-amount";
$data_string = $api_client_id.$invoice_number.$amount.$secret;
echo "\nDataString: $data_string\n";
$hash = base64_encode(hash_hmac('sha256', $data_string, $key));
echo "\n $hash \n"
?>
<?php
$url = 'https://{UAT_SERVER_URL}/api/payment/validate';
$api_client_id = "";
$invoice_no = "";
$amount = "";
$currency="";
$secret="";
$key="";
$data = array(
"api_client_id"=> $api_client_id,
"ref_no"=> $invoice_no,
"currency"=> $currency,
"amount"=> $amount,
"secure_hash"=> base64_encode(hash_hmac('sha256', $api_client_id.$invoice_number.$amount.$secret, $key));,
);
$payload = json_encode($data);
$headers = ["Content-Type","application/json"];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$curl_response = curl_exec($curl);
echo $curl_response;
?>
url = 'https://{UAT_SERVER_URL}/api/payment/validate'
payload = %{
"api_client_id": "",
"ref_no": "",
"currency": "",
"amount": "",
"secure_hash": "",
}
{:ok, %HTTPoison.Response{body: body}} = HTTPoison.post(url, payload, %{
"Content-type" => "application/json;charset=UTF-8"})
{:ok, body}
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.lang.*;
import java.io.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HttpsURLConnection;
public class Main {
private final String USER_AGENT = "Mozilla/5.0";
public static void main(String[] args) throws Exception {
Main m = new Main();
String hash = m.genSig();
System.out.println("\nHash - "+ hash);
}
// HTTP POST request
private String genSig() {
/**
* Validate Payment
* This endpoint validates a invoices or topups exist before payment is accepted.
* To generate your secure hash, use format below,
* data_string = "$api_client_id"."$ref_no"."$amount"."$secret"
*
*/
String provided_hmac_secret = "your-key"; //
String api_client_id= "your-api-client-id";
String invoice_no = "";
String amount = "";
String secret = "your-secret";
String data_string = api_client_id + invoice_no + amount + secret;
return generate_signature(data_string, provided_hmac_secret);
}
static String generate_signature(String data_string, String secret){
try{
SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(),"HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(keySpec);
byte[] result = mac.doFinal(data_string.getBytes());
String encode_result = Base16Encoder.encode(result);
return Base64.getEncoder().encodeToString(encode_result.toLowerCase().getBytes());
} catch (Exception e) {
return "Cannot Process Signature";
}
}
}
class Base16Encoder {
private final static char[] HEX = new char[]{
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
/**
* Convert bytes to a base16 string.
*/
public static String encode(byte[] byteArray) {
StringBuffer hexBuffer = new StringBuffer(byteArray.length * 2);
for (int i = 0; i < byteArray.length; i++)
for (int j = 1; j >= 0; j--)
hexBuffer.append(HEX[(byteArray[i] >> (j * 4)) & 0xF]);
return hexBuffer.toString();
}
/**
* Convert a base16 string into a byte array.
*/
public static byte[] decode(String s) {
int len = s.length();
byte[] r = new byte[len / 2];
for (int i = 0; i < r.length; i++) {
int digit1 = s.charAt(i * 2), digit2 = s.charAt(i * 2 + 1);
if (digit1 >= '0' && digit1 <= '9')
digit1 -= '0';
else if (digit1 >= 'A' && digit1 <= 'F')
digit1 -= 'A' - 10;
if (digit2 >= '0' && digit2 <= '9')
digit2 -= '0';
else if (digit2 >= 'A' && digit2 <= 'F')
digit2 -= 'A' - 10;
r[i] = (byte) ((digit1 << 4) + digit2);
}
return r;
}
}
The above command returns JSON structured like this:
{
"status": 200,
"description": "Bill Found",
"data": {
"amount": "xxx",
"name": "xxx",
"currency": "xxx"
}
}
{
"status": 404,
"description": "Bill not found",
}
{
"status": 500,
"description": "Internal Error or any other failure error",
}
This endpoint checks the validity of an invoice before payment is accepted.
To generate your secure hash, use fields below:-
Expected Parameters
| Parameter | Mandatory | Description |
|---|---|---|
| api_client_id | Yes | Provided by KhusaPay |
| ref_no | Yes | Invoice Reference |
| amount | Yes | Amount paid |
| secret | Yes | Unique client secret provided by KhusaPay |
HTTP Request
POST https://{UAT_SERVER_URL}/api/payment/validate
Expected Parameters
| Parameter | Mandatory | Description |
|---|---|---|
| api_client_id | Yes | The provided client ID. |
| ref_no | Yes | Unique invoice/topup reference code from KhusaPay. |
| currency | Yes | Currency associated |
| amount | Yes | Amount of the bill. |
| secure_hash | Yes | A sha256 encoded hash. |
Confirm Payment
curl -H "Content-Type: application/json"\
-XPOST -d '<see sample payload in `php` or `elixir` tab >'\
"https://{UAT_SERVER_URL}/api/payment/confirm"
<?php
$url = 'https://{UAT_SERVER_URL}/api/payment/confirm';
$key = "";
$secret = "";
$api_client_id = "";
$invoice_no = "";
$amount = "";
$currency="";
$gateway_transaction_id = "";
$gateway_transaction_date = date("Y-m-d H:i:s");
$customer_name = "John Doe";
$customer_account_number = "";
$data = array(
"api_client_id"=> $api_client_id,
"ref_no"=> $invoice_no,
"amount"=> $amount,
"currency"=> $currency,
"gateway_transaction_id"=> $gateway_transaction_id,
"gateway_transaction_date"=> $gateway_transaction_date,
"customer_name"=> $customer_name,
"customer_account_number"=> $customer_account_number,
"secure_hash"=> base64_encode(hash_hmac('sha256',$api_client_id . $invoice_no . $amount . $currency . $gateway_transaction_id . $gateway_transaction_date . $customer_name . $customer_account_number . $secret, $key))
);
$headers = ["Content-Type","application/json"];
$payload = json_encode($data);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$curl_response = curl_exec($curl);
echo $curl_response;
?>
url = 'https://{UAT_SERVER_URL}/api/payment/confirm'
payload = %{
"api_client_id": "",
"ref_no": "",
"amount": "",
"currency": "",
"gateway_transaction_id": "",
"gateway_transaction_date": "",
"customer_name": "",
"customer_account_number": "",
"secure_hash": "",
}
{:ok, %HTTPoison.Response{body: body}} = HTTPoison.post(url, payload, %{
"Content-type" => "application/json;charset=UTF-8"})
{:ok, body}
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.lang.*;
import java.io.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HttpsURLConnection;
public class Main {
private final String USER_AGENT = "Mozilla/5.0";
public static void main(String[] args) throws Exception {
Main m = new Main();
String hash = m.genSig();
System.out.println("\nHash - "+ hash);
}
// HTTP POST request
private String genSig() {
String provided_hmac_secret = "key"; //
String api_client_id= "1";
String invoice_no = "NWQTYU";
String currency = "SSP";
String amount = "10";
String gateway_transaction_id="1234434";
String gateway_transaction_date="2021-01-26 15:30:01";
String customer_name = "JOHN DOE";
String customer_account_number = "438485959";
String secret = "secret";
String data_string = api_client_id + invoice_no + amount + currency + gateway_transaction_id + gateway_transaction_date + customer_name + customer_account_number + secret;
return generate_signature(data_string, provided_hmac_secret);
}
static String generate_signature(String data_string, String secret){
try{
SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(),"HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(keySpec);
byte[] result = mac.doFinal(data_string.getBytes());
String encode_result = Base16Encoder.encode(result);
return Base64.getEncoder().encodeToString(encode_result.toLowerCase().getBytes());
} catch (Exception e) {
return "Cannot Process Signature";
}
}
}
class Base16Encoder {
private final static char[] HEX = new char[]{
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
/**
* Convert bytes to a base16 string.
*/
public static String encode(byte[] byteArray) {
StringBuffer hexBuffer = new StringBuffer(byteArray.length * 2);
for (int i = 0; i < byteArray.length; i++)
for (int j = 1; j >= 0; j--)
hexBuffer.append(HEX[(byteArray[i] >> (j * 4)) & 0xF]);
return hexBuffer.toString();
}
/**
* Convert a base16 string into a byte array.
*/
public static byte[] decode(String s) {
int len = s.length();
byte[] r = new byte[len / 2];
for (int i = 0; i < r.length; i++) {
int digit1 = s.charAt(i * 2), digit2 = s.charAt(i * 2 + 1);
if (digit1 >= '0' && digit1 <= '9')
digit1 -= '0';
else if (digit1 >= 'A' && digit1 <= 'F')
digit1 -= 'A' - 10;
if (digit2 >= '0' && digit2 <= '9')
digit2 -= '0';
else if (digit2 >= 'A' && digit2 <= 'F')
digit2 -= 'A' - 10;
r[i] = (byte) ((digit1 << 4) + digit2);
}
return r;
}
}
The above command returns JSON structured like this:
{
"status": 200,
"description": "Success",
}
{
"status": 500,
"description": "Failed",
}
This endpoint received and stores the payment tied to a specific invoice.
To generate your secure hash, use fields below:-
Expected Parameters
| Parameter | Mandatory | Description |
|---|---|---|
| api_client_id | Yes | Provided by KhusaPay |
| ref_no | Yes | Invoice Reference |
| amount | Yes | Amount paid |
| currency | Yes | Currency |
| gateway_transaction_id | Yes | Unique gateway transaction ID |
| gateway_transaction_date | Yes | Transaction date, format Y-m-d H:i:s |
| customer_name | Yes | Customers name |
| customer_account_number | Yes | Customers account number e.g phone number |
| secret | Yes | Unique client secret provided by KhusaPay |
HTTP Request
POST https://{UAT_SERVER_URL}/api/payment/confirm
URL Parameters
| Parameter | Mandatory | Description |
|---|---|---|
| api_client_id | Yes | The provided client ID. |
| ref_no | Yes | Unique bill/invoice reference code. |
| amount | Yes | Amount of the bill. |
| currency | Yes | Currency used for payment |
| gateway_transaction_id | Yes | Callers unique transaction reference |
| gateway_transaction_date | Yes | Date and time transaction takes place. Format Y-m-d h:i:s e.g 2019-08-01 08:30:08 |
| customer_name | Yes | Name of customer. |
| customer_account_number | Yes | Associated account identifier for customer e,g id_number or msisdn can be used here |
| secure_hash | Yes | A sha256 encoded hash. |
Instant Payment Notification
POST https://{thirdparty endpoint}
<?php
$json = file_get_contents('php://input');
$data = json_decode($json);
//Sample hash-generation
$secret="some-secret";
$key="some-key";
$client_invoice_ref= $data["client_invoice_ref"];
$invoice_number=$data["invoice_number"];
$amount=$data["amount_paid"];
$payment_date = $data["payment_date"];
$data_string = $client_invoice_ref.$invoice_number.$amount.$payment_date.$secret;
echo "\nDataString: $data_string\n";
$hash = base64_encode(hash_hmac('sha256', $data_string, $key));
echo "\n $hash \n"
?>
key = "my-key"
secret = "my-secret"
hash_list = ["#{client_invoice_ref}", "#{invoice_number}", "#{amount_paid}", "#{payment_date}", "#{secret}"]
def generate_secure_hash(key, hash_list) when is_list(hash_list) do
:crypto.hmac(:sha256, key, hash_list)
|> Base.encode16()
|> String.downcase()
|> Base.encode64()
end
KhusaPay will send a payment notification after SUCCESSFUL processing. You will expect a payload that is structured as below and within this payload, a secure_hash is provided so that third-party systems can be able to verify the legitimacy of the notification. A Sample is below,
{
"payment_channel" : "Some Channel",
"client_invoice_ref" : "SS6489db2e1fdfd",
"payment_reference" : [ {
"payment_reference" : "ABCDEF-925",
"payment_date" : "2023-06-14T15:33:16",
"inserted_at" : "2023-06-14T15:33:16",
"currency" : "MWK",
"amount" : "102.00"
} ],
"currency" : "MWK",
"amount_paid" : "102.00",
"invoice_amount" : "102.00",
"status" : "settled",
"invoice_number" : "ABCDEF",
"payment_date" : "2023-06-14 15:33:16Z",
"last_payment_amount" : "102.00",
"secure_hash": "NTU4NzEzNzhiOTI1N2NlODY3YWYzYjVhYjQ4MzNiNDYzY2M3MzQwYmNlZDc4ZDJlZjg3ZDZkOTQ5ZjUyM2EzNQ==",
}
Please note: Use secure_hash, to check validity of the received notification.
In addition, to generate a matching hash, use/concatenate the following fields in the same order:-
Expected Parameters
| Parameter | Mandatory | Description |
|---|---|---|
| client_invoice_ref | Yes | Clients reference |
| invoice_number | Yes | Invoice Reference |
| amount_paid | Yes | Amount paid |
| payment_date | Yes | Payment Date |
| secret | Yes | Unique client secret provided by KhusaPay |
The above parameters are from the sample IPN payload on to your right side.
Query Payment Status
curl -H "Content-Type: application/json" \
-X GET -d '<see sample payload in `php` or `elixir` tab >' \
"https://{UAT_SERVER_URL}/api/invoice/payment/status?api_client_id=YOUR_CLIENT_ID&ref_no=YOUR_REF_NO&secure_hash=YOUR_HASH"
<?php
$key = "my_key";
$data_string = "my_client_id"."my_ref_no";
$secure_hash = base64_encode(hash_hmac('sha256', $data_string, $key));
$url = 'https://{UAT_SERVER_URL}/invoice/payment/status';
$data = array(
"api_client_id"=>"",
"ref_no"=>"",
"secure_hash"=>"$secure_hash",
);
$payload = json_encode($data);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
$curl_response = curl_exec($curl);
echo $curl_response;
?>
key = "my-key"
api_client_id="my_api_client_id"
ref_no="ref-no"
hash_list = ["#{api_client_id}", "#{ref_no}"]
secure_hah = generate_secure_hash(key, hash_list) # Referenced from the Elixir hash sample
url = 'https://{UAT_SERVER_URL}/invoice/payment/status'
payload = %{
"api_client_id": "",
"ref_no": "",
"secure_hash": ""
}
{:ok, %HTTPoison.Response{body: body}} = HTTPoison.get(url, payload, %{
"Content-type" => "application/json;charset=UTF-8"})
{:ok, body}
The above command returns JSON structured like this(example):
{
"status": "pending",
"ref_no": "WVZGEP",
"name": "Test User",
"currency": "MWK",
"client_invoice_ref": "EPIC-ORDER103",
"payment_date": "2024-01-01 12:30:01",
"amount_paid": "0.00",
"amount_expected": "100.00"
}
Status can be - pending, partial, settled
In the event that push notification is not available, or Network Timeouts, clients can use this endpoint to query the status of bill payments.
This endpoint checks the status of an invoice. To generate your secure hash, use fields below:-
Expected Parameters
| Parameter | Mandatory | Description |
|---|---|---|
| api_client_id | Yes | Provided by KhusaPay |
| ref_no | Yes | Invoice Reference |
| key | Yes | Unique client key provided by KhusaPay |
HTTP Request
GET https://{UAT_SERVER_URL}/api/invoice/payment/status
URL Parameters
| Parameter | Mandatory | Description |
|---|---|---|
| api_client_id | Yes | Provided by KhusaPay |
| ref_no | Yes | Unique invoice number from KhusaPay. |
| secure_hash | Yes | A sha256 encoded hash. |
FAQs
Still unable to integrate, here are the frequently asked questions about the process.
| Issue | Meaning |
|---|---|
| No IPN Response | Check if your IPN endpoint has an error and you are able to connect to it via the internet. |
| Invalid Hash Error | Please review the secure hash section and verify that your data string conforms to the documentation. Confirm that the credentials you are using are valid. |
| 502 Error | Possible maintainance on-going. Wait a few minutes to retry |
Errors
The KhusaPay API uses the following HTTP error codes:
| Error Code | Meaning |
|---|---|
| 200 | Valid Request -- Your request is valid. |
| 400 | Invalid Request -- Your request is invalid. |
| 401 | Unauthorized/Invalid secure hash -- Your API key is wrong. |
| 403 | Forbidden Access |
| 404 | Item not found or does not exist -- The item (e.g) does not exist. |
| 500 | Internal Server Error -- We had a problem with our server. Try again later. |
| 502 | Bad Gateway - Something went wrong. |
| 503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |