Signature Specification
MD5 will be deprecated on 2026/03/31. Please migrate to HMAC-SHA256 before this date. Requests using MD5 will return errors after deprecation.
To ensure secure data transmission, we verify request parameters using digital signatures.
Signature Algorithms
We support the following signature algorithms:
| Algorithm | sign_type Value | Recommendation | Description |
|---|---|---|---|
| HMAC-SHA256 | HMAC-SHA256 | ⭐ Recommended | More secure signing algorithm |
| MD5 | MD5 or omit | Legacy | For backward compatibility |
We strongly recommend using HMAC-SHA256. MD5 is considered insecure by modern cryptographic standards.
How to Choose
Add the sign_type parameter to your request:
{
"platform_id": "PF0002",
"sign_type": "HMAC-SHA256",
"sign": "..."
}
If sign_type is omitted, MD5 is used by default for backward compatibility.
Test Merchant Information
| Field | Value |
|---|---|
| Merchant ID (platform_id) | PF0002 |
| Platform Key (platform_key) | ThisIsYourSecretKey123 |
HMAC-SHA256 Signature (Recommended)
Signing Rules
- Sort parameters by key in ASCII ascending order
- Exclude:
sign,sign_type, and empty values - Concatenate as
key=valuepairs joined by& - Sign using HMAC-SHA256 with platform_key as the secret
- Convert result to lowercase 64-character hex string
HMAC-SHA256 uses the key directly for signing. Do NOT append the key to the string.
Deposit Example
Request Parameters:
{
"platform_id": "PF0002",
"service_id": "SVC0001",
"payment_cl_id": "DEVPM00014581",
"amount": "50000",
"notify_url": "https://your-domain.com/callback",
"request_time": "1595504136",
"sign_type": "HMAC-SHA256"
}
Step 1: Sort and concatenate (excluding sign, sign_type)
amount=50000¬ify_url=https://your-domain.com/callback&payment_cl_id=DEVPM00014581&platform_id=PF0002&request_time=1595504136&service_id=SVC0001
Step 2: HMAC-SHA256 Sign
Sign using key ThisIsYourSecretKey123.
Code Examples
cURL
# 1. Concatenate sorted parameters (excluding sign and sign_type)
PARAM_STR="amount=50000¬ify_url=https://your-domain.com/callback&payment_cl_id=DEVPM00014581&platform_id=PF0002&request_time=1595504136&service_id=SVC0001"
PLATFORM_KEY="ThisIsYourSecretKey123"
# 2. HMAC-SHA256 sign
SIGN=$(echo -n "$PARAM_STR" | openssl dgst -sha256 -hmac "$PLATFORM_KEY" | awk '{print $2}')
echo $SIGN
Python
import hmac
import hashlib
def generate_sign_hmac_sha256(params: dict, platform_key: str) -> str:
filtered = {k: v for k, v in params.items()
if v and k not in ['sign', 'sign_type']}
sorted_keys = sorted(filtered.keys())
param_str = '&'.join([f'{k}={filtered[k]}' for k in sorted_keys])
return hmac.new(
platform_key.encode('utf-8'),
param_str.encode('utf-8'),
hashlib.sha256
).hexdigest().lower()
Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
public class SignatureUtil {
public static String generateHmacSha256(Map<String, String> params, String key) {
TreeMap<String, String> filtered = new TreeMap<>();
for (Map.Entry<String, String> e : params.entrySet()) {
if (e.getValue() != null && !e.getValue().isEmpty()
&& !e.getKey().equals("sign") && !e.getKey().equals("sign_type")) {
filtered.put(e.getKey(), e.getValue());
}
}
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> e : filtered.entrySet()) {
if (sb.length() > 0) sb.append("&");
sb.append(e.getKey()).append("=").append(e.getValue());
}
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256"));
byte[] hash = mac.doFinal(sb.toString().getBytes("UTF-8"));
StringBuilder hex = new StringBuilder();
for (byte b : hash) hex.append(String.format("%02x", b));
return hex.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
PHP
<?php
function generateSignHmacSha256(array $params, string $platformKey): string {
$filtered = array_filter($params, function($v, $k) {
return !empty($v) && !in_array($k, ['sign', 'sign_type']);
}, ARRAY_FILTER_USE_BOTH);
ksort($filtered);
$paramStr = http_build_query($filtered, '', '&');
return strtolower(hash_hmac('sha256', $paramStr, $platformKey));
}
?>
Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"sort"
"strings"
)
func GenerateSignHmacSha256(params map[string]string, platformKey string) string {
var keys []string
for k, v := range params {
if v != "" && k != "sign" && k != "sign_type" {
keys = append(keys, k)
}
}
sort.Strings(keys)
var pairs []string
for _, k := range keys {
pairs = append(pairs, k+"="+params[k])
}
paramStr := strings.Join(pairs, "&")
h := hmac.New(sha256.New, []byte(platformKey))
h.Write([]byte(paramStr))
return strings.ToLower(hex.EncodeToString(h.Sum(nil)))
}
JavaScript
const crypto = require('crypto');
function generateSignHmacSha256(params, platformKey) {
const filtered = Object.entries(params)
.filter(([k, v]) => v && k !== 'sign' && k !== 'sign_type')
.sort(([a], [b]) => a.localeCompare(b));
const paramStr = filtered.map(([k, v]) => `${k}=${v}`).join('&');
return crypto
.createHmac('sha256', platformKey)
.update(paramStr)
.digest('hex')
.toLowerCase();
}
MD5 Signature (Legacy) - Click to expand
MD5 is only kept for backward compatibility. New merchants should use HMAC-SHA256.
Signing Rules
- Sort parameters by key in ASCII order, exclude
sign,sign_type, empty values - Concatenate as
key=value&key=value - Append key:
&{platform_key}(NOT&key={platform_key}) - MD5 hash, convert to lowercase 32-character string
Example
Concatenated string with key:
amount=50000¬ify_url=https://your-domain.com/callback&payment_cl_id=DEVPM00014581&platform_id=PF0002&request_time=1595504136&service_id=SVC0001&ThisIsYourSecretKey123
MD5 Result: 49be5fa304b5f536c6e2ea89435e211a
Verify Callback Signature
When receiving callback notifications, verify the signature using the same algorithm.
If the callback contains sign_type, use that algorithm; otherwise use MD5.
Always verify callback signatures to prevent forged callback attacks.
Common Issues
Signature Error (error_code: 0004)
Common causes:
- Wrong MD5 key format - Should be
&{platform_key}, NOT&key={platform_key} - Not excluding sign_type - Both
signandsign_typeshould be excluded - Encoding issues - Ensure UTF-8 encoding