Java Example
Example:
POST /payIn/orders/createAndPay, sign data istimestamp|nonce|rawBody.
java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.UUID;
public class PayApiClient {
static String sign(String timestamp, String nonce, String body, String secret) throws Exception {
String signData = timestamp + "|" + nonce + "|" + body;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] hash = mac.doFinal(signData.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash);
}
public static void main(String[] args) throws Exception {
String body = "{\"merchantOrderNo\":\"M202412220001\",\"amount\":\"100.00\",\"currency\":\"USD\","
+ "\"methodCode\":\"INTERNATIONAL_CARD\",\"methodData\":{\"cardNumber\":\"4111111111111111\","
+ "\"expiryMonth\":\"12\",\"expiryYear\":\"27\",\"securityCode\":\"123\"}}";
String timestamp = String.valueOf(System.currentTimeMillis());
String nonce = UUID.randomUUID().toString().replace("-", "");
String sign = sign(timestamp, nonce, body, "sk_test_9f3b8a2d7c1e4f6a8b0c2d4e6f8a1b3c");
// Send the request with headers:
// X-Merchant-Id, X-Timestamp, X-Nonce, X-Sign
}
}Verify signature (callback)
rawBody is the exact JSON string received in the callback.
java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
public class WebhookVerifier {
static String sign(String timestamp, String nonce, String body, String secret) throws Exception {
String signData = timestamp + "|" + nonce + "|" + body;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] hash = mac.doFinal(signData.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash);
}
static boolean verify(String timestamp, String nonce, String rawBody, String secret, String signHeader)
throws Exception {
String expected = sign(timestamp, nonce, rawBody, secret);
return MessageDigest.isEqual(expected.getBytes(StandardCharsets.UTF_8),
signHeader.getBytes(StandardCharsets.UTF_8));
}
public static void main(String[] args) throws Exception {
String rawBody = "{\"payNo\":\"P202312230001\",\"tradeStatus\":\"SUCCESS\"}";
String timestamp = "1734921005000";
String nonce = "b2b2f3b6a6f24a4ba3dcd0e777c9a888";
String signHeader = "base64_signature_from_header";
boolean ok = verify(timestamp, nonce, rawBody, "sk_test_9f3b8a2d7c1e4f6a8b0c2d4e6f8a1b3c", signHeader);
System.out.println(ok);
}
}