Validating Payment Response with Signature
In order to check whether the response received by your client was sent by the Nimbbl server, you need to validate the signature received as part of the response. To validate this signature, you will also need to generate a signature on your server and then compare the generated signature with the one received from Nimbbl.
- This is a mandatory step to check the veracity of the response received
- It allows you to be protected from tampering frauds
- This should be performed on your server
Attributes for Creating the Signature - Transaction
The following attributes will be required to generate the signature on your server
| Attribute | Description |
|---|---|
signature_version | Use the signature_version in the transaction object returned by Nimbbl for the payment in the response |
invoice_id | Use the invoice_id of the order that is generated on your server, returned by Nimbbl in the response |
transaction_id | Use the transaction_id in the transaction object returned by Nimbbl for the payment in the response |
secret_key | The secret_key is generated from the Command Center. Available on your server |
transaction_amount | Use the transaction_amount in the transaction object returned by Nimbbl in the response. Always use the transaction_amount with 2 decimal places. |
transaction_currency | Use the transaction_currency in the transaction object returned by Nimbbl in the response |
status | Use the status in the transaction object returned by Nimbbl in the response |
transaction_type | Use the transaction_type in the transaction object returned by Nimbbl in the response |
Attributes for Creating the Signature - Payment Link
The following attributes will be required to generate the payment link signature on your server
| Attribute | Description |
|---|---|
signature_version | Use the signature_version returned by Nimbbl in the webhook/callback response |
invoice_id | Use the invoice_id of the payment link returned by Nimbbl in the response |
payment_link_status | Use the payment link status returned by Nimbbl in the response |
payment_link_currency | Use the payment link currency returned by Nimbbl in the response |
payment_link_total_amount | Use the payment link total_amount returned by Nimbbl in the response. Always use the amount with 2 decimal places. |
payment_link_hash | Use the payment_link_hash returned by Nimbbl in the response |
secret_key | The secret_key is generated from the Command Center. Available on your server |
Generating the HMAC Signature
Use the SHA256 algorithm to construct a HMAC hex digest as shown below:
Some JSON libraries convert the whole float numbers to integers (3.0 may be converted to 3).
Hence, we recommend to always convert the transaction_amount field into float with 2 decimal places.
However, if the transaction_amount has more than 2 decimal places, trim the transaction_amount to 2 decimal places.
For example
- If the
transaction_amountis 3, use thetransaction_amountvalue as 3.00 for signature creation. - If the
transaction_amountis 3.1, use thetransaction_amountvalue as 3.10 for signature creation. - If the
transaction_amountis 3.12, use thetransaction_amountvalue as 3.12 for signature creation. - If the
transaction_amountis 3.129, use thetransaction_amountvalue as 3.12 for signature creation.
- Java
- C#
- PHP
- Python
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
public class HmacUtils {
public static String hmacSha256(String signatureData, String secretKey) throws NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKeySpec);
byte[] raw = mac.doFinal(signatureData.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : raw) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
String signatureVersion = "v3";
String generatedSignature;
String signatureData;
if ("v3".equals(signatureVersion)) {
signatureData = "invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR|succeeded|payment";
} else {
throw new IllegalArgumentException("Invalid signature version");
}
String accessSecret = "<YOUR_ACCESS_SECRET>";
generatedSignature = hmacSha256(signatureData, accessSecret);
String expectedSignature = "d743d28875603deeb206d3d742bec9494c1f61212a84217649f233549a279259";
if (generatedSignature.equals(expectedSignature)) {
System.out.println("Matched");
}
}
}
using System;
using System.Security.Cryptography;
using System.Text;
class HmacUtils
{
public static string HmacSha256(string signatureData, string secretKey)
{
byte[] keyBytes = Encoding.UTF8.GetBytes(secretKey);
byte[] dataBytes = Encoding.UTF8.GetBytes(signatureData);
using (var hmac = new HMACSHA256(keyBytes))
{
byte[] hashBytes = hmac.ComputeHash(dataBytes);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
}
static void Main()
{
string signatureVersion = "v3";
string generatedSignature;
string signatureData;
if (signatureVersion == "v3")
{
signatureData = "invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR|succeeded|payment";
}
else
{
throw new ArgumentException("Invalid signature version");
}
string accessSecret = "<YOUR_ACCESS_SECRET>";
generatedSignature = HmacSha256(signatureData, accessSecret);
string expectedSignature = "d743d28875603deeb206d3d742bec9494c1f61212a84217649f233549a279259";
if (generatedSignature == expectedSignature)
{
Console.WriteLine("Matched");
}
}
}
<?php
function hmac_sha256($signatureData, $secretKey) {
$raw = utf8_encode($signatureData);
$key = utf8_encode($secretKey);
return hash_hmac('sha256', $raw, $key);
}
$signatureVersion = 'v3';
$generatedSignature = '';
$signatureData = '';
if ($signatureVersion === 'v3') {
$signatureData = 'invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR|succeeded|payment';
}
$accessSecret = '<YOUR_ACCESS_SECRET>';
$generatedSignature = hmac_sha256($signatureData, $accessSecret);
$expectedSignature = 'd743d28875603deeb206d3d742bec9494c1f61212a84217649f233549a279259';
if ($generatedSignature === $expectedSignature) {
echo "Matched\n";
}
?>
import hmac
import hashlib
def _hmac_sha256(signature_data, secret_key):
raw = signature_data.encode("utf-8")
key = secret_key.encode("utf-8")
return hmac.new(key=key, msg=raw, digestmod=hashlib.sha256).hexdigest()
if signature_version == 'v3':
generated_signature = _hmac_sha256(
"invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR|succeeded|payment",
"<YOUR_ACCESS_SECRET>",
)
signature = "d743d28875603deeb206d3d742bec9494c1f61212a84217649f233549a279259"
if generated_signature == signature:
print("Matched")
Comparing the Signatures
The signature you generate on your server should match the signature returned to you by the Checkout in order to verify that the payment received is from an authentic source.
- V3 Signature - Transaction
- V3 Signature - Payment Link
If the signature_version returned in the Webhook/Callback is v3 then verify the signature using the logic mentioned below:
generated_signature = hmac_sha256(invoice_id + "|" + transaction_id + "|" + transaction_amount + "|" + transaction_currency + "|" + status + "|" + transaction_type, <your_secret_key>);
if (generated_signature == signature) {
payment is successful
}
If the signature_version returned in the Webhook/Callback is v3 then verify the signature using the logic mentioned below:
generated_signature = hmac_sha256(invoice_id + "|" + payment_link_status + "|" + payment_link_currency + "|" + payment_link_total_amount + "|" + payment_link_hash, <your_secret_key>);
if (generated_signature == signature) {
payment is successful
}
If the signature you generate doesn't match the signature returned to you, please mark the Order as failed on your end. You should also raise a request for an investigation of this order on [email protected]