Handle webhook
All things event
When a payment occurs, Bani sends a webhook event to the webhook URL that you saved on your dashboard.
It is highly recommended that you use webhooks or verify the payment transaction status before delivering value to your customers.
We advise you to verify the response before carrying out any further action.
Please note: if the payout_status value is 'system_closed', kindly wait until the status change to either 'failed' or 'completed' before taking action on your end.
To verify the response, you will have to form the signature and compare your result with the value of 'BANI-HOOK-SIGNATURE' sent to you. The signature is a combination of your merchant_private_key
and request payload.
import hmac
import hashlib
import six
my_hook_signature = hmac.new(six.b(merchant_private_key), msg=str(request_payload).encode('utf-8'), digestmod=hashlib.sha256).hexdigest()
if not hmac.compare_digest(my_hook_signature, bani-hook-signature):
content = {"message":"Invalid signature"}
return JsonResponse(content, status=400)
app.post("/webhook", (req, res) => {
const merchant_private_key = "privatekey";
const headers = req.headers;
const body = req.rawBody;
const sig = Buffer.from(headers["bani-hook-signature"] || "", "utf8");
//Calculate HMAC
const hmac = crypto.createHmac("sha256", merchant_private_key);
const digest = Buffer.from(hmac.update(body).digest("hex"), "utf8");
if (sig.length !== digest.length || !crypto.timingSafeEqual(digest, sig)) {
return false;
} else {
return true;
}
});
$requestBody = 'request_payload';
$secret = 'merchant_private_key';
$signature = hash_hmac('sha256', $requestBody, $secret);
echo $signature;
using System;
using System.Security.Cryptography;
using System.Text;
class Program
{
static void Main()
{
string requestBody = "request_payload";
string merchantPrivateKey = "your_merchant_private_key";
string signature = ComputeHmacSha256Signature(requestBody, merchantPrivateKey);
Console.WriteLine(signature);
}
static string ComputeHmacSha256Signature(string data, string secret)
{
byte[] keyBytes = Encoding.UTF8.GetBytes(secret);
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
using (HMACSHA256 hmac = new HMACSHA256(keyBytes))
{
byte[] hashBytes = hmac.ComputeHash(dataBytes);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
}
}
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class Main {
public static void main(String[] args) {
String requestBody = "request_payload";
String secret = "merchant_private_key";
String signature = computeHmacSha256(requestBody, secret);
System.out.println(signature);
}
public static String computeHmacSha256(String data, String secret) {
try {
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
hmacSha256.init(secretKeySpec);
byte[] hash = hmacSha256.doFinal(data.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
return null;
}
}
}
require 'openssl'
require 'digest'
def compute_hmac_sha256(data, secret)
hmac = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), secret, data)
hmac_hex = hmac.unpack1('H*')
hmac_hex
end
request_body = 'request_payload'
secret = 'merchant_private_key'
signature = compute_hmac_sha256(request_body, secret)
puts signature
payin_mobile_money
Payment made via mobile money
payin_bank_transfer
Payment made via bank transfer
payin_ewallet
Payment made via third party wallet
coin_payment_incoming
An incoming crypto payment
coin_payment_received
Payment made via crypto
payout
A successful transfer to a bank account or mobile money wallet has been completed
payout_reversal
A transfer to a bank account or mobile money wallet you attempted has been reversed
payout_crypto
A successful transfer to a crypto wallet has been completed
payout_crypto_reversal
A transfer to a crypto wallet you attempted has been reversed
collection_service_status
This is sent whenever a payment method/provider is active or inactive. It's just a way of giving you heads-up on when to activate or deactivate the payment method/provider
vas_completed
This will be sent after a successful bill payment transaction
vas_failed
This will be sent after a failed bill payment transaction
Find sample request payload below.
{
"event": "payin_mobile_money",
"data": {
"pay_ref": "BNPay-j6bva8xcesc2vrhhh4w1vs51t9xj96",
"pay_ext_ref": "",
"holder_first_name": "Star",
"holder_last_name": "Lord",
"custom_data": {
"me": "userr"
},
"pay_amount": "30.88",
"pay_method": "mobile_money",
"holder_phone": "+254713674757",
"holder_phone_carrier": "safke",
"order_details": null,
"holder_currency": "KES",
"holder_country_code": "KE",
"pay_status": "paid",
"holder_account_number": "",
"pub_date": "2022-04-07T11:32:24.084772Z",
"modified_date": "2022-04-07T11:32:33.166011Z",
"holder_bank_name": "",
"merch_currency": "NGN",
"merch_amount": "150.00"
}
}
{
"event": "payin_bank_transfer",
"data": {
"pay_ref": "BNPay-6je71r6y7yd8x0a6pxpp1b2absx56c",
"pay_ext_ref": "",
"holder_first_name": "Mac",
"holder_last_name": "Keita",
"custom_data": {
"me": "userr"
},
"pay_amount": "150.00",
"pay_method": "bank_transfer",
"holder_phone": null,
"holder_phone_carrier": "",
"order_details": null,
"holder_currency": "NGN",
"holder_country_code": "NG",
"pay_status": "paid",
"holder_account_number": "8180000003",
"pub_date": "2022-04-07T08:27:54.481411Z",
"modified_date": "2022-04-07T08:31:16.452737Z",
"holder_bank_name": "Wema Bank",
"merch_currency": "NGN",
"merch_amount": "150.00"
}
}
{
"event": "payin_ewallet",
"data": {
"pay_ref": "BNPay-ck0rhghzhb8wtaqycmk8b4as2bpdma",
"pay_ext_ref": "",
"holder_first_name": "Rodney",
"holder_last_name": "Jackson-Cole",
"custom_data": {
"me": "userr"
},
"pay_amount": "150.00",
"pay_method": "ewallet",
"holder_phone": "",
"holder_phone_carrier": "",
"order_details": null,
"holder_currency": "NGN",
"holder_country_code": "NG",
"pay_status": "paid",
"holder_account_number": "",
"pub_date": "2022-04-06T23:10:13.719380Z",
"modified_date": "2022-04-06T23:12:01.638946Z",
"holder_bank_name": "",
"merch_currency": "NGN",
"merch_amount": "150.00"
}
}
{
"event": "collection_service_status",
"data": {
"pay_method": "Bank Transfer",
"pay_provider_name": "Ocean Bank",
"pay_method_status": "active",
"pay_currency": "NGN",
"pay_keyword":["ocean", "000017"],
"pay_country": [
"NG"
]
}
}
{
"event": "payout",
"data": {
"transaction_note": "Remittance to 0066492583|John Scodo",
"fiat_amount": "10.00",
"coin_amount": "0.000000000000000000",
"transaction_reference": "f6gktkjykamr40mtq13cc76qx",
"pub_date": "2022-10-23T10:59:48.586327Z",
"modified_date": "2022-10-23T10:59:48.588187Z",
"is_done": true,
"payout_details": {
"payout_method": "Bank Transfer",
"receiver_amount": "10.00",
"receiver_phone": "",
"receiver_sort_code": "000005",
"payout_status": "completed",
"payout_ref": "WMPRM_jeebzavhj3",
"payout_ext_ref": "WEMBA-1013",
"payout_receiver_type": "personal",
"receiver_account_name": "John Scodo",
"receiver_account_num": "0000010101",
"receiver_account_type": "",
"receiver_address": "",
"receiver_bank_name": "GRANT BANK",
"receiver_city": "",
"receiver_currency": "NGN",
"receiver_personal_num": "",
"receiver_postcode": "",
"receiver_state": "",
"receiver_country_code": "NG",
"receiver_bank_branch": "",
"receiver_first_name": "",
"receiver_last_name": "",
"pub_date": "2022-10-23T10:59:48.582486Z",
"modified_date": "2022-10-23T11:21:49.899924Z",
"is_beneficiary": false
},
"source_account_name": "Nest Cafe"
}
}
{
"event": "payout_reversal",
"data": {
"transaction_note": "Remittance to 0066492583|John Scodo",
"fiat_amount": "10.00",
"coin_amount": "0.000000000000000000",
"transaction_reference": "f6gktkjykamr40mtq13cc76qx",
"pub_date": "2022-10-23T10:59:48.586327Z",
"modified_date": "2022-10-23T10:59:48.588187Z",
"is_done": true,
"payout_details": {
"payout_method": "Bank Transfer",
"receiver_amount": "10.00",
"receiver_phone": "",
"receiver_sort_code": "000005",
"payout_status": "failed",
"payout_ref": "WMPRM_jeebzavhj3",
"payout_ext_ref": "WEMBA-1013",
"payout_receiver_type": "personal",
"receiver_account_name": "John Scodo",
"receiver_account_num": "0000010101",
"receiver_account_type": "",
"receiver_address": "",
"receiver_bank_name": "GRANT BANK",
"receiver_city": "",
"receiver_currency": "NGN",
"receiver_personal_num": "",
"receiver_postcode": "",
"receiver_state": "",
"receiver_country_code": "NG",
"receiver_bank_branch": "",
"receiver_first_name": "",
"receiver_last_name": "",
"pub_date": "2022-10-23T10:59:48.582486Z",
"modified_date": "2022-10-23T11:21:49.899924Z",
"is_beneficiary": false
},
"source_account_name": "Nest Cafe"
}
}
{
"event": "vas_completed",
"data": {
"amount": "3200.00",
"biller_customer_item": "12345678910",
"customer_biller_code": "91 Abodunrin Street 60 313 IfeomaVille",
"customer_biller_name": "Wale Emeka Sylvester",
"vas_type": "Bills Payment",
"customer_phone_number": "+2348053022958",
"currency": "NGN",
"transaction_ext_ref": "",
"customer_phone_network": "",
"transaction_status": "completed",
"main_category": "ELECTRICITY",
"sub_category": "IKEDC",
"biller_extra_info": "60114651373352292125|Units Purchased: 5.1",
"vas_item_name": "",
"transaction_ref": "BV-xaz8h4c8k7bjwmw",
"pub_date": "2023-06-11T20:44:51.648453Z"
}
}
{
"event": "vas_failed",
"data": {
"amount": "100.00",
"biller_customer_item": "",
"customer_biller_code": "",
"customer_biller_name": "",
"vas_type": "Mobile Data",
"customer_phone_number": "+2348053022958",
"currency": "NGN",
"country_code": "NG",
"transaction_ext_ref": "",
"customer_phone_network": "glo",
"transaction_status": "failed",
"main_category": "mobile_data",
"sub_category": "glo",
"biller_extra_info": "",
"vas_item_name": "GLO-150MB-3",
"transaction_ref": "BV-am75yb6zf82z0k8",
"pub_date": "2023-06-11T21:11:26.399568Z"
}
}
Last updated