Skip to content

Signature Mechanism

Signature Algorithm

The fields included in the signature are:

  • apiPath – the request URI (required)
  • body – the request payload (required), as a JSON string
  • x-api-key – identical to appId (required)
  • x-api-timestamp – the current timestamp in milliseconds (required)
  • Any additional parameters present in the URI

Description for implementing:

  • Place every parameter name and value listed above into a map, e.g. contentMap, then sort the map’s keys in ascending order.
  • Serialize the ordered map to a JSON string.
  • Encrypt the JSON string with HMAC‑SHA256 using your secret key.
  • Base64‑encode the resulting digest, the encoded string is the final signature string.

For example,

shell

curl -H 'x-api-key: key' \
     -H 'x-api-timestamp: 1744636844000' \
     -H 'x-api-signature: 0xb7Kxxxx=' \
      'https://{HOST}/path/to/pay?param1=test1&param2=test2' \
      -d '{"data":"test"}'

curl -H 'x-api-key: key' \
     -H 'x-api-timestamp: 1744636844000' \
     -H 'x-api-signature: 0xb7Kxxxx=' \
      'https://{HOST}/path/to/pay?param1=test1&param2=test2' \
      -d '{"data":"test"}'

The contentMap after JSON serialization is as follows:

json
{
    "apiPath": "/path/to/pay",
    "body": {
        "data": "test"
    },
    "param1": "test1",
    "param2": "test2",
    "x-api-key": "key",
    "x-api-timestamp": "17200001"
}
{
    "apiPath": "/path/to/pay",
    "body": {
        "data": "test"
    },
    "param1": "test1",
    "param2": "test2",
    "x-api-key": "key",
    "x-api-timestamp": "17200001"
}

Finally, encrypt the above JSON string.

Code Examples

go

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "net/url"
    "sort"
)

func GenSign(appId, apiSecret, pathUrl, payload string, tm int64) string {
	// Construct a map 
	path := ""
	contentMap := make(map[string]string)
	if u, err := url.Parse(pathUrl); err == nil {
		path = u.Path
		for k, v := range u.Query() {
			if len(v) > 0 {
				contentMap[k] = v[0]
			}
		}
	}
	contentMap["x-api-key"] = appId
	contentMap["x-api-timestamp"] = fmt.Sprintf("%d", tm)
	contentMap["apiPath"] = path
	contentMap["body"] = payload

	// Sort the map’s keys in ascending order
	keys := make([]string, 0, len(contentMap))
	for k := range contentMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	// Serialize the ordered map to a JSON string
	orderedMap := make(map[string]string)
	for _, k := range keys {
		orderedMap[k] = contentMap[k]
	}
	content, _ := json.Marshal(orderedMap)

	// Encrypt by SHA256 with apiSecret
	mac := hmac.New(sha256.New, []byte(apiSecret))
	mac.Write(content)
	
	// Encode by base64
	return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

// Invoke
GenSign("A123456", "ABC123", "/path/to/pay?param1=test1&param2=test2", `{"data":"test"}`, time.Now().UnixMilli())

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "net/url"
    "sort"
)

func GenSign(appId, apiSecret, pathUrl, payload string, tm int64) string {
	// Construct a map 
	path := ""
	contentMap := make(map[string]string)
	if u, err := url.Parse(pathUrl); err == nil {
		path = u.Path
		for k, v := range u.Query() {
			if len(v) > 0 {
				contentMap[k] = v[0]
			}
		}
	}
	contentMap["x-api-key"] = appId
	contentMap["x-api-timestamp"] = fmt.Sprintf("%d", tm)
	contentMap["apiPath"] = path
	contentMap["body"] = payload

	// Sort the map’s keys in ascending order
	keys := make([]string, 0, len(contentMap))
	for k := range contentMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	// Serialize the ordered map to a JSON string
	orderedMap := make(map[string]string)
	for _, k := range keys {
		orderedMap[k] = contentMap[k]
	}
	content, _ := json.Marshal(orderedMap)

	// Encrypt by SHA256 with apiSecret
	mac := hmac.New(sha256.New, []byte(apiSecret))
	mac.Write(content)
	
	// Encode by base64
	return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

// Invoke
GenSign("A123456", "ABC123", "/path/to/pay?param1=test1&param2=test2", `{"data":"test"}`, time.Now().UnixMilli())
php
<?php

function GenSign(string $appId, string $apiSecret, string $pathUrl, string $payload, int $tm): string {
    
    // Construct a map 
    $contentMap = [];
    $parts      = parse_url($pathUrl);
    $path = $parts['path'] ?? '';
    if (!empty($parts['query'])) {
        parse_str($parts['query'], $queryArr);
        foreach ($queryArr as $k => $v) {
            $contentMap[$k] = (string)$v;
        }
    }
    $contentMap['x-api-key']      = $appId;
    $contentMap['x-api-timestamp'] = (string)$tm; 
    $contentMap['apiPath']        = $path;
    $contentMap['body']           = $payload;

    // Sort the map’s keys in ascending order
    ksort($contentMap, SORT_STRING);

    // Serialize the ordered map to a JSON string
    $json = json_encode(
        $contentMap,
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
    );

    // Encrypt by SHA256 with apiSecret
    $raw  = hash_hmac('sha256', $json, $apiSecret, true);
    
	// Encode by base64
    return base64_encode($raw);
}

// Invoke
GenSign("A123456", "ABC123", "/path/to/pay?param1=test1&param2=test2", '{"data":"test"}', floor(microtime(true) * 1000))
<?php

function GenSign(string $appId, string $apiSecret, string $pathUrl, string $payload, int $tm): string {
    
    // Construct a map 
    $contentMap = [];
    $parts      = parse_url($pathUrl);
    $path = $parts['path'] ?? '';
    if (!empty($parts['query'])) {
        parse_str($parts['query'], $queryArr);
        foreach ($queryArr as $k => $v) {
            $contentMap[$k] = (string)$v;
        }
    }
    $contentMap['x-api-key']      = $appId;
    $contentMap['x-api-timestamp'] = (string)$tm; 
    $contentMap['apiPath']        = $path;
    $contentMap['body']           = $payload;

    // Sort the map’s keys in ascending order
    ksort($contentMap, SORT_STRING);

    // Serialize the ordered map to a JSON string
    $json = json_encode(
        $contentMap,
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
    );

    // Encrypt by SHA256 with apiSecret
    $raw  = hash_hmac('sha256', $json, $apiSecret, true);
    
	// Encode by base64
    return base64_encode($raw);
}

// Invoke
GenSign("A123456", "ABC123", "/path/to/pay?param1=test1&param2=test2", '{"data":"test"}', floor(microtime(true) * 1000))