Skip to content

Java Example

Example: POST /payIn/orders/createAndPay, sign data is timestamp|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);
    }
}