Webhook Signature

Webhook Signature

Signature Fields

  • Timestamp: Retrieved from the asynchronous notification request header
  • Request Method: Fixed value POST
  • Request Path: The callbackUrl provided by the merchant when placing an order, only the path without the domain
  • Request Body: Request parameters

(1) Sort the request parameters in ascending alphabetical order by parameter name, excluding empty values, signature, and newSignature.

(2) Generate the string to be signed with the fixed order: timestamp+requestMethod+requestPath+requestBody.

Generate Signature

public class SignCheck {

    public static String signCheck(String content, String secretkey) throws NoSuchAlgorithmException, InvalidKeyException {
        Base64.Encoder base = Base64.getEncoder();
        String signVal = base.encodeToString(sha256(content.getBytes(StandardCharsets.UTF_8), secretkey.getBytes(StandardCharsets.UTF_8)));
        return signVal;
    }

    public static byte[] sha256(byte[] message, byte[] secret) throws NoSuchAlgorithmException, InvalidKeyException {
        Mac sha256_HMAC = Mac.getInstance("HmacSha256");
        SecretKeySpec secretKey = new SecretKeySpec(secret, "HmacSha256");
        sha256_HMAC.init(secretKey);
        return sha256_HMAC.doFinal(message);
    }

    public static void main(String[] args) throws Exception {
        String content = "1700549311596POST/onRamp/callback{"address": "TGNMkik3nPaioVJdkE7qEixWr9cUvsyT5g","crypto": "USDT","fiat": "SGD"}";
        String secretkey = "XXXXX";
        String sign = signCheck(content, secretkey);
        System.out.println(sign);
    }
}

Generate the string to be signed "Example"

  1. Retrieve the webhook parameters:
{
	"amount": "15.00000000",
	"orderNo": "***",
	"address": "***",
	"payTime": "2024-09-27 17:59:27",
	"signature": "f13fb8137f2c999c5932261de9bc8668b0a7b014",
	"rawRampFee": "0.998500",
	"merchantOrderNo": "***",
	"crypto": "USDT",
	"network": "TRX",
	"rampFeeUnit": "USD",
	"cryptoPrice": "0.00000000",
	"payType": "CREDIT_CARD",
	"rampFee": "0.99000000",
	"cryptoQuantity": "12.93",
	"appId": "f83Is2y7L425rxl8",
	"fiat": "USD",
	"newSignature": "+T2BJ1S2X+ffRXoF+q5c/aqgZSyjGXt7Oh073UXLti0=",
	"email": "***@gmail.com",
	"status": "PAY_SUCCESS",
	"rampFeeInUSD": "0.99"
}
  1. Remove empty values, signature, and newSignature, then sort the parameters:
{
	"address": "***",
	"amount": "15.00000000",
	"appId": "f83Is2y7L425rxl8",
	"crypto": "USDT",
	"cryptoPrice": "0.00000000",
	"cryptoQuantity": "12.93",
	"email": "***@gmail.com",
	"fiat": "USD",
	"merchantOrderNo": "***",
	"network": "TRX",
	"orderNo": "***",
	"payTime": "2024-09-27 17:59:27",
	"payType": "CREDIT_CARD",
	"rampFee": "0.99000000",
	"rampFeeInUSD": "0.99",
	"rampFeeUnit": "USD",
	"rawRampFee": "0.998500",
	"status": "PAY_SUCCESS"
}
  1. Retrieve the timestamp parameter from the request header and the callbackUrl path:
  • timestamp: 1727431167633
  • requestPath: /alchemypay-on-ramp
  1. Concatenate the string to be signed:

1727431167633POST/alchemypay-on-ramp{"address":"***","amount":"15.00000000","appId":"f83Is2y7L425rxl8","crypto":"USDT","cryptoPrice":"0.00000000","cryptoQuantity":"12.93","email":"***@gmail.com","fiat":"USD","merchantOrderNo":"***","network":"TRX","orderNo":"***","payTime":"2024-09-27 17:59:27","payType":"CREDIT_CARD","rampFee":"0.99000000","rampFeeInUSD":"0.99","rampFeeUnit":"USD","rawRampFee":"0.998500","status":"PAY_SUCCESS"}