Dinger Callback Response
After the payment, Dinger will invoke to your callback url if the transaction is success or fail. If it is in pending status, dinger will not invoke the callback url.
Dinger will also send encrypted response to your callback url. You will need to use your callback key you generated in the dashboard to decrypt the payment result.
• paymentResult (Needs to decrypt the paymentResult response with Base64 first and then with AES/ECB/PKCS7Padding algorithm)
• checksum(sha256(jsonString(resultObj))
Testing Callback Key - d655c33205363f5450427e6b6193e466 (Call Back Key from Data Dash)
Method - POST
Content-Type: application/json
{
“paymentResult":"5zDOSGSI/YE7wsmX/IlBZb6iH0NpwgRuUL13RY9sEKIvo8oebHCh1FKZ0MKTkvlKPQ6Cn2qYg7UDQssBuMbkVAGWcVPK0WvvrrACrx480jdydrNUcsqX4vsaqHuRlCQa/7Qfur+W6WNKO4exvOvN25FtE8hDB7ENu37r54wUlGC21bojhq9M15/Ql5P9+w1x/+Ep13nmyptGOHfI4a4V3D57v0HQ8KqUnOy5P6E4FYOSeOVeVuCJ516RK94OIVAUB3F9jqy4NLm9jqc243pWOR9fwGJK5YplMbOuQFEZKt0=", “checksum":"3e6dc224539d382f300f658a26775e75029b26ba0b885196e7ec66feb6a756ae"
}
curl example
curl --location -g --request POST 'https://merchanturl.com/api/callBack' \
--header 'Content-Type: application/json' \
--data-raw '{"paymentResult":"uQZVb6O5qTxp7dz3c4yB3T5WBlc/EWVXsAaapcc2BXquHcJIQYdyjc2zW+EIWYOznH2XEUkL1h5BSvhr+XWgiBZpkDK4klcGRigE61vRhAxLFs32HypMdcVvPQ17yeDrmhOPtrsyiVWTZ/Ub4Iu97DPBCHp+gTM1qyj+NqjccS+06wnLG+IzyWMXgW8fuEa2ODczp3NpsUv3tEUjIKvp99x4inG/FObzU8y4lyeu2mJDL1WBdKgnNLCR+tUU2qfzry8M/mDbbPAxb6Hi2Q4s/zVwyeXQE27jBRlUieXTP1ePrQ9fdj7dJxBQ7fsGmEWQ9iPuzL367lJvFlIPcTgQThg9XFieqG9ZBz9eTzaMAuw=","checksum":"99f13ebc78ae100494c41409139552f838371ac87e55f907ce23dd63dfec2bed"}'
Sample Response After Decryption
{
"totalAmount":1000,
"createdAt":"20210916 085233",
"transactionStatus":"SUCCESS",
"methodName":"QR",
"merchantOrderId":"0586",
"transactionId":"TRX312720215216085254",
"customerName":"Min Thu Kyaw",
"providerName":"KBZ Pay"
}
Decryption Code Sample
import * as aesEcb from 'aes-ecb';
const SECRET_KEY = 'd655c33205363f5450427e6b6193e466';
const cipherText ="5zDOSGSI/YE7wsmX/IlBZb6iH0NpwgRuUL13RY9sEKIvo8oebHCh1FKZ0MKTkvlKPQ6Cn2qYg7UDQssBuMbkVAGWcVPK0WvvrrACrx480jdydrNUcsqX4vsaqHuRlCQa/7Qfur+W6WNKO4exvOvN25FtE8hDB7ENu37r54wUlGC21bojhq9M15/Ql5P9+w1x/+Ep13nmyptGOHfI4a4V3D57v0HQ8KqUnOy5P6E4FYOSeOVeVuCJ516RK94OIVAUB3F9jqy4NLm9jqc243pWOR9fwGJK5YplMbOuQFEZKt0=";
const resultObj = aesEcb.decrypt(SECRET_KEY, cipherText);
console.log(resultObj);
import { sha256 } from "js-sha256";
let sign = sha256(resultObj);
console.log(sign);
* This sign value and the checksum value(from the URL) must be same, if not we have to assume incorrect signature and return error *
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "dbname";
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$result = file_get_contents("php://input");
$decodeValue = json_decode($result, true);
$paymentResult = $decodeValue['paymentResult'];
$checkSum = $decodeValue['checksum'];
$secrectKey = "d655c33205363f5450427e6b6193e466";
$decrypted = openssl_decrypt($paymentResult,"AES-256-ECB", $secrectKey);
if(hash("sha256", $decrypted) !== $checkSum){
echo "incorrect Singanature.";
} elseif (hash("sha256", $decrypted) == $checkSum) {
$decryptedValues = json_decode($decrypted, true);
$transactionStatus = $decryptedValues["transactionStatus"];
$merchantOrderId = $decryptedValues["merchantOrderId"];
$totalAmount = $decryptedValues["totalAmount"];
$methodName = $decryptedValues["methodName"];
$providerName = $decryptedValues["providerName"];
$transactionId = $decryptedValues["transactionId"];
$customerName = $decryptedValues["customerName"];
$date = date("Y-m-d H:i:s");
if ( $transactionStatus == "SUCCESS" ) {
$success = "display your success message to customer and save the transaction to db. and do some success function for your app";
$sql = "INSERT INTO callback_data (totalAmount, transactionStatus, methodName, providerName, merchantOrderId, transactionId, customerName, created_at, updated_at )
VALUES ('$totalAmount', '$transactionStatus', '$methodName', '$providerName', '$merchantOrderId', '$transactionId', '$customerName', '$date', '$date' )";
if ($conn->query($sql) === TRUE) {
echo "New record created successfully";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
} else {
$error = "display error message and save the transaction to db";
}
$callBackResponse = array(
'transactionStatus' => $transactionStatus,
'merchantOrderId' => $merchantOrderId,
'totalAmount' => $totalAmount,
'methodName' => $methodName,
'providerName' => $providerName,
'transactionId' => $transactionId,
'customerName' => $customerName,
);
header('Content-Type: application/json');
echo json_encode(array("data"=>$callBackResponse));
}
// decrypt callback data
$paymentResult = $request->paymentResult;
$secrectKey = "7f4917e39f698ac433ac1d207e139adc";
$decrypted = openssl_decrypt($paymentResult,"AES-256-ECB", $secrectKey);
// get callback data
$decryptedValues = json_decode($decrypted, true);
$transactionStatus = $decryptedValues["transactionStatus"];
$merchantOrderId = $decryptedValues["merchantOrderId"];
$totalAmount = $decryptedValues["totalAmount"];
$methodName = $decryptedValues["methodName"];
$providerName = $decryptedValues["providerName"];
$transactionId = $decryptedValues["transactionId"];
$customerName = $decryptedValues["customerName"];
from Crypto.Util.Padding import pad
from Crypto.Cipher import AES
import base64
class PrpCrypt(object):
def __init__(self):
self.unpad = lambda date: date[0:-ord(date[-1])]
def aes_cipher(self, key, aes_str):
aes = AES.new(key.encode('utf-8'), AES.MODE_ECB)
pad_pkcs7 = pad(aes_str.encode('utf-8'), AES.block_size, style='pkcs7')
encrypt_aes = aes.encrypt(pad_pkcs7)
encrypted_text = str(base64.encodebytes(encrypt_aes), encoding='utf-8')
encrypted_text_str = encrypted_text.replace("\n", "")
return encrypted_text_str
def decrypt(self, key, decrData):
res = base64.decodebytes(decrData.encode("utf8"))
aes = AES.new(key.encode('utf-8'), AES.MODE_ECB)
msg = aes.decrypt(res).decode("utf8")
return self.unpad(msg)
if __name__ == '__main__':
# replace with your callback key
key = "d655c33205363f5450427e6b6193e466"
# callback data to be decrypted
paymentResult = "mX2Ku+jslxIXDSQMxl3wzDclIiKilKlakN2149ijiV467m3lgyQTHuUlobdKDUrfxa5xlMg5HLj9MuO0WWssf+EjcRnPI8LMxU7LnM8lDYO52QeuU1bZ/0WV95jzJ1jOt6AJXNiSl+wu6wy6sQioCjVyyRXIpSug/4pokaXkIdQCpZo/YKa5QpVtSf1DucnCG/ESsxTw1sJQ39Pox8tdbcSvTPZrdFzcAyi/C8JFVtavTaUS8X1QndfKQphquZVhfKhVBA8etZaMwsoclfB8/e8mCSMUn+2s7/LYf9i9QHqlVdoS2ssTqJT+Rcfs9/Wa"
result = PrpCrypt().decrypt(key,paymentResult)
print(result)
val paymentDecrypted = decryptWithAES(callbackKey, paymentResult)
fun decryptWithAES(key: String, strToDecrypt: String?): String? {
Security.addProvider(BouncyCastleProvider())
val keyBytes: ByteArray
try {
keyBytes = key.toByteArray(charset("UTF8"))
val skey = SecretKeySpec(keyBytes, "AES")
val input = org.bouncycastle.util.encoders.Base64
.decode(strToDecrypt?.trim { it <= ' ' }?.toByteArray(charset("UTF8")))
synchronized(Cipher::class.java) {
val cipher = Cipher.getInstance("AES/ECB/PKCS7Padding")
cipher.init(Cipher.DECRYPT_MODE, skey)
val plainText = ByteArray(cipher.getOutputSize(input.size))
var ptLength = cipher.update(input, 0, input.size, plainText, 0)
ptLength += cipher.doFinal(plainText, ptLength)
val decryptedString = String(plainText)
return decryptedString.trim { it <= ' ' }
}
} catch (uee: UnsupportedEncodingException) {
uee.printStackTrace()
} catch (ibse: IllegalBlockSizeException) {
ibse.printStackTrace()
} catch (bpe: BadPaddingException) {
bpe.printStackTrace()
} catch (ike: InvalidKeyException) {
ike.printStackTrace()
} catch (nspe: NoSuchPaddingException) {
nspe.printStackTrace()
} catch (nsae: NoSuchAlgorithmException) {
nsae.printStackTrace()
} catch (e: ShortBufferException) {
e.printStackTrace()
}
return null
}
Callback Response Parameters
Content of Payment Result
Name | Type | Mandatary | Description |
---|---|---|---|
totalAmount | Integer | Yes | |
createdAt | String | Yes | yyyyMMdd HHmmss |
transactionStatus | String | Yes | SUCCESS, ERROR, CANCELLED, TIMEOUT, DECLINED, SYSTEM_ERROR |
methodName | String | Yes | |
providerName | String | Yes | |
customerName | String | Yes | |
merchantOrderId | String | Yes | |
transactionId | String | Yes |