Guides

Sample Code

webhook

For the .NET source code click here.

<?php /* ------------------------ WEBHOOK Endpoint -------------------------------- */ //Required headers header("Access-Control-Allow-Origin: *"); header("Content-Type: application/json; charset=UTF-8"); header("Access-Control-Allow-Methods: POST"); header("Access-Control-Max-Age: 3600"); header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"); //get MyFatoorah-Signature from request headers $request_headers = apache_request_headers(); $MyFatoorah_Signature = $request_headers['MyFatoorah-Signature']; //Webhook secret //You can get Webhook Secret Key as described in https://myfatoorah.readme.io/docs/webhook-information $secret = 'copy here the Webhook Secret Key generated in MyFatoorah vendor account'; //Get webhook body content $body = (file_get_contents("php://input")); $data = json_decode($body, true); //Log data to check the result error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - ' . $body, 3, './webhook.log'); //Validate the signature validateSignature($data, $secret, $MyFatoorah_Signature); //Call $data['Event'] function if (empty($data['Event'])) { exit(); } $data['Event']($data['Data']); /* ------------------------ Functions --------------------------------------- */ /* * validateSignature function */ function validateSignature($body, $secret, $MyFatoorah_Signature) { if ($body['Event'] == 'RefundStatusChanged') { unset($body['Data']['GatewayReference']); } if ($body['Event'] == 'SupplierStatusChanged') { unset($body['Data']['KycFeedback']); } $data = $body['Data']; //1- Order all data properties in alphabetic and case insensitive. uksort($data, 'strcasecmp'); //2- Create one string from the data after ordering it to be like that key=value,key2=value2 ... $orderedData = implode(',', array_map(function ($v, $k) { return sprintf("%s=%s", $k, $v); }, $data, array_keys($data) )); //4- Encrypt the string using HMAC SHA-256 with the secret key from the portal in binary mode. //Generate hash string $result = hash_hmac('sha256', $orderedData, $secret, true); //5- Encode the result from the previous point with base64. $hash = base64_encode($result); error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - Generated Signature - ' . $hash, 3, './webhook.log'); error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - MyFatoorah-Signature - ' . $MyFatoorah_Signature, 3, './webhook.log'); //6- Compare the signature header with the encrypted hash string. If they are equal, then the request is valid and from the MyFatoorah side. if ($MyFatoorah_Signature === $hash) { error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - Signature is valid ', 3, './webhook.log'); return true; } else { error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - Signature is not valid ', 3, './webhook.log'); exit; } } //------------------------------------------------------------------------------ /* * TransactionsStatusChanged function */ function TransactionsStatusChanged($data) { error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - Inside ' . __FUNCTION__ . ' function', 3, './webhook.log'); error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - Transaction Status is ' . $data['TransactionStatus'], 3, './webhook.log'); error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - You should update order status with Transactions Status Changed webhook output ', 3, './webhook.log'); } //------------------------------------------------------------------------------ /* * RefundStatusChanged function */ function RefundStatusChanged($data) { error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - Inside ' . __FUNCTION__ . ' function', 3, './webhook.log'); error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - You should update order with Refund Status Changed webhook output ', 3, './webhook.log'); } //------------------------------------------------------------------------------ /* * RecurringStatusChanged function */ function RecurringStatusChanged($data) { error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - Inside ' . __FUNCTION__ . ' function', 3, './webhook.log'); error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - You should update order with Recurring Status Changed webhook output ', 3, './webhook.log'); } //------------------------------------------------------------------------------ /* * BalanceTransferred function */ function BalanceTransferred($data) { error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - Inside ' . __FUNCTION__ . ' function', 3, './webhook.log'); error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - You should update your system with Balance Transferred webhook output ', 3, './webhook.log'); } //------------------------------------------------------------------------------ /* * SupplierStatusChanged function */ function SupplierStatusChanged($data) { error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - Inside ' . __FUNCTION__ . ' function', 3, './webhook.log'); error_log(PHP_EOL . date('d.m.Y h:i:s') . ' - You should update your system with Supplier Status Changed webhook output ', 3, './webhook.log'); } /* -------------------------------------------------------------------------- */
using System.Web.Http; using System.Web; using System.IO; using Newtonsoft.Json; using MF.Models.DTO.Webhook; using System; using System.Linq; using MF.Core.Enums; using System.Collections.Generic; namespace MF.Api.Controllers { public class WebhookController : BaseApiController { [HttpPost] [Route("Webhook/Index")] public IHttpActionResult Index() { try { var json = new StreamReader(HttpContext.Current.Request.InputStream).ReadToEndAsync().Result; var signatureHeader = HttpContext.Current.Request.Headers["MyFatoorah-Signature"]; string secretKey = "", headerSignature = ""; bool isValidSignature = true; if (signatureHeader != null) //Check If Enabled Secret Key and If The header has request { isValidSignature = false; headerSignature = signatureHeader.ToString(); secretKey = "/Xp+v8r2dDmNlOTgFyuSRoASudhBm04AzJ6891UWz4k="; //From Your Portal. } var model = JsonConvert.DeserializeObject<GenericWebhookModel<object>>(json); switch (model.EventType) { case WebhookEvents.TrnasactionsStatusChanged: var transactionModel = JsonConvert.DeserializeObject<GenericWebhookModel<WebhookTransactionStatus>>(json); if (!isValidSignature) { isValidSignature = CheckMyFatoorahSignature(transactionModel, secretKey, headerSignature); if (!isValidSignature) return BadRequest("Invalid Signature"); } //Do Some Work break; case WebhookEvents.RefundStatusChanged: var refundModel = JsonConvert.DeserializeObject<GenericWebhookModel<WebhookRefund>>(json); if (!isValidSignature) { isValidSignature = CheckMyFatoorahSignature(refundModel, secretKey, headerSignature); if (!isValidSignature) return BadRequest("Invalid Signature"); } //Do Some Work break; case WebhookEvents.BalanceTransferred: var depositModel = JsonConvert.DeserializeObject<GenericWebhookModel<WebhookDeposit>>(json); if (!isValidSignature) { isValidSignature = CheckMyFatoorahSignature(depositModel, secretKey, headerSignature); if (!isValidSignature) return BadRequest("Invalid Signature"); } //Do Some Work break; case WebhookEvents.SupplierStatusChanged: var supplierModel = JsonConvert.DeserializeObject<GenericWebhookModel<WebhookSupplierStatus>>(json); if (!isValidSignature) { isValidSignature = CheckMyFatoorahSignature(supplierModel, secretKey, headerSignature); if (!isValidSignature) return BadRequest("Invalid Signature"); } //Do Some Work break; } return Ok(); } catch (Exception e) { return BadRequest(e.Message); } } public bool CheckMyFatoorahSignature<T>(GenericWebhookModel<T> model, string secretKey, string headerSignature) { //***Generate The Signature*** : //1- Order all properties alphabetic //2-Encrypt the data with the secret key //3-Compare the signature var properties = typeof(T).GetProperties().Select(p => p.Name).OrderBy(p => p).ToList(); var type = model.Data.GetType(); var parameters = new List<ItemTxt>(); for (int i = 0; i < properties.Count; i++) { var value = type.GetProperty(properties[i]).GetValue(model.Data); value = value == null ? "" : value.ToString(); parameters.Add(new ItemTxt { Text = properties[i], Value = value.ToString() }); } var signature = Sign(parameters, secretKey); return signature == headerSignature; } private static string Sign(List<ItemTxt> paramsArray, string secretKey) { var dataToSign = paramsArray.Select(p => p.Text + "=" + p.Value).ToList(); var data = string.Join(",", dataToSign); var encoding = new UTF8Encoding(); var keyByte = encoding.GetBytes(secretKey); var hmacsha256 = new HMACSHA256(keyByte); var messageBytes = encoding.GetBytes(data); return Convert.ToBase64String(hmacsha256.ComputeHash(messageBytes)); } } public class ItemTxt { public string Value { get; set; } public string Text { get; set; } } }
function validateSignature(bodyString, secret, myFatoorahSignature) { var json = JSON.parse(bodyString); if (json['Event'] === 'RefundStatusChanged') { delete json['Data']['GatewayReference']; } var unOrderedArray = json['Data']; //1- Order all data properties in alphabetic and case insensitive. const orderedArray = Object.keys(unOrderedArray).sort((a, b) => a.localeCompare(b)); //2- Create one string from the data after ordering its key to be like that key=value,key2=value2 ... let orderedString = ""; orderedArray.forEach(key => { unOrderedArray[key] = (unOrderedArray[key]) ? unOrderedArray[key] : ''; orderedString += `${key}=${unOrderedArray[key]},`; }); orderedString = orderedString.slice(0, -1); //4- Encrypt the string using HMAC SHA-256 with the secret key from the portal in binary mode. const crypto = require('crypto'); let result = crypto.createHmac("sha256", secret).update(orderedString).digest(); //5- Encode the result from the previous point with base64. let hash = result.toString('base64'); //6- Compare the signature header with the encrypted hash string. If they are equal, then the request is valid and from the MyFatoorah side. console.log('hash = ' + hash); console.log('MyFatoorah_Signature = ' + myFatoorahSignature); if(hash === myFatoorahSignature){ console.log('valid'); }else{ console.log('error'); } }
import hashlib, base64, hmac # Validate webhood signature function. def validate_signature(response, secret, MyFatoorah_Signature): # removing "GatewayReference" from the data string bodyString = response.json()["Data"] if "GatewayReference" in bodyString.keys(): del bodyString["GatewayReference"] if "KycFeedback" in bodyString.keys(): del bodyString["KycFeedback"] # sorting the string and removing null values required_string = "" for key in sorted(bodyString, key=str.lower): if bodyString[key] in [None, "null"]: bodyString[key] = "" x = "{key}={value},".format(key=key, value=bodyString[key]) required_string = required_string + x required_string = required_string.rstrip(required_string[-1]) print(required_string) # Encode the secret key and ordered data with UTF-8 message_encoded = required_string.encode('utf8') secret_encoded = secret.encode('utf8') #Encrypt the string using HMAC SHA-256 with the secret key from the portal in binary mode. signature = base64.b64encode(hmac.new(secret_encoded, message_encoded, digestmod=hashlib.sha256).digest()) signature = signature.decode('utf8') if signature == MyFatoorah_Signature: result = "Valid" else: result = "Invalid" print(result) return result

Did this page help you?