Signature does not match – POST HTTP Request to BingX API with Python

Question:

I’m trying to communicate with an API of a Tradingplatform via post requests in Python. Unfortunately, this only works if the request does not have to be signed. At the beginning I just wanted to follow the example of the documentation (BingX API Documentation on GitHub) to get an account balance. The example gave me the impression that this would take half an hour, but now i’ve been at it for two days and i’m slowly starting to despair.

When I send my request I get an error message from the server that my signature is not correct:

{"code":80014,"msg":"signature not match","data":{}}

Since i have no experience with encryption or similar things, it is very difficult for me to analyze the error. I could imagine that the error lies in the conversion to bytes, but i can’t omit this step for test purposes either. The documentation asks you to encrypt the string according to this scheme:

Signature = HmacSHA256("UuGuyEGt6ZEkpUObCYCmIfh0elYsZVh80jlYwpJuRZEw70t6vomMH7Sjmf94ztSI", "POST/api/v1/user/getBalanceapiKey=Zsm4DcrHBTewmVaElrdwA67PmivPv6VDK6JAkiECZ9QfcUnmn67qjCOgvRuZVOzU&currency=USDT&timestamp=1615272721001")
Signature = Base64Encode(Signature)
Signature = UrlEncode(Signature)

Which i "solved" as follows:

signature       =   hmac.new(api_secret.encode('utf-8'), originstring.encode('utf-8'), hashlib.sha256).digest().upper()
signature       =   str(signature)
signature       =   bytes(signature, 'utf-8')
signature       =   base64.b64encode(signature)
signature       =   urllib.parse.quote(signature)

I would be very happy if someone could explain to me what I’m doing wrong.

Thanks very much

Daniel

My full Python Code:

import requests
import hmac
import hashlib
import time
import base64
import urllib
import json

api_key         =   "tHeKeY"
api_secret      =   "MySuPeRsEcReT"
asset           =   "USDT"
want            =   "getBalance"

timestamp       =   str(int(time.time()))

paramstring     =   (str("apiKey=")     +
                    str(api_key)        +
                    str("&currency=")   +
                    str(asset)          +
                    str("&timestamp=")  +
                    str(timestamp))

print("PARAMSTRING:")
print(paramstring)
print("")

originstring    =   (str("POST/api/v1/user/") +
                    str(want) +
                    str(paramstring))

print("ORIGINSTRING:")
print(originstring)
print("")

signature       =   hmac.new(api_secret.encode('utf-8'), originstring.encode('utf-8'), hashlib.sha256).digest().upper()
signature       =   str(signature)
signature       =   bytes(signature, 'utf-8')
signature       =   base64.b64encode(signature)
signature       =   urllib.parse.quote(signature)

print("SIGNATURE:")
print(signature)
print("")

signature = str(signature)

requeststring   =   (str("https://api-swap-rest.bingbon.pro/api/v1/user/getBalance?") +
                    str("apiKey=")      +
                    str(api_key)        +
                    str("&currency=")   +
                    str(asset)          +
                    str("&timestamp=")  +
                    str(timestamp)      +
                    str("&sign=")       +
                    str(signature))

print("REQUESTSTRING:")
print(requeststring)
print("")
print("RESPONSE:")

response            =   requests.post(requeststring)
response            =   str(response.text)
print(response)
response            =   json.loads(response)
response_code       =   (response["code"])
response_message    =   (response["msg"])
response_data       =   (response["data"])

print(response_code)
print(response_message)
print(response_data)
Asked By: Daniel

||

Answers:

Infinite monkeys with infinite typewriters, with enough time you can experiment.

I have no idea why, but when I do it this way it works:

signature       =   (base64.b64encode(
                hmac.new(bytes(api_secret, 'utf-8'), bytes(originstring, 'utf-8'),digestmod=hashlib.sha256).digest()).decode("utf-8"))

But anyway, if someone can tell me where my problem was, it would be great. Because for me both solutions look somehow the same.

Answered By: Daniel

Incase someone still has issues with BingX API, heres a Link to some demo wrappers for python/php/postman/java/go. Incase the git gets removed il add some example code here aswell.
https://github.com/BingX-API/BingX-swap-api-doc/tree/master/demo

Python

import urllib.request
import json
import base64
import hmac
import time

APIURL = "https://api-swap-rest.bingbon.pro"
APIKEY = "Set your api key here !!"
SECRETKEY = "Set your secret key here!!"

def genSignature(path, method, paramsMap):
    sortedKeys = sorted(paramsMap)
    paramsStr = "&".join(["%s=%s" % (x, paramsMap[x]) for x in sortedKeys])
    paramsStr = method + path + paramsStr
    return hmac.new(SECRETKEY.encode("utf-8"), paramsStr.encode("utf-8"), digestmod="sha256").digest()

def post(url, body):
    req = urllib.request.Request(url, data=body.encode("utf-8"), headers={'User-Agent': 'Mozilla/5.0'})
    return urllib.request.urlopen(req).read()

def getBalance():
    paramsMap = {
        "apiKey": APIKEY,
        "timestamp": int(time.time()*1000),
        "currency": "USDT",
    }
    sortedKeys = sorted(paramsMap)
    paramsStr = "&".join(["%s=%s" % (x, paramsMap[x]) for x in sortedKeys])
    paramsStr += "&sign=" + urllib.parse.quote(base64.b64encode(genSignature("/api/v1/user/getBalance", "POST", paramsMap)))
    url = "%s/api/v1/user/getBalance" % APIURL
    return post(url, paramsStr)

PHP

<?php

$url = "https://api-swap-rest.bingbon.pro";
$apiKey = "Set your api key here!!";
$secretKey = "Set your secret key here!!";

function getOriginString(string $method, string $path, array $params) {
    // combine origin string
    $originString = $method.$path;
    $first = true;
    foreach($params as $n => $v) {
          if (!$first) {
              $originString .= "&";
          }
          $first = false;
          $originString .= $n . "=" . $v;
    }
    return $originString;
}

function getSignature(string $originString) {
    global $secretKey;
    $signature = hash_hmac('sha256', $originString, $secretKey, true);
    $signature = base64_encode($signature);
    $signature = urlencode($signature);
    return $signature;
}

function getRequestUrl(string $path, array $params) {
    global $url;
    $requestUrl = $url.$path."?";
    $first = true;
    foreach($params as $n => $v) {
          if (!$first) {
              $requestUrl .= "&";
          }
          $first = false;
          $requestUrl .= $n . "=" . $v;
    }
    return $requestUrl;
}

function httpPost($url)
{
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_USERAGENT, "curl/7.80.0");
    $response = curl_exec($curl);
    curl_close($curl);
    return $response;
}

function getBalance() {
    global $apiKey;

    // interface info
    $path = "/api/v1/user/getBalance";
    $method = "POST";

    // interface params
    $params = array();
    $params['currency'] = 'USDT';
    $params['apiKey'] = $apiKey;
    $date = new DateTime();
    $params['timestamp'] = $date->getTimestamp()*1000;

    // sort params
    ksort($params);

    // generate signature
    $originString = getOriginString($method, $path, $params);
    $signature = getSignature($originString);
    $params["sign"] = $signature;

    // send http request
    $requestUrl = getRequestUrl($path, $params);
    $result = httpPost($requestUrl);
    echo "t";
    echo $result;
    echo "n";
}
?>
Answered By: capo

I tested it many times, non of them cannot fix the problem, I watched the problem, and whenever in my signature I have plus character "+" I will face this error. then I write a function to generate many times of signature while it doesn’t have "+".

example:
WRONG: "VFVrfx8kcs8aT+rgSeyq3/xuez7e7JY4x2S40IebL+s="

CORRECT: "3KoqzrBj8WSWsf3UDZj1fuuj8elLAOO2hSxSJUOO3jE="

Answered By: Emad Hejazian
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.