This page describes how to encrypt charge requests when calling Rave's direct API's
Rave ensures complete security by using 3DES military grade encryption. When performing a card/account charge
and your request is sent from your server, you will need to use 3DES encryption and our getKey
function to generate an encryption key
.
Using your secret key in your application
Always store your
secret key
in an environment variable, don't expose it in your code, you would most likely commit it, and it would be exposed to the public. You can add it in your code using an environment variable.
Rave encryption is broken down into two parts,
- the
getKey()
function; this helps generate the encryption key to be used by hashing the key (Secret Key) using anmd5
algorithm then picking asubstring
(last 12 digits) of the the hashed key.
On the other end, you would strip the original key of it's prefix (FLWSECK-
), and get the substring (first 12 digits), combine them to make create the encryption key.
- Second part is the encryption function itself, which uses the
3DES
algorithm method. Thedata
object to be passed along with the key is the payment request data in String format. Example is given below.
// this is the getKey function that generates an encryption Key for you by passing your Secret Key as a parameter.
function getKey(seckey){
var md5 = require('md5');
var keymd5 = md5(seckey);
var keymd5last12 = keymd5.substr(-12);
var seckeyadjusted = seckey.replace('FLWSECK-', '');
var seckeyadjustedfirst12 = seckeyadjusted.substr(0, 12);
return seckeyadjustedfirst12 + keymd5last12;
}
// This is the encryption function that encrypts your payload by passing the stringified format and your encryption Key.
function encrypt(key, text)
{
var CryptoJS = require('crypto-js');
var forge = require('node-forge');
var utf8 = require('utf8');
var cipher = forge.cipher.createCipher('3DES-ECB', forge.util.createBuffer(key));
cipher.start({iv:''});
cipher.update(forge.util.createBuffer(text, 'utf-8'));
cipher.finish();
var encrypted = cipher.output;
return ( forge.util.encode64(encrypted.getBytes()) );
}
/**** THIS ENCRYPTION SECTION IS FOR FRONT END ECRYPTION***/
// Encryption can also be done at the front end using `RSA Encryption`:
function getPublicKey(){
// write function to generate Public Key here using RSA Encryption
// see cryptico docs on how to do that.
}
chargeDataGlobal = { "// Enter your payload here" };
var newdata = {PBFPubKey:chargeDataGlobal.PBFPubKey, client:cryptico.encrypt(JSON.stringify(chargeDataGlobal),getPublicKey()).cipher};
<?php
// this is the getKey function that generates an encryption Key for you by passing your Secret Key as a parameter.
function getKey($seckey){
$hashedkey = md5($seckey);
$hashedkeylast12 = substr($hashedkey, -12);
$seckeyadjusted = str_replace("FLWSECK-", "", $seckey);
$seckeyadjustedfirst12 = substr($seckeyadjusted, 0, 12);
$encryptionkey = $seckeyadjustedfirst12.$hashedkeylast12;
return $encryptionkey;
}
function encrypt3Des($data, $key)
{
$encData = openssl_encrypt($data, 'DES-EDE3', $key, OPENSSL_RAW_DATA);
return base64_encode($encData);
}
import base64
from Crypto.Cipher import DES3
import hashlib
"""this is the getKey function that generates an encryption Key for you by passing your Secret Key as a parameter."""
def getKey():
seckey = "FLWSECK-6b32914d4d60c10d0ef72bdad734134a-X"
hashedseckey = hashlib.md5(seckey.encode("utf-8")).hexdigest()
hashedseckeylast12 = hashedseckey[-12:]
seckeyadjusted = seckey.replace('FLWSECK-', '')
seckeyadjustedfirst12 = seckeyadjusted[:12]
return seckeyadjustedfirst12 + hashedseckeylast12
"""This is the encryption function that encrypts your payload by passing the text and your encryption Key."""
def encryptData(key, plainText):
blockSize = 8
padDiff = blockSize - (len(plainText) % blockSize)
cipher = DES3.new(key, DES3.MODE_ECB)
plainText = "{}{}".format(plainText, "".join(chr(padDiff) * padDiff))
encrypted = base64.b64encode(cipher.encrypt(plainText))
return encrypted
require "digest"
require "openssl"
require "base64"
require 'json'
# function to get the hashed secret key
def get_hashed_key(secret_key)
hash = Digest::MD5.hexdigest(secret_key)
last_twelve = hash[hash.length-12..hash.length-1]
private_secret_key = secret_key
private_secret_key['FLWSECK-'] = ''
first_twelve = private_secret_key[0..11]
return first_twelve + last_twelve
end
# encryption function
def self.encrypt(key, data)
cipher = OpenSSL::Cipher.new("des-ede3")
cipher.encrypt # Call this before setting key
cipher.key = key
data = data.to_json
ciphertext = cipher.update(data)
ciphertext << cipher.final
return Base64.encode64(ciphertext)
end
public class TripleDES{
private String key;
// Method to turn bytes in hex
public static String toHexStr(byte[] bytes){
StringBuilder builder = new StringBuilder();
for(int i = 0; i < bytes.length; i++ ){
builder.append(String.format("%02x", bytes[i]));
}
return builder.toString();
}
// this is the getKey function that generates an encryption Key for you by passing your Secret Key as a parameter.
public static String getKey(String seedKey) {
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] hashedString = md.digest(seedKey.getBytes("utf-8"));
byte[] subHashString = toHexStr(Arrays.copyOfRange(hashedString, hashedString.length - 12, hashedString.length)).getBytes("utf-8");
String subSeedKey = seedKey.replace("FLWSECK-", "");
subSeedKey = subSeedKey.substring(0, 12);
byte[] combineArray = new byte[24];
System.arraycopy(subSeedKey.getBytes(), 0, combineArray, 0, 12);
System.arraycopy(subHashString, subHashString.length - 12, combineArray, 12, 12);
return new String(combineArray);
} catch (NoSuchAlgorithmException ex) {
Logger.getGlobal().log(Level.SEVERE, null, ex);
} catch (UnsupportedEncodingException ex) {
Logger.getGlobal().log(Level.SEVERE, null, ex);
}
return null;
}
// This is the encryption function that encrypts your payload by passing the stringified format and your encryption Key.
public static String encryptData(String message, String _encryptionKey) {
try {
final byte[] digestOfPassword = _encryptionKey.getBytes("utf-8");
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
final SecretKey key = new SecretKeySpec( keyBytes , "DESede");
final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
final byte[] plainTextBytes = message.getBytes("utf-8");
final byte[] cipherText = cipher.doFinal(plainTextBytes);
return Base64.getEncoder().encodeToString(cipherText);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
// Authored by Tade samson find link to github here: https://github.com/TadeSamson/RavePaymentDataEncryption
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
namespace EncryptionService
{
public class RavePaymentDataEncryption: IPaymentDataEncryption
{
/// <summary>
/// Gets an encryption key from rave secret key.
/// </summary>
/// <param name="secretKey">The secret key generated from your rave dashboard</param>
/// <returns>a string value encrypted</returns>
public string GetEncryptionKey(string secretKey)
{
//MD5 is the hash algorithm expected by rave to generate encryption key
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
//MD5CryptoServiceProvider works with bytes so a conversion of plain secretKey to it bytes equivalent is required.
//UTF8Encoding.UTF8.GetBytes(secretKey) can also be used.
byte[] secretKeyBytes = ASCIIEncoding.UTF8.GetBytes(secretKey);
byte[] hashedSecret = md5.ComputeHash(secretKeyBytes,0,secretKeyBytes.Length);
byte[] hashedSecretLast12Bytes=new byte[12];
Array.Copy(hashedSecret, hashedSecret.Length - 12, hashedSecretLast12Bytes, 0, 12);
String hashedSecretLast12HexString = BitConverter.ToString(hashedSecretLast12Bytes);
hashedSecretLast12HexString = hashedSecretLast12HexString.ToLower().Replace("-", "");
String secretKeyFirst12 = secretKey.Replace("FLWSECK-", "").Substring(0,12);
byte[] hashedSecretLast12HexBytes = ASCIIEncoding.UTF8.GetBytes(hashedSecretLast12HexString);
byte[] secretFirst12Bytes = ASCIIEncoding.UTF8.GetBytes(secretKeyFirst12);
byte[] combineKey = new byte[24];
Array.Copy(secretFirst12Bytes, 0, combineKey, 0, secretFirst12Bytes.Length);
Array.Copy(hashedSecretLast12HexBytes, hashedSecretLast12HexBytes.Length-12, combineKey, 12, 12);
return ASCIIEncoding.UTF8.GetString(combineKey);
}
// This is the encryption function that encrypts your payload by passing the stringified format and your encryption Key.
public string EncryptData(string encryptionKey, string data)
{
TripleDES des = new TripleDESCryptoServiceProvider();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
des.Key = ASCIIEncoding.UTF8.GetBytes(encryptionKey);
ICryptoTransform cryptoTransform = des.CreateEncryptor();
byte[] dataBytes=ASCIIEncoding.UTF8.GetBytes(data);
byte[] encryptedDataBytes= cryptoTransform.TransformFinalBlock(dataBytes, 0, dataBytes.Length);
des.Clear();
return Convert.ToBase64String(encryptedDataBytes);
}
public string DecryptData(string encryptedData,string encryptionKey)
{
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.Key = ASCIIEncoding.UTF8.GetBytes(encryptionKey);
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
ICryptoTransform cryptoTransform = des.CreateDecryptor();
byte[] EncryptDataBytes=Convert.FromBase64String(encryptedData);
byte[] plainDataBytes= cryptoTransform.TransformFinalBlock(EncryptDataBytes, 0, EncryptDataBytes.Length);
des.Clear();
return ASCIIEncoding.UTF8.GetString(plainDataBytes);
}
}
}
The `getEncryptedData` method needs to be called first to clean the secret key, all other methods are used inside it.
private static String encrypt(String data, String key) throws Exception {
byte[] keyBytes = key.getBytes(UTF_8);
SecretKeySpec skey = new SecretKeySpec(keyBytes, ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, skey);
byte[] plainTextBytes = data.getBytes(UTF_8);
byte[] buf = cipher.doFinal(plainTextBytes);
return Base64.encodeToString(buf, Base64.DEFAULT);
}
private static String getMd5(String md5) throws Exception {
MessageDigest md = MessageDigest.getInstance(MD5);
byte[] array = md.digest(md5.getBytes(CHARSET_NAME));
StringBuffer sb = new StringBuffer();
for (int i = 0; i < array.length; ++i) {
sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString();
}
public static String getEncryptedData(String unEncryptedString, String secret) {
try {
// hash the secret
String md5Hash = getMd5(secret);
String cleanSecret = secret.replace(TARGET, "");
int hashLength = md5Hash.length();
String encryptionKey = cleanSecret.substring(0, 12).concat(md5Hash.substring(hashLength - 12, hashLength));
return encrypt(unEncryptedString, encryptionKey);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
// Encrypting the secret key
func MD5(string: String) -> Data? {
guard let messageData = string.data(using:String.Encoding.utf8) else { return nil }
var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))
_ = digestData.withUnsafeMutableBytes {digestBytes in
messageData.withUnsafeBytes {messageBytes in
CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes)
}
}
return digestData
}
func getEncryptionKey(_ secretKey:String)->String {
let md5Data = MD5(string:secretKey)
let md5Hex = md5Data!.map { String(format: "%02hhx", $0) }.joined()
var secretKeyHex = ""
if secretKey.contains("FLWSECK-") {
secretKeyHex = secretKey.replacingOccurrences(of: "FLWSECK-", with: "")
}
if secretKey.contains("-X") {
secretKeyHex = secretKeyHex.replacingOccurrences(of: "-X", with: "")
}
let index = secretKeyHex.index(secretKeyHex.startIndex, offsetBy: 12)
let first12 = secretKeyHex.substring(to: index)
let last12 = md5Hex.substring(from:md5Hex.index(md5Hex.endIndex, offsetBy: -12))
return first12 + last12
}
// Encrypting the payload
static func encrypt(string:String, key:String) -> NSData? {
let keyData: NSData! = (key as NSString).data(using: String.Encoding.utf8.rawValue) as NSData!
let keyBytes = keyData.bytes
let data: NSData! = (string as NSString).data(using: String.Encoding.utf8.rawValue) as NSData!
let dataLength = UInt(data.length)
let dataBytes = data.bytes
let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSize3DES)!
let cryptPointer = cryptData.mutableBytes
let cryptLength = size_t(cryptData.length)
let keyLength = size_t(kCCKeySize3DES)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding+kCCOptionECBMode)
var numBytesEncrypted :Int = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, Int(dataLength),
cryptPointer, cryptLength,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
let _: Int = numBytesEncrypted
cryptData.length = Int(numBytesEncrypted)
return cryptData
} else {
print("Error: \(cryptStatus)")
}
return nil
}
// USAGE
let secret = getEncryptionKey("FLWSECK-045c2e4312c965eefc9c7c62f0a4762c-X")
let data = encrypt(string: payloadJson, key:secret)
Encryption Examples
<?php
function getKey($seckey){
$hashedkey = md5($seckey);
$hashedkeylast12 = substr($hashedkey, -12);
$seckeyadjusted = str_replace("FLWSECK-", "", $seckey);
$seckeyadjustedfirst12 = substr($seckeyadjusted, 0, 12);
$encryptionkey = $seckeyadjustedfirst12.$hashedkeylast12;
return $encryptionkey;
}
function encrypt3Des($data, $key)
{
$encData = openssl_encrypt($data, 'DES-EDE3', $key, OPENSSL_RAW_DATA);
return base64_encode($encData);
}
function payviacard(){ // set up a function to test card payment.
error_reporting(E_ALL);
ini_set('display_errors',1);
$data = array('PBFPubKey' => 'FLWPUBK-e634d14d9ded04eaf05d5b63a0a06d2f-X',
'cardno' => '5438898014560229',
'currency' => 'NGN',
'country' => 'NG',
'cvv' => '789',
'amount' => '300',
'expiryyear' => '19',
'expirymonth' => '09',
'suggested_auth' => 'pin',
'pin' => '3310',
'email' => '[email protected]',
'IP' => '103.238.105.185',
'txRef' => 'MXX-ASC-4578',
'device_fingerprint' => '69e6b7f0sb72037aa8428b70fbe03986c');
$SecKey = 'FLWSECK-bb971402072265fb156e90a3578fe5e6-X';
$key = getKey($SecKey);
$dataReq = json_encode($data);
$post_enc = encrypt3Des( $dataReq, $key );
var_dump($dataReq);
$postdata = array(
'PBFPubKey' => 'FLWPUBK-e634d14d9ded04eaf05d5b63a0a06d2f-X',
'client' => $post_enc,
'alg' => '3DES-24');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/charge");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postdata)); //Post Fields
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 200);
curl_setopt($ch, CURLOPT_TIMEOUT, 200);
$headers = array('Content-Type: application/json');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$request = curl_exec($ch);
if ($request) {
$result = json_decode($request, true);
echo "<pre>";
print_r($result);
}else{
if(curl_error($ch))
{
echo 'error:' . curl_error($ch);
}
}
curl_close($ch);
}
payviacard();
require "digest"
require "openssl"
require "base64"
require 'json'
require 'httparty'
# Rave card payment test
class PayTest
# function to get the hashed secret key
def self.get_hashed_key(secret_key)
hash = Digest::MD5.hexdigest(secret_key)
last_twelve = hash[hash.length-12..hash.length-1]
private_secret_key = secret_key
private_secret_key['FLWSECK-'] = ''
first_twelve = private_secret_key[0..11]
return first_twelve + last_twelve
end
# encryption function
def self.encrypt(key, data)
cipher = OpenSSL::Cipher.new("des-ede3")
cipher.encrypt # Call this before setting key
cipher.key = key
data = data.to_json
ciphertext = cipher.update(data)
ciphertext << cipher.final
return Base64.encode64(ciphertext)
end
# function to test card payment
def self.pay_via_card
data = {
'PBFPubKey' => 'FLWPUBK-e634d14d9ded04eaf05d5b63a0a06d2f-X',
"cardno" => "5438898014560229",
"cvv" => "890",
"expirymonth" => "09",
"expiryyear" => "19",
"currency" => "NGN",
"country" => "NG",
'suggested_auth' => 'pin',
'pin' => '3310',
"amount" => "10",
'txRef' => 'MC-TESTREF-1234',
"email" => "[email protected]",
"phonenumber" => "0902620185",
"firstname" => "maestro",
"lastname" => "jolly",
"IP" => "355426087298442",
"device_fingerprint" => "69e6b7f0b72037aa8428b70fbe03986c"
}
sec_key = 'FLWSECK-bb971402072265fb156e90a3578fe5e6-X'
# hash the secret key with the get hashed key function
hashed_sec_key = get_hashed_key(sec_key)
# encrypt the hashed secret key and payment parameters with the encrypt function
encrypt_3DES_key = encrypt(hashed_sec_key, data)
# payment payload
payload = {
"PBFPubKey" => "FLWPUBK-e634d14d9ded04eaf05d5b63a0a06d2f-X",
"client" => encrypt_3DES_key,
"alg" => "3DES-24"
}
# card charge endpoint
endpoint = "https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/charge"
# send a post request to the charge endpoint
response = HTTParty.post(endpoint, {
body: payload.to_json,
headers: {
'Content-Type' => 'application/json'
}
})
# check if the request is successful or not
if response.code == 200
print response.body
else
raise "An error with this response code #{response.code} has occurred. Response: #{response.body}"
end
end
pay_via_card
end
import os, hashlib, warnings, requests, json
import base64
from Crypto.Cipher import DES3
class PayTest(object):
"""this is the getKey function that generates an encryption Key for you by passing your Secret Key as a parameter."""
def __init__(self):
pass
def getKey(self,secret_key):
hashedseckey = hashlib.md5(secret_key.encode("utf-8")).hexdigest()
hashedseckeylast12 = hashedseckey[-12:]
seckeyadjusted = secret_key.replace('FLWSECK-', '')
seckeyadjustedfirst12 = seckeyadjusted[:12]
return seckeyadjustedfirst12 + hashedseckeylast12
"""This is the encryption function that encrypts your payload by passing the text and your encryption Key."""
def encryptData(self, key, plainText):
blockSize = 8
padDiff = blockSize - (len(plainText) % blockSize)
cipher = DES3.new(key, DES3.MODE_ECB)
plainText = "{}{}".format(plainText, "".join(chr(padDiff) * padDiff))
# cipher.encrypt - the C function that powers this doesn't accept plain string, rather it accepts byte strings, hence the need for the conversion below
test = plainText.encode('utf-8')
encrypted = base64.b64encode(cipher.encrypt(test)).decode("utf-8")
return encrypted
def pay_via_card(self):
data = {
'PBFPubKey': 'FLWPUBK-e634d14d9ded04eaf05d5b63a0a06d2f-X',
"cardno": "5438898014560229",
"cvv": "890",
"expirymonth": "09",
"expiryyear": "19",
"currency": "NGN",
"country": "NG",
'suggested_auth': 'pin',
'pin': '3310',
"amount": "10",
'txRef': 'MC-TESTREF-1234',
"email": "[email protected]",
"phonenumber": "0902620185",
"firstname": "maestro",
"lastname": "jolly",
"IP": "355426087298442",
"device_fingerprint": "69e6b7f0b72037aa8428b70fbe03986c"
}
sec_key = 'FLWSECK-bb971402072265fb156e90a3578fe5e6-X'
# hash the secret key with the get hashed key function
hashed_sec_key = self.getKey(sec_key)
# encrypt the hashed secret key and payment parameters with the encrypt function
encrypt_3DES_key = self.encryptData(hashed_sec_key, json.dumps(data))
# payment payload
payload = {
"PBFPubKey": "FLWPUBK-e634d14d9ded04eaf05d5b63a0a06d2f-X",
"client": encrypt_3DES_key,
"alg": "3DES-24"
}
# card charge endpoint
endpoint = "https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/charge"
# set the content type to application/json
headers = {
'content-type': 'application/json',
}
response = requests.post(endpoint, headers=headers, data=json.dumps(payload))
print(response.json())
rave = PayTest()
rave.pay_via_card()
const forge = require('node-forge');
const request = require('request-promise-native');
const md5 = require('md5');
var options = {
url: "",
method: "",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: {
"PBFPubKey": "",
"alg": "3DES-24",
client: "",
},
json: true
}
class Rave {
/**
* Rave object constructor
* @param {*} public_key This is a string that can be found in merchant rave dashboard
* @param {*} secret_key This is a string that can be found in merchant rave dashboard
*/
constructor(public_key, secret_key){
this.public_key = public_key;
this.secret_key = secret_key;
}
encryptCardDetails(card_details) {
card_details = JSON.stringify(card_details);
let cipher = forge.cipher.createCipher('3DES-ECB', forge.util.createBuffer(this.getKey()));
cipher.start({iv:''});
cipher.update(forge.util.createBuffer(card_details, 'utf-8'));
cipher.finish();
let encrypted = cipher.output;
return ( forge.util.encode64(encrypted.getBytes()) );
}
getKey() {
let sec_key = this.secret_key;
let keymd5 = md5(sec_key);
let keymd5last12 = keymd5.substr(-12);
let seckeyadjusted = sec_key.replace('FLWSECK-', '');
let seckeyadjustedfirst12 = seckeyadjusted.substr(0, 12);
return seckeyadjustedfirst12 + keymd5last12;
}
initiatePayment(card_details) {
return new Promise((resolve, reject) => {
let encrypted_card_details = this.encryptCardDetails(card_details);
let payment_options = Object.assign({}, options);
payment_options.url = 'https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/charge';
payment_options.body.client = encrypted_card_details;
payment_options.method = 'POST';
payment_options.body.PBFPubKey = this.public_key; // set public key
request(payment_options)
.then((result) => {
resolve(result);
}).catch((err) => {
reject(err);
});
})
}
}
var rave = new Rave('FLWPUBK-ba0a57153f497c03bf34a9e296aa9439-X','FLWSECK-327b3874ca8e75640a1198a1b75c0b0b-X');
rave.initiatePayment({
"cardno": "5438898014560229",
"cvv": "890",
"expirymonth": "09",
"expiryyear": "19",
"currency": "NGN",
"pin": "3310",
"country": "NG",
"amount": "10",
"email": "[email protected]",
"suggested_auth": "PIN",
"phonenumber": "0902620185",
"firstname": "temi",
"lastname": "desola",
"IP": "355426087298442",
"txRef": "MC-" + Date.now(),
"redirect_url": "https://rave-webhook.herokuapp.com/receivepayment",
"meta": [{metaname: "flightID", metavalue: "123949494DC"}],
"device_fingerprint": "69e6b7f0b72037aa8428b70fbe03986c"
}).then(result => console.log(result))
.catch(error => console.log(error));