Skip to content

Signature Authentication ​

Overview ​

All API requests must be authenticated and signed to ensure security and integrity.

Authentication ​

Header Authentication ​

Each request must include the following headers:

x-access-keystringRequired

Merchant access identifier assigned by the platform

signaturestringRequired

Request signature

Example

http
POST /api/v2/pay/submit
Content-Type: application/json
x-access-key: MERCHANT_001
signature: a1b2c3d4e5f6...

Signature Algorithm ​

Steps to Calculate the Signature ​

Step 1: Prepare Parameters ​

Collect all body parameters and exclude:

  • The signature field itself
  • Parameters whose values are null or empty strings

Example body parameters

json
{
  "timestamp": "1742205605123",
  "merchantOrderNo": "PHC202604170001",
  "orderAmount": "1200",
  "payMethod": "MAYA",
  "callbackUrl": "https://merchant.example.com/payments/notify",
  "redirectUrl": "https://merchant.example.com/payments/return"
}

Step 2: Sort Parameters ​

Sort all parameters by parameter name in alphabetical order (a-z).

Example

After sorting:
callbackUrl, merchantOrderNo, orderAmount, payMethod, redirectUrl, timestamp

Step 3: Concatenate the String ​

Concatenate the sorted parameters in key=value format, joined by &. Use the original string values from the request when building the signing string.

Example

callbackUrl=https://merchant.example.com/payments/notify&merchantOrderNo=PHC202604170001&orderAmount=1200&payMethod=MAYA&redirectUrl=https://merchant.example.com/payments/return&timestamp=1742205605123

Step 4: Append the Secret Key ​

Append the merchant secret key to the end of the concatenated string.

Example

callbackUrl=https://merchant.example.com/payments/notify&merchantOrderNo=PHC202604170001&orderAmount=1200&payMethod=MAYA&redirectUrl=https://merchant.example.com/payments/return&timestamp=1742205605123{SECRET_KEY}

Step 5: Calculate the Hash ​

Use the SHA256 algorithm to calculate the hash.

Step 6: Convert to Lowercase ​

Convert the hash result to a lowercase hexadecimal string.

Final signature

If the example above uses demo_secret_key_ph as the secret key, the signature result is:

baaa22c91470a152155a34284dbf32d6e21bd761a4067755db3d70e5bad28c30

Async callback signature verification follows the same rule. The callback signature field is also signature, and the signature field itself must be excluded during verification.


Signature Example Code ​

Java ​

java
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;

public class SignUtil {

    public static String sign(Map<String, Object> params, String secretKey) throws NoSuchAlgorithmException {
        TreeMap<String, String> sortedParams = new TreeMap<>();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value != null && !"".equals(value) && !"signature".equals(key)) {
                sortedParams.put(key, value.toString());
            }
        }

        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(entry.getKey()).append("=").append(entry.getValue());
        }

        sb.append(secretKey);

        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] hash = md.digest(sb.toString().getBytes(StandardCharsets.UTF_8));

        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) {
            String hex = Integer.toHexString(b & 0xff);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }

        return hexString.toString().toLowerCase();
    }
}

Node.js ​

javascript
const crypto = require('crypto');

function generateSignature(params, secretKey) {
  const filteredParams = {};
  for (const [key, value] of Object.entries(params)) {
    if (value !== null && value !== '' && key !== 'signature') {
      filteredParams[key] = value;
    }
  }

  const sortedKeys = Object.keys(filteredParams).sort();

  const signStr = sortedKeys
    .map(key => `${key}=${filteredParams[key]}`)
    .join('&');

  return crypto.createHash('sha256').update(signStr + secretKey).digest('hex').toLowerCase();
}

Java Usage Example ​

java
Map<String, Object> params = new HashMap<>();
params.put("timestamp", "1742205605123");
params.put("merchantOrderNo", "PHC202604170001");
params.put("orderAmount", "1200");
params.put("payMethod", "MAYA");
params.put("callbackUrl", "https://merchant.example.com/payments/notify");
params.put("redirectUrl", "https://merchant.example.com/payments/return");

String signature = SignUtil.sign(params, "demo_secret_key_ph");
System.out.println(signature);
// baaa22c91470a152155a34284dbf32d6e21bd761a4067755db3d70e5bad28c30

Node.js Usage Example ​

javascript
const params = {
  timestamp: '1742205605123',
  merchantOrderNo: 'PHC202604170001',
  orderAmount: '1200',
  payMethod: 'MAYA',
  callbackUrl: 'https://merchant.example.com/payments/notify',
  redirectUrl: 'https://merchant.example.com/payments/return',
};

const signature = generateSignature(params, 'demo_secret_key_ph');
console.log(signature);
// baaa22c91470a152155a34284dbf32d6e21bd761a4067755db3d70e5bad28c30