Signature Parameters

DescriptionDescriptionRemarks
timestampThirteen-digit timestamp1699261493465
httpMethodRequest Method GET/POSTrequest method must be in uppercase
requestPathRequest Pathexcluding the domain name
bodyStringRequest BodyGET:empty
POST:request body

Step 1: Generate An Encrypted String

The signature string is fixed as follows: timestamp + httpMethod + requestPath + bodyString.

For the parameters in requestPath,bodyString, sort them in dictionary order and remove any empty values.

Finally, encrypt using HMAC SHA256 with the SecretKey and encode it using Base64 to obtain the sign.

request method:POST

Example:Create Order

  • timestamp:1699261493465
  • httpMethod:POST
  • requestPath:/open/api/v4/merchant/trade/create
  • bodyString:
{
    "side": "BUY",
    "cryptoCurrency": "USDT",
    "address": "TSx82tWNWe5Ns6t3w94Ye3Gt6E5KeHSoP8",
    "network": "TRX",
    "fiatCurrency": "USD",
    "amount": "100",
    "depositType": 2,
    "payWayCode": "10001",
    "alpha2": "US",
    "redirectUrl": "",
    "callbackUrl": "http://payment.jyoumoney.com/alchemyRamp/pay/callback?tradeNo=DZ02207091800356504"
}

(1) Sort bodyString

{"address":"TSx82tWNWe5Ns6t3w94Ye3Gt6E5KeHSoP8","alpha2":"US","amount":"100","callbackUrl":"http://payment.jyoumoney.com/alchemyRamp/pay/callback?tradeNo=DZ02207091800356304","cryptoCurrency":"USDT","depositType":2,"fiatCurrency":"USD","network":"TRX","payWayCode":"10001","side":"BUY"}

(2) Signature String:

1699261493465POST/open/api/v4/merchant/trade/create{"address":"TSx82tWNWe5Ns6t3w94Ye3Gt6E5KeHSoP8","alpha2":"US","amount":"100","callbackUrl":"http://payment.jyoumoney.com/alchemyRamp/pay/callback?tradeNo=DZ02207091800356304","cryptoCurrency":"USDT","depositType":2,"fiatCurrency":"USD","network":"TRX","payWayCode":"10001","side":"BUY"}

request method:GET

Example:Query Order

  • timestamp:1699261493465
  • httpMethod:GET
  • requestPath:/open/api/v4/merchant/query/trade?orderNo=1028577684629876736&side=BUY&[email protected]
  • bodyString:

(1) Sort requestPath

[email protected]&orderNo=1028577684629876736&side=BUY

(2) Signature String:

1699261493465GET/open/api/v4/merchant/query/[email protected]&orderNo=1028577684629876736&side=BUY

Step Two: Generate Your Signature

Use the encrypted string and secret as parameters to generate a signature as follows

public class AchSign {


    public static String apiSign(String timestamp, String method, String path, Map<String, String> paramMap, String secretkey) throws NoSuchAlgorithmException, InvalidKeyException {
        String content = timestamp + method.toUpperCase() + path + getJsonBody(paramMap);
        Base64.Encoder base = Base64.getEncoder();
        String signVal = base.encodeToString(sha256(content.getBytes(StandardCharsets.UTF_8), secretkey.getBytes(StandardCharsets.UTF_8)));
        return signVal;
    }

    public static byte[] sha256(byte[] message, byte[] secret) throws NoSuchAlgorithmException, InvalidKeyException {
        Mac sha256_HMAC = Mac.getInstance("HmacSha256");
        SecretKeySpec secretKey = new SecretKeySpec(secret, "HmacSha256");
        sha256_HMAC.init(secretKey);
        return sha256_HMAC.doFinal(message);
    }


    private static String getJsonBody(Map<String,String> parameters) {
        if (parameters == null || parameters.isEmpty()) {
            return "";
        }
        parameters = removeEmptyKeys(parameters);
        parameters = (Map) sortObject(parameters);
        return JSON.toJSONString(parameters);
    }
    

    private static Map removeEmptyKeys(Map map) {
        if (map.isEmpty()) {
            return map;
        }
        Map retMap = new HashMap();
        Iterator<Map.Entry> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            if (entry.getValue() != null && !entry.getValue().equals("")) {
                retMap.put(entry.getKey(), entry.getValue());
            }
        }
        return retMap;
    }

    private static Object sortObject(Object obj) {
        if (obj instanceof Map) {
            return sortMap((Map) obj);
        } else if (obj instanceof List) {
            sortList((List) obj);
            return obj;
        }
        return null;
    }

    private static Map sortMap(Map map) {
        if (map.isEmpty()) {
            return null;
        }
        SortedMap<String, Object> sortedMap = new TreeMap<>(removeEmptyKeys(map));
        for (String sortKey : sortedMap.keySet()) {
            if (sortedMap.get(sortKey) instanceof Map) {
                sortedMap.put(sortKey, sortMap((Map) sortedMap.get(sortKey)));
            } else if (sortedMap.get(sortKey) instanceof List) {
                sortedMap.put(sortKey, sortList((List) sortedMap.get(sortKey)));
            }
        }
        return sortedMap;
    }

    private static List sortList(List list) {
        if (list.isEmpty()) {
            return null;
        }
        List objectList = new ArrayList();

        List intList = new ArrayList();
        List floatList = new ArrayList();
        List stringList = new ArrayList();

        List jsonArray = new ArrayList();
        for (Object obj : list) {
            if (obj instanceof Map || obj instanceof List) {
                jsonArray.add(obj);
            } else if (obj instanceof Integer) {
                intList.add(obj);
            } else if (obj instanceof BigDecimal) {
                floatList.add(obj);
            } else if (obj instanceof String) {
                stringList.add(obj);
            } else {
                intList.add(obj);
            }
        }

        Collections.sort(intList);
        Collections.sort(floatList);
        Collections.sort(stringList);

        objectList.addAll(intList);
        objectList.addAll(floatList);
        objectList.addAll(stringList);
        objectList.addAll(jsonArray);

        list.clear();
        list.addAll(objectList);


        List retList = new ArrayList();

        for (Object obj : list) {
            if (obj instanceof Map) {
                retList.add(sortMap((Map) obj));
            } else if (obj instanceof List) {
                retList.add(sortList((List) obj));
            } else {
                retList.add(obj);
            }
        }
        return retList;
    }

    public static void main(String[] args) throws Exception {
        String timestamp = String.valueOf(System.currentTimeMillis());
        String method = "";
        String path = "";
        Map map = new hashMap();
        String secretkey = "";
        String sign = apiSign(timestamp, method, path, map, secretkey);
        System.out.println(timestamp);
        System.out.println(sign);
        System.out.println(URLEncoder.encode(sign));

    }

}
import base64
import hashlib
import hmac
import json
from urllib.parse import urlparse, urlencode

def api_sign(timestamp, method, request_url, body, secretkey):
    content = timestamp + method.upper() + get_path(request_url) + get_json_body(body)
    print(content)
    key = secretkey.encode('utf-8')
    message = content.encode('utf-8')
    signature = hmac.new(key, message, hashlib.sha256).digest()
    signature_b64 = base64.b64encode(signature).decode('utf-8')
    return signature_b64


def sha256(message, secret):
    return hmac.new(secret.encode('utf-8'), message.encode('utf-8'), hashlib.sha256).digest()


def get_path(request_url):
    parsed_url = urlparse(request_url)
    path = parsed_url.path
    params = dict(parsed_url.query)
    if not params:
        return path
    sorted_params = {k: params[k] for k in sorted(params)}
    query_string = urlencode(sorted_params)
    return f'{path}?{query_string}'


def get_json_body(body):
    try:
        json_data = json.loads(body)
    except (json.JSONDecodeError, TypeError):
        json_data = {}
    if not json_data:
        return ''
    json_data = remove_empty_keys(json_data)
    return json.dumps(sort_object(json_data), separators=(',', ':'))


def parse_path(request_url):
    parsed_url = urlparse(request_url)
    path = parsed_url.path
    params = dict(parsed_url.query)
    return path, params


def is_json(json_string):
    try:
        json.loads(json_string)
        return True
    except (json.JSONDecodeError, TypeError):
        return False


def remove_empty_keys(data):
    return {k: v for k, v in data.items() if v}


def sort_object(data):
    if isinstance(data, dict):
        return {k: sort_object(v) for k, v in sorted(data.items())}
    elif isinstance(data, list):
        data.sort(key=sort_object)
        return [sort_object(item) for item in data]
    else:
        return data
      
if __name__ == '__main__':
  timestamp = ""
  request_method = ""
  request_url = ""
  req_body = {
        "XXX": "XXXXX"
  }
  sign = api_sign(timestamp, method, request_url,get_json_body(json.dumps(req_body)), appSecret)
  print(sign)

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"testing"
	"time"
)


func PostRequest(url string, headers map[string]string, bodyData map[string]string) ([]byte, error) {
	requestBody, err := json.Marshal(bodyData)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
	if err != nil {
		return nil, err
	}

	for key, value := range headers {
		req.Header.Set(key, value)
	}
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return responseBody, nil
}

func APISign(timestamp string, method string, requestURL string, body string, secretKey string) (string, error) {
	content := timestamp + strings.ToUpper(method) + getPath(requestURL) + getJSONBody(body)
	signature, err := calculateHMACSHA256([]byte(content), []byte(secretKey))
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(signature), nil
}

func calculateHMACSHA256(message []byte, secret []byte) ([]byte, error) {
	hash := hmac.New(sha256.New, secret)
	_, err := hash.Write(message)
	if err != nil {
		return nil, err
	}
	return hash.Sum(nil), nil
}

func getPath(requestURL string) string {
	u, err := url.Parse(requestURL)
	if err != nil {
		return ""
	}
	path := u.Path
	query := u.Query()
	query.Del("")
	keys := make([]string, 0, len(query))
	for key := range query {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	var encodedParams []string
	for _, key := range keys {
		encodedParams = append(encodedParams, fmt.Sprintf("%s=%s", key, query.Get(key)))
	}
	paramsString := strings.Join(encodedParams, "&")
	if paramsString != "" {
		return path + "?" + paramsString
	}
	return path
}

func getJSONBody(body string) string {
	if body == "" {
		return "" 
	}

	var data interface{}
	err := json.Unmarshal([]byte(body), &data)
	if err != nil {
		return "" 
	}

	
	if dataMap, ok := data.(map[string]interface{}); ok && len(dataMap) == 0 {
		return "" 
	}

	removeEmptyKeys(data)
	sortedData := sortObject(data)

	jsonBytes, err := json.Marshal(sortedData)
	if err != nil {
		return ""
	}
	return string(jsonBytes)
}

func removeEmptyKeys(data interface{}) {
	switch value := data.(type) {
	case map[string]interface{}:
		for key, v := range value {
			if v == nil || v == "" {
				delete(value, key)
			} else {
				removeEmptyKeys(v)
			}
		}
	case []interface{}:
		for _, v := range value {
			removeEmptyKeys(v)
		}
	}
}

func sortObject(data interface{}) interface{} {
	switch value := data.(type) {
	case map[string]interface{}:
		keys := make([]string, 0, len(value))
		for k := range value {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		sortedMap := make(map[string]interface{})
		for _, k := range keys {
			v := sortObject(value[k])
			sortedMap[k] = v
		}
		return sortedMap

	case []interface{}:
		for i, v := range value {
			value[i] = sortObject(v)
		}
		return value
	default:
		return value
	}
}

func main() {
	timestamp := fmt.Sprintf("%d", time.Now().UnixNano()/int64(time.Millisecond))
	method := "XX"
	requestURL := "XXXXX"
	req_body := map[string]string{
		"XXX": "XXXXX",
	}

	dataType, _ := json.Marshal(req_body)
	dataString := string(dataType)

	appId := "XXXXX"
	secretKey := "XXXXX"

	sign, err := APISign(timestamp, method, requestURL, dataString, secretKey)
	if err != nil {
		fmt.Println("Error:", err.Error())
		return
	}

	headers := map[string]string{
		"appId":     appId,
		"timestamp": timestamp,
		"sign":      sign,
	}

	response, err := PostRequest(requestURL, headers, req_body)
	if err != nil {
		fmt.Println("Error:", err)
	} else {
		fmt.Println(string(response))
	}

const crypto = require('crypto');
const url = require('url');

function apiSign(timestamp, method, requestUrl, body, secretkey) {
  const content = timestamp + method.toUpperCase() + getPath(requestUrl) + getJsonBody(body);
  const signVal = crypto.createHmac('sha256', secretkey)
    .update(content, 'utf8')
    .digest('base64');
  
  return signVal;
}

function sha256(message, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(message);
  return hmac.digest();
}

function getPath(requestUrl) {
  const uri = new URL(requestUrl);
  const path = uri.pathname;
  const params = Array.from(uri.searchParams.entries());

  if (params.length === 0) {
    return path;
  } else {
    const sortedParams = [...params].sort(([aKey], [bKey]) => aKey.localeCompare(bKey));
    const queryString = sortedParams.map(([key, value]) => `${key}=${value}`).join('&');
    return `${path}?${queryString}`;
  }
}

function getJsonBody(body) {
  let map;

  try {
    map = JSON.parse(body);
  } catch (error) {
    map = {};
  }

  if (Object.keys(map).length === 0) {
    return '';
  }

  map = removeEmptyKeys(map);
  map = sortObject(map);

  return JSON.stringify(map);
}

function parsePath(requestUrl) {
  const uri = new URL(requestUrl);
  const path = uri.pathname;
  const params = Object.fromEntries(uri.searchParams.entries());

  return { path, params };
}

function isJson(jsonString) {
  if (!jsonString || jsonString === '') {
    return false;
  }

  try {
    JSON.parse(jsonString);
    return true;
  } catch (error) {
    return false;
  }
}

function removeEmptyKeys(map) {
  const retMap = {};

  for (const [key, value] of Object.entries(map)) {
    if (value !== null && value !== '') {
      retMap[key] = value;
    }
  }

  return retMap;
}

function sortObject(obj) {
  if (typeof obj === 'object') {
    if (Array.isArray(obj)) {
      return sortList(obj);
    } else {
      return sortMap(obj);
    }
  }

  return obj;
}

function sortMap(map) {
  const sortedMap = new Map(Object.entries(removeEmptyKeys(map)).sort(([aKey], [bKey]) => aKey.localeCompare(bKey)));

  for (const [key, value] of sortedMap.entries()) {
    if (typeof value === 'object') {
      sortedMap.set(key, sortObject(value));
    }
  }

  return Object.fromEntries(sortedMap.entries());
}

function sortList(list) {
  const objectList = [];
  const intList = [];
  const floatList = [];
  const stringList = [];
  const jsonArray = [];

  for (const item of list) {
    if (typeof item === 'object') {
      jsonArray.push(item);
    } else if (Number.isInteger(item)) {
      intList.push(item);
    } else if (typeof item === 'number') {
      floatList.push(item);
    } else if (typeof item === 'string') {
      stringList.push(item);
    } else {
      intList.push(item);
    }
  }

  intList.sort((a, b) => a - b);
  floatList.sort((a, b) => a - b);
  stringList.sort();

  objectList.push(...intList, ...floatList, ...stringList, ...jsonArray);
  list.length = 0;
  list.push(...objectList);

  const retList = [];

  for (const item of list) {
    if (typeof item === 'object') {
      retList.push(sortObject(item));
    } else {
      retList.push(item);
    }
  }

  return retList;
}

const timestamp = String(Date.now());
const method = 'XXXXX';
const requestUrl = 'XXXXX';
const body = '';
const secretkey = 'XXXXX';
const sign = apiSign(timestamp, method, requestUrl, body, secretkey);
console.log(timestamp);
console.log(sign);
console.log(encodeURIComponent(sign));