API Sign
Signature Parameters
Description | Description | Remarks |
---|---|---|
timestamp | Thirteen-digit timestamp | 1699261493465 |
httpMethod | Request Method GET/POST | request method must be in uppercase |
requestPath | Request Path | excluding the domain name |
bodyString | Request Body | GET: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));
Updated about 2 months ago