How to build a signature
{danger.fa-exclamation} IMPORTANT: Current encryption algorithm applies to API version 1.2 (document version latest). Please pay attention at the request version that you are using.
Request is signed as follows:
data
0
-padded 32 chars key
0
-padded 16 chars initialization vector, or iv
data
is encrypted with aes-256-cbc encryption using key
and 16-chars iv
- signature
"signature":"..."
Please check out the online generator and validator to test your code.
The following example illustrates the algorithm of adding the authentication details and signature to your requests. The example code can be used to handle the data formatting, however you need to implement the network communication and data handling aspects based on the specifics of your application.
The implementation in each language below contains a generateRequest()
function to receive the input data and
build the valid request JSON. Also, you can find the acceptRequestAndGenerateResponse()
function to parse the incoming
notification requests, validate the authentication details and build the valid JSON response.
INPORTANT: TEST CASES. Both above methods are invoked by default within the _TEST_()
method when you execute the code. The methods are
invoked with sample data from built-in _GET_SAMPLE_DATA_TO_SEND_REQUEST_()
and
_GET_SAMPLE_INCOMING_NOTIFICATION_DATA_()
mock generators accordingly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
namespace HowToBuildSignature
{
class Program
{
// Your Merchant Account ID
public const string MERCHANT_ID = "Test-Integration-Merchant";
// Your Merchant Secret
public const string MERCHANT_SECRET = "MerchantSecretKey";
// Your Application Key
public const string APPLICATION_KEY = "Sandbox";
// Your API Version
public const string API_VERSION = "1.2";
private class _GET_SAMPLE_DATA_TO_SEND_REQUEST_
{
public string your_variable_key_1 { get; set; }
public int your_variable_key_2 { get; set; }
public bool your_variable_key_3 { get; set; }
public bool your_variable_key_4 { get; set; }
public _GET_SAMPLE_DATA_TO_SEND_REQUEST_()
{
your_variable_key_1 = "some_string_value";
your_variable_key_2 = 12345;
// your_variable_key_3 remains undefined
your_variable_key_4 = true;
}
}
private static string _GET_SAMPLE_INCOMING_NOTIFICATION_DATA_()
{
Dictionary<String, Object> request = new Dictionary<string, object>();
request.Add("your_variable_key_1", "some_string_value");
request.Add("your_variable_key_2", 12345);
request.Add("your_variable_key_3", null);
request.Add("your_variable_key_4", true);
request.Add("merchant_id", MERCHANT_ID);
request.Add("version", API_VERSION);
request.Add("application_key", APPLICATION_KEY);
request.Add("timestamp", getCurrentTimestamp());
string concatenated_string = getConcatenatedString(request);
concatenated_string += MERCHANT_SECRET;
string signature = generateSignature(concatenated_string);
request.Add("signature", signature);
string request_json = exportDictionaryToJSON(request);
return request_json;
}
private static Dictionary<string, object> getObjectAsDictionary(object instance)
{
Dictionary<string, object> objectAsDictionary = instance
.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
.ToDictionary(propertyInfo => propertyInfo.Name, propertyInfo => propertyInfo.GetValue(instance));
return objectAsDictionary;
}
private static string getConcatenatedString(Dictionary<string, object> dictionary)
{
string concatenated_string = "";
foreach (KeyValuePair<string, object> key in dictionary.OrderBy(key => key.Key))
{
try
{
if (key.Value.Equals(null) || key.Value.Equals(false))
{
continue;
}
else if (key.Value.Equals(true) || key.Value.ToString().Equals("True"))
{
concatenated_string += "1";
}
else
{
concatenated_string += key.Value.ToString();
}
}
catch (Exception) {
continue;
}
}
return concatenated_string;
}
private static string generateSignature(string input)
{
using (SHA384 sha384Hash = SHA384.Create())
{
//From String to byte array
byte[] sourceBytes = Encoding.UTF8.GetBytes(input);
byte[] hashBytes = sha384Hash.ComputeHash(sourceBytes);
string hash = BitConverter.ToString(hashBytes).Replace("-", string.Empty);
return hash.ToLower();
}
}
private static string exportDictionaryToJSON(Dictionary<string, object> input)
{
string json_string = JsonSerializer.Serialize(input);
return json_string;
}
private static Dictionary<string, object> importJSONToDictionary(string input)
{
Dictionary<string, object> jsonAsDictionary = JsonSerializer.Deserialize<Dictionary<string, object>>(input);
return jsonAsDictionary;
}
private static long getCurrentTimestamp()
{
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
return timestamp;
}
public static string generateRequest(object requestInstance)
{
Dictionary<string, object> request = getObjectAsDictionary(requestInstance);
request.Add("timestamp", getCurrentTimestamp());
request.Add("merchant_id", MERCHANT_ID);
request.Add("application_key", APPLICATION_KEY);
request.Add("version", API_VERSION);
// Sort request array by keys ASC
string concatenated_string = getConcatenatedString(request);
// Concatenate Merchant Secret Key with request params
concatenated_string += MERCHANT_SECRET;
// Generate HASH of concatenated string
string signature = generateSignature(concatenated_string);
request.Add("signature", signature);
// Get a JSON string
string request_json_string = JsonSerializer.Serialize(request);
return request_json_string;
}
public static string acceptRequestAndGenerateResponse(string incoming_json_string)
{
// Parse incoming JSON into data dict
Dictionary<string, object> incoming_data = importJSONToDictionary(incoming_json_string);
// validate signature
string incoming_signature = incoming_data["signature"].ToString();
incoming_data.Remove("signature");
// Concatenate Merchant Secret Key with request params
string incoming_concatenated_string = getConcatenatedString(incoming_data);
// Concatenate Merchant Secret Key with incoming request params
incoming_concatenated_string += MERCHANT_SECRET;
// Generate HASH of concatenated string using your credentials
string test_signature = generateSignature(incoming_concatenated_string);
Dictionary<string, object> response = new Dictionary<string, object>();
response.Add("version", API_VERSION);
// Compare the incoming signature to match the expexted one
if (!incoming_signature.Equals(test_signature))
{
response.Add("status", 1);
response.Add("description", "Invalid signature");
}
else if (!incoming_data.ContainsKey("timestamp") || Convert.ToInt64(incoming_data["timestamp"].ToString()) < getCurrentTimestamp())
{
response.Add("status", 1);
response.Add("description", "Invalid timestamp");
}
else if (!incoming_data.ContainsKey("merchant_id") || !incoming_data["merchant_id"].ToString().Equals(MERCHANT_ID))
{
response.Add("status", 1);
response.Add("description", "Invalid merchant_id");
}
else if (!incoming_data.ContainsKey("application_key") || !incoming_data["application_key"].ToString().Equals(APPLICATION_KEY))
{
response.Add("status", 1);
response.Add("description", "Invalid application_key");
}
else if (!incoming_data.ContainsKey("version") || !incoming_data["version"].ToString().Equals(API_VERSION))
{
response.Add("status", 1);
response.Add("description", "Invalid version");
}
else
{
try
{
// YOUR NOTIFICATION HANDLER GOES HERE
// YOUR NOTIFICATION HANDLER GOES HERE
// YOUR NOTIFICATION HANDLER GOES HERE
response.Add("status", 0);
response.Add("description", "Ok");
}
catch (Exception e)
{
response.Add("status", -1);
response.Add("description", "Exception has occurred: " + e.Message);
}
}
// Concatenate Merchant Secret Key with request params
string concatenated_string = getConcatenatedString(response);
concatenated_string += MERCHANT_SECRET;
// Generate HASH of concatenated string
String signature = generateSignature(concatenated_string);
response.Add("signature", signature);
// Get a JSON string
String response_json_string = exportDictionaryToJSON(response);
return response_json_string;
}
public static void _TEST_()
{
Console.WriteLine("=== TESTING REQUEST TO BE SENT ====");
Object request_to_send = new _GET_SAMPLE_DATA_TO_SEND_REQUEST_();
String request_to_send_json_string = generateRequest(request_to_send);
Console.WriteLine("== data to send:");
Console.WriteLine(request_to_send_json_string);
Console.WriteLine("");
Console.WriteLine("=== TESTING NOTIFICATION TO BE RECEIVED ====");
String notification_to_receive = _GET_SAMPLE_INCOMING_NOTIFICATION_DATA_();
String notification_response_to_send_json_string = acceptRequestAndGenerateResponse(notification_to_receive);
Console.WriteLine("== data to receive:");
Console.WriteLine(notification_to_receive);
Console.WriteLine("== data to send in response:");
Console.WriteLine(notification_response_to_send_json_string);
}
static void Main(string[] args)
{
_TEST_();
}
}
}
<?php
class HowToBuildSignature
{
// Your Merchant Account ID
const MERCHANT_ID = 'Test-Integration-Merchant';
// Your Merchant Secret
const MERCHANT_SECRET = 'MerchantSecretKey';
// Your Application Key
const APPLICATION_KEY = 'Sandbox';
// Your API Version
const API_VERSION = '1.3';
public static function _GET_SAMPLE_DATA_TO_SEND_REQUEST_():array {
$request = [
'your_variable_key_1' => 'some_string_value',
'your_variable_key_2' => 12345,
'your_variable_key_3' => null,
'your_variable_key_4' => true,
'your_nested_variable' => [
'your_nested_variable_key_1' => 'some_nested_string_value',
],
];
return $request;
}
public static function _GET_SAMPLE_INCOMING_NOTIFICATION_DATA_():string {
$request = [
'your_variable_key_1' => 'some_string_value',
'your_variable_key_2' => 12345,
'your_variable_key_3' => null,
'your_variable_key_4' => true,
'your_nested_variable' => [
'your_nested_variable_key_1' => 'some_nested_string_value',
],
'merchant_id' => HowToBuildSignature::MERCHANT_ID,
'version' => HowToBuildSignature::API_VERSION,
'application_key' => HowToBuildSignature::APPLICATION_KEY,
'timestamp' => self::getCurrentTimestamp()
];
$request_string = HowToBuildSignature::getConcatenatedString($request);
$request['signature'] = HowToBuildSignature::generateSignature($request_string, HowToBuildSignature::MERCHANT_SECRET, $request['timestamp']);
$request_json = HowToBuildSignature::exportArrayToJSON($request);
return $request_json;
}
private static function getConcatenatedString(array $data):string {
foreach ($data as $key => $value) {
if (is_array($value)) {
$data[$key] = self::getConcatenatedString($value);
}
}
ksort($data);
return implode('', array_values($data));
}
private static function generateSignature(string $input, $key, $iv):string {
$cipher = "aes-256-cbc";
$iv = str_pad($iv, 16, '0');
$hashtext = base64_encode(openssl_encrypt($input, $cipher, $key, OPENSSL_RAW_DATA, $iv));
return $hashtext;
}
private static function exportArrayToJSON(array $input):string {
$json_string = json_encode($input);
return $json_string;
}
private static function importJSONToArray(string $input):array {
$data_array = json_decode($input, true);
return $data_array;
}
private static function getCurrentTimestamp():int {
return time();
}
public static function generateRequest(array $request):string {
$request['timestamp'] = self::getCurrentTimestamp();
$request['merchant_id'] = self::MERCHANT_ID;
$request['application_key'] = self::APPLICATION_KEY;
$request['version'] = self::API_VERSION;
// Sort request array by keys ASC
$concatenated_string = self::getConcatenatedString($request);
// Generate HASH of concatenated string
$signature = self::generateSignature($concatenated_string, self::MERCHANT_SECRET, $request['timestamp']);
$request['signature'] = $signature;
// Get a JSON string
$request_json_string = self::exportArrayToJSON($request);
return $request_json_string;
}
public static function acceptRequestAndGenerateResponse(string $incoming_json_string):string {
// Parse incoming JSON into data dict
$incoming_data = self::importJSONToArray($incoming_json_string);
// validate signature
$incoming_signature = $incoming_data['signature'];
unset($incoming_data['signature']);
// Sort incoming data array by keys ASC
$incoming_concatenated_string = self::getConcatenatedString($incoming_data);
// Generate HASH of concatenated string using your credentials
$test_signature = self::generateSignature($incoming_concatenated_string, self::MERCHANT_SECRET, $incoming_data['timestamp']);
$response = [
'version' => self::API_VERSION,
'timestamp' => self::getCurrentTimestamp(),
];
// Compare the incoming signature to match the expexted one
if ($incoming_signature !== $test_signature) {
$response['status'] = 1;
$response['description'] = 'Invalid signature';
} else if (empty($incoming_data['timestamp']) || $incoming_data['timestamp'] < (time() - 60)) {
$response['status'] = 1;
$response['description'] = 'Invalid timestamp';
} else if (empty($incoming_data['merchant_id']) || $incoming_data['merchant_id'] !== self::MERCHANT_ID) {
$response['status'] = 1;
$response['description'] = 'Invalid merchant_id';
} else if (empty($incoming_data['application_key']) || $incoming_data['application_key'] !== self::APPLICATION_KEY) {
$response['status'] = 1;
$response['description'] = 'Invalid application_key';
} else if (empty($incoming_data['version']) || $incoming_data['version'] !== self::API_VERSION) {
$response['status'] = 1;
$response['description'] = 'Invalid version';
} else {
try {
// YOUR NOTIFICATION HANDLER GOES HERE
// YOUR NOTIFICATION HANDLER GOES HERE
// YOUR NOTIFICATION HANDLER GOES HERE
$response['status'] = 0;
$response['description'] = 'Ok';
} catch (Exception $e) {
$response['status'] = -1;
$response['description'] = 'Exception has occurred';
}
}
// Sort response array by keys ASC
$concatenated_string = self::getConcatenatedString($response);
// Generate HASH of concatenated string
$signature = self::generateSignature($concatenated_string, self::MERCHANT_SECRET, $response['timestamp']);
$response['signature'] = $signature;
// Get a JSON string
$response_json_string = self::exportArrayToJSON($response);
return $response_json_string;
}
public static function _TEST_() {
echo "=== TESTING REQUEST TO BE SENT ===="; echo "\n";
$request_to_send = self::_GET_SAMPLE_DATA_TO_SEND_REQUEST_();
$request_to_send_json_string = self::generateRequest($request_to_send);
echo "== data to send:"; echo "\n";
echo $request_to_send_json_string; echo "\n";
echo "\n";
echo "=== TESTING NOTIFICATION TO BE RECEIVED ===="; echo "\n";
$notification_to_receive = self::_GET_SAMPLE_INCOMING_NOTIFICATION_DATA_();
$notification_response_to_send_json_string = self::acceptRequestAndGenerateResponse($notification_to_receive);
echo "== data to receive:"; echo "\n";
echo $notification_to_receive; echo "\n";
echo "== data to send in response:"; echo "\n";
echo $notification_response_to_send_json_string; echo "\n";
}
}
HowToBuildSignature::_TEST_();
import hashlib
import time
import json
class HowToBuildSignature:
# Your Merchant Account ID
MERCHANT_ID = "Test-Integration-Merchant"
# Your Merchant Secret
MERCHANT_SECRET = "MerchantSecretKey"
# Your Application Key
APPLICATION_KEY = "Sandbox"
# Your API Version
API_VERSION = "1.2";
@classmethod
def _GET_SAMPLE_DATA_TO_SEND_REQUEST_(cls):
request = {
'your_variable_key_1':'some_string_value',
'your_variable_key_2':12345,
'your_variable_key_3':None,
'your_variable_key_4':True
}
return request
@classmethod
def _GET_SAMPLE_INCOMING_NOTIFICATION_DATA_(cls):
request = {
'your_variable_key_1':'some_string_value',
'your_variable_key_2':12345,
'your_variable_key_3':None,
'your_variable_key_4':True,
'merchant_id': cls.MERCHANT_ID,
'version': cls.API_VERSION,
'application_key': cls.APPLICATION_KEY,
'timestamp': cls.getCurrentTimestamp()
}
request_string = HowToBuildSignature.getConcatenatedString(request)
request_string = request_string + HowToBuildSignature.MERCHANT_SECRET
request['signature'] = HowToBuildSignature.generateSignature(request_string)
request_json = HowToBuildSignature.exportDictToJSON(request)
return request_json
@classmethod
def getConcatenatedString(cls, dictionary):
keys = dictionary.keys()
keys.sort()
concatenated_string = ''
for key in keys:
if dictionary[key] is True:
# boolean True should appear as 1
concatenated_string = concatenated_string + '1'
elif dictionary[key] is False or dictionary[key] is None:
# boolean False and None should be skipped
pass
else:
# all other data types appear with __str__() representation
concatenated_string = concatenated_string + str(dictionary[key])
return concatenated_string
@classmethod
def generateSignature(cls, input):
hashtext = hashlib.sha384(input).hexdigest()
return hashtext
@classmethod
def exportDictToJSON(cls, input):
json_string = json.dumps(input)
return json_string
@classmethod
def importJSONToDict(cls, input):
data_dict = json.loads(input)
return data_dict
@classmethod
def getCurrentTimestamp(cls):
timestamp = int( time.time() )
return timestamp
@classmethod
def generateRequest(cls, request):
request['timestamp'] = cls.getCurrentTimestamp()
request['merchant_id'] = cls.MERCHANT_ID
request['application_key'] = cls.APPLICATION_KEY
request['version'] = cls.API_VERSION
# Sort request array by keys ASC
concatenated_string = cls.getConcatenatedString(request)
# Concatenate Merchant Secret Key with request params
concatenated_string = concatenated_string + cls.MERCHANT_SECRET
# Generate HASH of concatenated string
signature = cls.generateSignature(concatenated_string)
request['signature'] = signature
# Get a JSON string
request_json_string = cls.exportDictToJSON(request)
return request_json_string
@classmethod
def acceptRequestAndGenerateResponse(cls, incoming_json_string):
# Parse incoming JSON into data dict
incoming_data = cls.importJSONToDict(incoming_json_string)
# validate signature
incoming_signature = incoming_data['signature']
del incoming_data['signature']
# Sort incoming data array by keys ASC
incoming_concatenated_string = cls.getConcatenatedString(incoming_data)
# Concatenate Merchant Secret Key with incoming request params
incoming_concatenated_string = incoming_concatenated_string + cls.MERCHANT_SECRET
# Generate HASH of concatenated string using your credentials
test_signature = cls.generateSignature(incoming_concatenated_string)
response = {
'version': cls.API_VERSION
}
# Compare the incoming signature to match the expexted one
if incoming_signature != test_signature:
response['status'] = 1
response['description'] = 'Invalid signature'
elif not incoming_data.has_key('timestamp') or incoming_data['timestamp'] < (cls.getCurrentTimestamp() - 60):
response['status'] = 1
response['description'] = 'Invalid timestamp'
elif not incoming_data.has_key('merchant_id') or incoming_data['merchant_id'] != cls.MERCHANT_ID:
response['status'] = 1
response['description'] = 'Invalid merchant_id'
elif not incoming_data.has_key('application_key') or incoming_data['application_key'] != cls.APPLICATION_KEY:
response['status'] = 1
response['description'] = 'Invalid application_key'
elif not incoming_data.has_key('version') or incoming_data['version'] != cls.API_VERSION:
response['status'] = 1
response['description'] = 'Invalid version'
else:
try:
# YOUR NOTIFICATION HANDLER GOES HERE
# YOUR NOTIFICATION HANDLER GOES HERE
# YOUR NOTIFICATION HANDLER GOES HERE
response['status'] = 0
response['description'] = 'Ok'
except:
response['status'] = -1
response['description'] = 'Exception has occurred'
# Sort response array by keys ASC
concatenated_string = cls.getConcatenatedString(response)
# Concatenate Merchant Secret Key with response params
concatenated_string = concatenated_string + cls.MERCHANT_SECRET
# Generate HASH of concatenated string
signature = cls.generateSignature(concatenated_string)
response['signature'] = signature
# Get a JSON string
response_json_string = cls.exportDictToJSON(response)
return response_json_string
@classmethod
def _TEST_(cls):
print "=== TESTING REQUEST TO BE SENT ===="
request_to_send = cls._GET_SAMPLE_DATA_TO_SEND_REQUEST_()
request_to_send_json_string = cls.generateRequest(request_to_send)
print "== data to send:"
print request_to_send_json_string
print ""
print "=== TESTING NOTIFICATION TO BE RECEIVED ===="
notification_to_receive = cls._GET_SAMPLE_INCOMING_NOTIFICATION_DATA_()
notification_response_to_send_json_string = cls.acceptRequestAndGenerateResponse(notification_to_receive)
print "== data to receive:"
print notification_to_receive
print "== data to send in response:"
print notification_response_to_send_json_string
if __name__ == '__main__':
HowToBuildSignature._TEST_()
const crypto = require('crypto');
// Your Merchant Account ID
const MERCHANT_ID = 'Test-Integration-Merchant';
// Your Merchant Secret
const MERCHANT_SECRET = 'MerchantSecretKey';
// Your Application Key
const APPLICATION_KEY = "Sandbox";
// Your API Version
const API_VERSION = "1.2";
function _GET_SAMPLE_DATA_TO_SEND_REQUEST_() {
let request = {
'your_variable_key_1': 'some_string_value',
'your_variable_key_2': 12345,
'your_variable_key_3': null,
'your_variable_key_4': true
};
return request;
}
function _GET_SAMPLE_INCOMING_NOTIFICATION_DATA_() {
let request = {
'your_variable_key_1':'some_string_value',
'your_variable_key_2':12345,
'your_variable_key_3':null,
'your_variable_key_4':true,
'merchant_id': MERCHANT_ID,
'version': API_VERSION,
'application_key': APPLICATION_KEY,
'timestamp': getCurrentTimestamp()
};
request_string = getConcatenatedString(request);
request_string += MERCHANT_SECRET;
request['signature'] = generateSignature(request_string);
request_json = exportArrayToJSON(request);
return request_json;
}
function getConcatenatedString(data) {
let keys = [],
concatenated_string = '';
for (let key in data) {
keys.push(key);
}
keys.sort();
for (let index=0; index<keys.length; index++) {
if (data[keys[index]] === null || data[keys[index]] === false) {
continue;
} else if (data[keys[index]] === true) {
concatenated_string = concatenated_string + '1';
} else {
concatenated_string = concatenated_string + data[keys[index]].toString();
}
}
return concatenated_string;
}
function generateSignature(input) {
let signature = crypto.createHash('sha384').update(input, 'utf-8').digest('hex');
return signature;
}
function exportArrayToJSON(input) {
let json_string = JSON.stringify(input);
return json_string;
}
function importJSONToArray(input) {
let data_array = JSON.parse(input);
return data_array;
}
function getCurrentTimestamp() {
let timestamp = Math.round( (new Date()).getTime() / 1000);
return timestamp;
}
function generateRequest(request) {
request['timestamp'] = getCurrentTimestamp();
request['merchant_id'] = MERCHANT_ID;
request['application_key'] = APPLICATION_KEY;
request['version'] = API_VERSION;
// Sort request array by keys ASC
let concatenated_string = getConcatenatedString(request);
// Concatenate Merchant Secret Key with request params
concatenated_string = concatenated_string + MERCHANT_SECRET;
// Generate HASH of concatenated string
let signature = generateSignature(concatenated_string);
request['signature'] = signature;
// Get a JSON string
let request_json_string = exportArrayToJSON(request);
return request_json_string;
}
function acceptRequestAndGenerateResponse(incoming_json_string) {
var response;
let incoming_data,
incoming_signature,
incoming_concatenated_string,
test_signature,
concatenated_string,
signature,
response_json_string;
// Parse incoming JSON into data dict
incoming_data = importJSONToArray(incoming_json_string);
// validate signature
incoming_signature = incoming_data['signature'];
delete(incoming_data['signature']);
// Sort incoming data array by keys ASC
incoming_concatenated_string = getConcatenatedString(incoming_data);
// Concatenate Merchant Secret Key with incoming request params
incoming_concatenated_string += MERCHANT_SECRET;
// Generate HASH of concatenated string using your credentials
test_signature = generateSignature(incoming_concatenated_string);
response = {
'version': API_VERSION
};
// Compare the incoming signature to match the expexted one
if (incoming_signature !== test_signature) {
response['status'] = 1;
response['description'] = 'Invalid signature';
} else if (typeof incoming_data['timestamp'] === 'undefined' || incoming_data['timestamp'] < (getCurrentTimestamp() - 60)) {
response['status'] = 1;
response['description'] = 'Invalid timestamp';
} else if (typeof incoming_data['merchant_id'] === 'undefined' || incoming_data['merchant_id'] !== MERCHANT_ID) {
response['status'] = 1;
response['description'] = 'Invalid merchant_id';
} else if (typeof incoming_data['application_key'] === 'undefined' || incoming_data['application_key'] !== APPLICATION_KEY) {
response['status'] = 1;
response['description'] = 'Invalid application_key';
} else if (typeof incoming_data['version'] === 'undefined' || incoming_data['version'] !== API_VERSION) {
response['status'] = 1;
response['description'] = 'Invalid version';
} else {
try {
// YOUR NOTIFICATION HANDLER GOES HERE
// YOUR NOTIFICATION HANDLER GOES HERE
// YOUR NOTIFICATION HANDLER GOES HERE
response['status'] = 0;
response['description'] = 'Ok';
} catch (e) {
response['status'] = -1;
response['description'] = 'Exception has occurred';
}
}
// Sort response array by keys ASC
concatenated_string = getConcatenatedString(response);
// Concatenate Merchant Secret Key with response params
concatenated_string += MERCHANT_SECRET;
// Generate HASH of concatenated string
signature = generateSignature(concatenated_string);
response['signature'] = signature;
// Get a JSON string
response_json_string = exportArrayToJSON(response);
return response_json_string;
}
function _TEST_() {
console.log('=== TESTING REQUEST TO BE SENT ====');
let request_to_send = _GET_SAMPLE_DATA_TO_SEND_REQUEST_();
let request_to_send_json_string = generateRequest(request_to_send);
console.log('== data to send:');
console.log(request_to_send_json_string);
console.log('');
console.log('=== TESTING NOTIFICATION TO BE RECEIVED ====');
let notification_to_receive = _GET_SAMPLE_INCOMING_NOTIFICATION_DATA_();
let notification_response_to_send_json_string = acceptRequestAndGenerateResponse(notification_to_receive);
console.log('== data to receive:');
console.log(notification_to_receive);
console.log('== data to send in response:');
console.log(notification_response_to_send_json_string);
}
_TEST_();
package com.praxiscashier;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class Main {
// Your Merchant Account ID
public static final String MERCHANT_ID = "Test-Integration-Merchant";
// Your Merchant Secret
public static final String MERCHANT_SECRET = "MerchantSecretKey";
// Your Application Key
public static final String APPLICATION_KEY = "Sandbox";
// Your API Version
public static final String API_VERSION = "1.2";
// Sample request data
private static class _GET_SAMPLE_DATA_TO_SEND_REQUEST_ {
public String your_variable_key_1;
public Integer your_variable_key_2;
public Boolean your_variable_key_3;
public Boolean your_variable_key_4;
public _GET_SAMPLE_DATA_TO_SEND_REQUEST_() {
your_variable_key_1 = "some_string_value";
your_variable_key_2 = 12345;
your_variable_key_4 = true;
}
}
// Sample incoming notification data
private static String _GET_SAMPLE_INCOMING_NOTIFICATION_DATA_() {
Map<String, Object> request = new HashMap<String, Object>();
request.put("your_variable_key_1", "some_string_value");
request.put("your_variable_key_2", 12345);
request.put("your_variable_key_3", null);
request.put("your_variable_key_4", true);
request.put("merchant_id", MERCHANT_ID);
request.put("version", API_VERSION);
request.put("application_key", APPLICATION_KEY);
request.put("timestamp", getCurrentTimestamp());
Map<String, Object> request_sorted = getSortedMap(request);
String request_string = getConcatenatedString(request_sorted);
request_string += MERCHANT_SECRET;
String signature = generateSignature(request_string);
request.put("signature", signature);
String request_json = exportMapToJSON(request);
return request_json;
}
private static Map<String, Object> getObjectAsMap(Object instance) {
Class<?> instanceClass = instance.getClass();
Field[] fields = instanceClass.getDeclaredFields();
Map<String, Object> fieldsAsMap = new HashMap<String, Object>();
for (Field field : fields) {
try {
fieldsAsMap.put(field.getName().toString(), field.get(instance));
}
catch (IllegalArgumentException ignored) { }
catch (IllegalAccessException e) { }
}
return fieldsAsMap;
}
private static Map<String, Object> getSortedMap(Map<String, Object> map) {
Map<String, Object> mapSorted = new TreeMap<String, Object>(map);
return mapSorted;
}
private static String getConcatenatedString(Map<String, Object> map) {
StringBuilder concatenated_string = new StringBuilder(14);
for (Map.Entry<String, Object> entry : map.entrySet()) {
try {
if (entry.getValue() == null || entry.getValue().equals(false)) {
// should not be added to resulting string
} else if (entry.getValue().equals(true)) {
concatenated_string.append("1");
} else {
concatenated_string.append(entry.getValue().toString());
}
}
catch (NullPointerException ignored) { }
}
return concatenated_string.toString();
}
private static String generateSignature(String input) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-384");
byte[] messageDigest = md.digest(input.getBytes());
BigInteger no = new BigInteger(1, messageDigest);
String hashtext = no.toString(16);
return hashtext;
}
catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static String exportMapToJSON(Map<String, Object> map) {
Gson gson = new Gson();
String mapAsJson = gson.toJson(map);
return mapAsJson;
}
private static Map<String, Object> importJSONToMap(String input) {
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> jsonAsMap = gson.fromJson(input, type);
// the API communication does not have floats nor doubles, make sure that all large numeric values are long
for (Map.Entry<String, Object> entry : jsonAsMap.entrySet()) {
try {
if (entry.getValue() instanceof Double) {
Double doubleValue = Double.parseDouble(entry.getValue().toString());
Long longValue = doubleValue.longValue();
jsonAsMap.put(entry.getKey(), longValue);
}
}
catch (NullPointerException ignored) { }
}
return jsonAsMap;
}
private static long getCurrentTimestamp() {
long timestamp = System.currentTimeMillis() / 1000L;
return timestamp;
}
public static String generateRequest(Object requestInstance) {
Map<String, Object> request = getObjectAsMap(requestInstance);
long timestamp = getCurrentTimestamp();
request.put("timestamp", timestamp);
request.put("merchant_id", MERCHANT_ID);
request.put("application_key", APPLICATION_KEY);
request.put("version", API_VERSION);
// Sort request array by keys ASC
Map<String, Object> requestSorted = getSortedMap(request);
// Concatenate Merchant Secret Key with request params
String concatenated_string = getConcatenatedString(requestSorted);
concatenated_string = concatenated_string + MERCHANT_SECRET;
// Generate HASH of concatenated string
String signature = generateSignature(concatenated_string);
requestSorted.put("signature", signature);
// Get a JSON string
String request_json_string = exportMapToJSON(requestSorted);
return request_json_string;
}
public static String acceptRequestAndGenerateResponse(String incoming_json_string) {
// Parse incoming JSON into data dict
Map<String, Object> incoming_data = importJSONToMap(incoming_json_string);
// validate signature
String incoming_signature = incoming_data.get("signature").toString();
incoming_data.remove("signature");
// Sort incoming data array by keys ASC
Map<String, Object> incoming_data_sorted = getSortedMap(incoming_data);
// Concatenate Merchant Secret Key with request params
String incoming_concatenated_string = getConcatenatedString(incoming_data_sorted);
incoming_concatenated_string += MERCHANT_SECRET;
// Generate HASH of concatenated string using your credentials
String test_signature = generateSignature(incoming_concatenated_string);
Map<String, Object> response = new HashMap<String, Object>();
response.put("version", API_VERSION);
// Compare the incoming signature to match the expexted one
if (!incoming_signature.equals(test_signature)) {
response.put("status", 1);
response.put("description", "Invalid signature");
} else if (Long.parseLong(incoming_data.getOrDefault("timestamp", 0).toString()) < getCurrentTimestamp()) {
response.put("status", 1);
response.put("description", "Invalid timestamp");
} else if (!incoming_data.getOrDefault("merchant_id", "").toString().equals(MERCHANT_ID)) {
response.put("status", 1);
response.put("description", "Invalid merchant_id");
} else if (!incoming_data.getOrDefault("application_key", "").toString().equals(APPLICATION_KEY)) {
response.put("status", 1);
response.put("description", "Invalid application_key");
} else if (!incoming_data.getOrDefault("version", "").toString().equals(API_VERSION)) {
response.put("status", 1);
response.put("description", "Invalid version");
} else {
try {
// YOUR NOTIFICATION HANDLER GOES HERE
// YOUR NOTIFICATION HANDLER GOES HERE
// YOUR NOTIFICATION HANDLER GOES HERE
response.put("status", 0);
response.put("description", "Ok");
} catch (Exception e) {
response.put("status", -1);
response.put("description", "Exception has occurred");
}
}
// Sort response array by keys ASC
Map<String, Object> response_sorted = getSortedMap(response);
// Concatenate Merchant Secret Key with request params
String concatenated_string = getConcatenatedString(response_sorted);
concatenated_string += MERCHANT_SECRET;
// Generate HASH of concatenated string
String signature = generateSignature(concatenated_string);
response.put("signature", signature);
// Get a JSON string
String response_json_string = exportMapToJSON(response);
return response_json_string;
}
public static void _TEST_() {
System.out.println("=== TESTING REQUEST TO BE SENT ====");
Object request_to_send = new _GET_SAMPLE_DATA_TO_SEND_REQUEST_();
String request_to_send_json_string = generateRequest(request_to_send);
System.out.println("== data to send:");
System.out.println(request_to_send_json_string);
System.out.println("");
System.out.println("=== TESTING NOTIFICATION TO BE RECEIVED ====");
String notification_to_receive = _GET_SAMPLE_INCOMING_NOTIFICATION_DATA_();
String notification_response_to_send_json_string = acceptRequestAndGenerateResponse(notification_to_receive);
System.out.println("== data to receive:");
System.out.println(notification_to_receive);
System.out.println("== data to send in response:");
System.out.println(notification_response_to_send_json_string);
}
public static void main(String[] args) {
_TEST_();
}
}
Notification signature (received by your CRM) is verified in a similar way:
signature
key is removed from arrayPlease check out the online generator and validator to test your code.
Response signature is built as follows:
-1
for error - notification is resent, 0
for success, 1
for request validation error) "version":"1.2"
"timestamp":...
"signature":"..."
Please check out the online generator and validator to test your code.