Spanish Invalid API-key, IP, or permissions for action. [Solucionado]

carlos7000

Well-Known Member
Licensed User
Longtime User
Hola.

Estoy tratado de obtener información sobre mi cuenta en Binance, empleando la Api de dicha empresa.
De la Api voy a emplear la funcion:

Binance Api: Account information (USER_DATA)

Para ello escribí el siguiente programa en B4J

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form  
    Private TextAreaOut As TextArea
    Private ButtonGet As Button
    Private BinanceApiUrl As String
    Private ApiSecret As String
    Private ApiKey As String  
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
    BinanceApiUrl = "https://api.binance.com/api/"
    ApiKey        = "VmcKfcJ127jpeGUPAKXnHXJBTSF9iMfHUqptwEb1TCvSLwgNnCJ2BuWsdVwyhsbD"
    ApiSecret    = "xTFh2bqOydbMumZmWcV13ecPYFTHmZa5pg0Xp3rlay5Tyog2VBoEAJQToMURhU1E"
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

'Funcion encargada de hacer las solicitudes a la Api de Binance
private Sub SendCommand(work As String, uri As String, Signature As Boolean)
    Try
        'Si se debe firmar
        If (Signature == True)Then          
            Dim timestamp As Long
            timestamp = DateTime.now 'Creamos el timestamp
            Dim queryString As String
            queryString = "timestamp=" & timestamp 'Creamos el Query string            
            Dim Sign() As Byte
            Sign = HashHmac(queryString, ApiSecret) 'Firmamos el Query string
           
            Dim API_Signed As String
            Dim Byte_Conv As ByteConverter
            API_Signed = Byte_Conv.HexFromBytes(Sign) 'convert to HEX
            API_Signed = API_Signed.ToLowerCase
        End If
       
        Dim j As HttpJob
        j.Initialize(work, Me)
       
        Dim Url As String
        Url = BinanceApiUrl & uri & "?" & queryString & "&signature=" & API_Signed 'Creamos la Url
        j.Download(Url)
        Log(Url)
        'Si se debe firmar
        If (Signature == True)Then  
            Try
                'Defino el SetHeader basado función "signedRequest()" que encontrará en este post.
                j.GetRequest.SetHeader("User-Agent", "Mozilla/4.0 (compatible; PHP Binance API)")
                j.GetRequest.SetHeader("X-MBX-ApiKey", ApiKey)
                j.GetRequest.SetHeader("Content-Type", "application/x-www-form-urlencoded")              
            Catch
                Log(LastException)
            End Try           
        End If
       
        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            TextAreaOut.Text = j.JobName & CRLF      
            TextAreaOut.Text = TextAreaOut.Text & j.GetString
            Log(j.GetString)
        Else
            TextAreaOut.Text = j.ErrorMessage
        End If
        j.Release
    Catch
        MessageBox(LastException, "Error")
    End Try
End Sub

Sub ButtonGet_Click
    SendCommand("GetBalances", "v3/account", True)
End Sub

'Funcion encargada de Firmar el QueryString
Public Sub HashHmac(data As String, secret As String) As Byte()
    Try
        Dim m As Mac                                         'm As Message Authentication Code
        Dim kg As KeyGenerator                               'kg As KeyGenerator
        kg.Initialize("HmacSHA512")                          'initialize kg using HmacSHA512 algorithm
        kg.KeyFromBytes(secret.GetBytes("UTF8"))             'encode string "secret" to an array of Bytes using UTF8
        m.Initialise("HmacSHA512", kg.Key)                   'initialize m using HmacSHA512 algorithm and the secret key
        m.Update(data.GetBytes("UTF8"))                      'encodes post data to an array of Bytes and loads it to be signed
        Return m.Sign                                        'sign the loaded data using the secret key, return the calc signature data
    Catch      
        MessageBox(LastException, "Error")
    End Try
End Sub


Public Sub MessageBox(Message As String, Title As String )
    Private jxui As XUI
    jxui.MsgboxAsync(Message, Title)
End Sub

Dicho programa esta basado en esta función escrita en PHP, la cual funciona correctamente.

PHP:
private function signedRequest($url, $params = [], $method = "GET") {
        $params['timestamp'] = number_format(microtime(true)*1000,0,'.','');

        $query = http_build_query($params, '', '&'); // https://www.php.net/manual/es/function.http-build-query.php
        $signature = hash_hmac('sha256', $query, $this->api_secret);
       
        $opt = [
            "http" => [
                "method" => $method,
                "ignore_errors" => true,
                "header" => "User-Agent: Mozilla/4.0 (compatible; PHP Binance API)\r\nX-MBX-APIKEY: {$this->api_key}\r\nContent-type: application/x-www-form-urlencoded\r\n"
            ]
        ];
        if ( $method == 'GET' ) {
            // parameters encoded as query string in URL
            $endpoint = "{$this->base}{$url}?{$query}&signature={$signature}";
        } else {
            // parameters encoded as POST data (in $context)
            $endpoint = "{$this->base}{$url}";
            $postdata = "{$query}&signature={$signature}";
            $opt['http']['content'] = $postdata;
        }
        $context = stream_context_create($opt); // https://www.php.net/manual/es/function.stream-context-create.php
        return json_decode(file_get_contents($endpoint, false, $context), true); // https://www.php.net/manual/es/function.json-decode.php
    }

Entiendo que tengo que crear una url de la forma
B4X:
https://api.binance.com/api/v3/account?timestamp=1614749827929&signature=5022a05d3b51db60b5933976c09a53775f8d753129fca5ee59b63b882bd9a0a80f7e4c9ab38cd4aec00bd042b8a344fb5841335e2e70946af2ca529bdf5dabab

La parte timestamp=1614749827929 debe ser firmada con (HMAC SHA256). Para ello empleo la siguiente función:

B4X:
Public Sub HashHmac(data As String, secret As String) As Byte()
    Try
        Dim m As Mac                                         'm As Message Authentication Code
        Dim kg As KeyGenerator                               'kg As KeyGenerator
        kg.Initialize("HmacSHA512")                          'initialize kg using HmacSHA512 algorithm
        kg.KeyFromBytes(secret.GetBytes("UTF8"))             'encode string "secret" to an array of Bytes using UTF8
        m.Initialise("HmacSHA512", kg.Key)                   'initialize m using HmacSHA512 algorithm and the secret key
        m.Update(data.GetBytes("UTF8"))                      'encodes post data to an array of Bytes and loads it to be signed
        Return m.Sign                                        'sign the loaded data using the secret key, return the calc signature data
    Catch      
        MessageBox(LastException, "Error")
    End Try
End Sub

La función importante del programa es SendCommand, la cual se encarga de hacer las solicituder de información a Binance empleando su Api

B4X:
private Sub SendCommand(work As String, uri As String, Signature As Boolean)
    Try
        'Si se debe firmar
        If (Signature == True)Then          
            Dim timestamp As Long
            timestamp = DateTime.now 'Creamos el timestamp
            Dim queryString As String
            queryString = "timestamp=" & timestamp 'Creamos el Query string            
            Dim Sign() As Byte
            Sign = HashHmac(queryString, ApiSecret) 'Firmamos el Query string
           
            Dim API_Signed As String
            Dim Byte_Conv As ByteConverter
            API_Signed = Byte_Conv.HexFromBytes(Sign) 'convert to HEX
            API_Signed = API_Signed.ToLowerCase
        End If
       
        Dim j As HttpJob
        j.Initialize(work, Me)
       
        Dim Url As String
        Url = BinanceApiUrl & uri & "?" & queryString & "&signature=" & API_Signed 'Creamos la Url
        j.Download(Url)
        Log(Url)
        'Si se debe firmar
        If (Signature == True)Then  
            Try
                'Defino el SetHeader basado en la línea 11 del código de la función [B]signedRequest() [/B]que encontrará mas abajo.
                j.GetRequest.SetHeader("User-Agent", "Mozilla/4.0 (compatible; PHP Binance API)")
                j.GetRequest.SetHeader("X-MBX-ApiKey", ApiKey)
                j.GetRequest.SetHeader("Content-Type", "application/x-www-form-urlencoded")              
            Catch
                Log(LastException)
            End Try
           
        End If
       
        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            TextAreaOut.Text = j.JobName & CRLF      
            TextAreaOut.Text = TextAreaOut.Text & j.GetString
            Log(j.GetString)
        Else
            TextAreaOut.Text = j.ErrorMessage
        End If
        j.Release
    Catch
        MessageBox(LastException, "Error")
    End Try
End Sub

La ejecutar el programa me aparece el error
ResponseError. Reason: , Response: {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}

La ApiKey y el ApiSecret incluidas en el programa son validas (en caso que ud desee ejecutar el programa).

Si Ud desea ayudarme solo debe bajar el proyecto que he adjuntado. El programa esta escrito en B4J, el cual, como ud puede ver es muy similar a B4A. Para ejecutarlo requiere B4J.

Nota: el programa lo estoy desarrollando en B4J para instalarlo en un VPS o un mini computador sin partes móviles. Por eso no lo he desarrollado en B4A para Android.
 

Attachments

  • Binance 2.zip
    3.6 KB · Views: 309
Last edited:

TILogistic

Expert
Licensed User
Longtime User
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form   
    
    Private TextAreaOut As TextArea
    Private ButtonGet As Button
    
    Private BaseURL As String
    Private ApiSecret As String
    Private ApiKey As String   
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
    
    BaseURL = "https://api.binance.com/api/"
    ApiKey = "VmcKfcJ127jpeGUPAKXnHXJBTSF9iMfHUqptwEb1TCvSLwgNnCJ2BuWsdVwyhsbD"
    ApiSecret = "xTFh2bqOydbMumZmWcV13ecPYFTHmZa5pg0Xp3rlay5Tyog2VBoEAJQToMURhU1E"
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub ButtonGet_Click
    SendCommand("v3/account")
End Sub

private Sub SendCommand(ApiURL As String)
    Dim Result As String
    
    Dim TimeStamp As String = DateTime.Now
    Dim Sign() As Byte = HashHmac(TimeStamp, ApiSecret)
    
    If Sign.Length = 0 Then Return
    Dim BConv As ByteConverter
    Dim Signature As String = BConv.HexFromBytes(Sign).ToLowerCase 'convert to HEX

    Dim URL As String = BaseURL & ApiURL & "?" & "timestamp=" & TimeStamp & "&" & "signature=" & Signature
    
    MessageBox($"ApiSecret: ${ApiSecret}"$)
    MessageBox($"ApiKey: ${ApiKey}"$)
    MessageBox($"TimeStamp: ${TimeStamp}"$)
    MessageBox($"Signature: ${Signature}"$)
    MessageBox($"URL: ${URL}"$)
    
    Try
        Dim j As HttpJob
        j.Initialize("", Me)
        j.Download(URL)
        j.GetRequest.SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0")
        j.GetRequest.SetHeader("Content-Type", "application/x-www-form-urlencoded")
        j.GetRequest.SetHeader("X-MBX-ApiKey", ApiKey)

        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            Result = j.GetString
        Else
            Result = j.ErrorMessage
        End If
        j.Release
    Catch
        Result = LastException.Message
    End Try
    MessageBox($"HttpJob: ${Result}"$)
    MessageBox($"------"$)
End Sub

Public Sub HashHmac(data As String, secret As String) As Byte()
    Dim m As Mac 'm As Message Authentication Code
    Dim kg As KeyGenerator 'kg As KeyGenerator
    Dim Result() As Byte 'Result Sign
    Try
        kg.Initialize("HmacSHA512")                          'initialize kg using HmacSHA512 algorithm
        kg.KeyFromBytes(secret.GetBytes("UTF8"))             'encode string "secret" to an array of Bytes using UTF8
        m.Initialise("HmacSHA512", kg.Key)                   'initialize m using HmacSHA512 algorithm and the secret key
        m.Update(data.GetBytes("UTF8"))                      'encodes post data to an array of Bytes and loads it to be signed
        Result = m.Sign                                      'sign the loaded data using the secret key, return the calc signature data
    Catch
        MessageBox($"HashHmac: ${LastException.Message}"$)
    End Try
    Return Result
End Sub

Public Sub MessageBox(Message As String)
    TextAreaOut.Text = TextAreaOut.Text & CRLF & Message
End Sub
 

carlos7000

Well-Known Member
Licensed User
Longtime User
Hola Oparra.

Le comento que comente las lineas...

B4X:
    'MessageBox($"ApiSecret: ${ApiSecret}"$)
    'MessageBox($"ApiKey: ${ApiKey}"$)
    'MessageBox($"TimeStamp: ${TimeStamp}"$)
    'MessageBox($"Signature: ${Signature}"$)
    'MessageBox($"URL: ${URL}"$)
... para ver mejor el mensaje de respuesta

Al ejecutar el programa, la respuesta que obtuve fue:



Me sigue apareciendo el mismo error.

De todas formas le agradezco mucho su ayuda. Muchas gracias.
 

TILogistic

Expert
Licensed User
Longtime User
Ver la solucion de la API.

 

carlos7000

Well-Known Member
Licensed User
Longtime User

Hola Oparra

Le comento que aunque no aparece el error que he mencionado antes, los datos no son lo esperados. Los datos que muestra la aplicacion corresponden a un documento html

La url https://api.binanceus.com/api/ redirige a una pagina de registro de Binance.

La respuesta correcta debe ser un json con información detallada de mi cuenta.

ej:

JSON:
{
  "makerCommission": 15,
  "takerCommission": 15,
  "buyerCommission": 0,
  "sellerCommission": 0,
  "canTrade": true,
  "canWithdraw": true,
  "canDeposit": true,
  "updateTime": 123456789,
  "accountType": "SPOT",
  "balances": [
    {
      "asset": "BTC",
      "free": "4723846.89208129",
      "locked": "0.00000000"
    },
    {
      "asset": "LTC",
      "free": "4763368.68006011",
      "locked": "0.00000000"
    }
  ],
    "permissions": [
    "SPOT"
  ]
}

Provee con la url para pruebas de la Api, que no debería dar error, y nada.

B4X:
BaseURL        = "https://testnet.binance.vision/api/"

En este link hay una explicación superficial del uso de la api, para obtener información detallada de la cuenta

En este link encontrara información mas detallada sobre el proceso de autenticación
 
Last edited:

TILogistic

Expert
Licensed User
Longtime User
Si lo que trato de explicarte, que hemos probado con otra api-key y nos devuelve datos.

y también la usamos en PHP, no hemos tenido problemas.

Saludos.
 

TILogistic

Expert
Licensed User
Longtime User
Mira esto, para detectar el problema.

Sin tu api-key:
j.GetRequest.SetHeader("X-MBX-APIKEY", "none")
ResponseError. Reason: , Response: {"code":-2014,"msg":"API-key format invalid."}
Con tu api-key:
j.GetRequest.SetHeader("X-MBX-APIKEY", ApiKey)
ResponseError. Reason: , Response: {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}

Esto quiere decir que no tienes restricciones de IP por que acepta las solicitudes.
El problema esta en API-key or permissions for action.

B4X:
        Dim j As HttpJob
        j.Initialize("", Me)
        j.Download2(BaseURL & ApiURL, Array As String("timestamp", TimeStamp, "signature", Signature))
        j.GetRequest.SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0")
        j.GetRequest.SetHeader("Content-Type", "application/x-www-form-urlencoded")
'        j.GetRequest.SetHeader("X-MBX-APIKEY", "none")
        j.GetRequest.SetHeader("X-MBX-APIKEY", ApiKey)
 

carlos7000

Well-Known Member
Licensed User
Longtime User

Hola.

Generé un nuevo par de claves, pero aun así el programa continuó dando problemas, agregué el parámetro "recvWindow=60000" y funcionó.



Este es el código que funcionó:

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 300
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    
    Private TextAreaOut As TextArea
    Private ButtonGet As Button
    
    Private BaseURL As String
    Private ApiSecret As String
    Private ApiKey As String
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
    
    BaseURL      = "https://api.binance.com/api/"
    ApiKey       = "QEGYxEGHjyun8Q8cMu7YPVjGjrbrgbvvBjn4KfRB9sYB4qAtKTSVjRFET9KxEnTs"
    ApiSecret    = "9XrkyK3JTCyMZHyvdDHqahjjhSyNXMZCrw4g9uJFtWSye98yfhAtxqmvtJmQeFhh"
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub ButtonGet_Click
    SendCommand("v3/account")
End Sub

private Sub SendCommand(ApiURL As String)
    Dim Result As String
    Dim Params As String = "recvWindow=60000&timestamp=" & DateTime.Now
    Dim Sign() As Byte = HashHmac(Params, ApiSecret)
    
    If Sign.Length = 0 Then Return
    Dim BConv As ByteConverter
    Dim Signature As String = BConv.HexFromBytes(Sign).ToLowerCase 'convert to HEX
    Dim URL As String = BaseURL & ApiURL & "?" & Params & "&signature=" & Signature     
    
    Try
        Dim j As HttpJob
        j.Initialize("", Me)
        j.Download(URL)
        j.GetRequest.SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0")
        j.GetRequest.SetHeader("Content-Type", "application/x-www-form-urlencoded")
        j.GetRequest.SetHeader("X-MBX-APIKEY", ApiKey)

        Wait For (j) JobDone(j As HttpJob)
        If j.Success Then
            Result = j.GetString
        Else
            Result = j.ErrorMessage
        End If
        j.Release
    Catch
        Result = LastException.Message
    End Try
    MessageBox($"HttpJob result: ${Result}"$)
    
End Sub

Public Sub HashHmac(data As String, secret As String) As Byte()
    Dim m As Mac 'm As Message Authentication Code
    Dim kg As KeyGenerator 'kg As KeyGenerator
    Dim Result() As Byte 'Result Sign
    Try
        kg.Initialize("HmacSHA256")                          'initialize kg using HmacSHA512 algorithm
        kg.KeyFromBytes(secret.GetBytes("UTF8"))             'encode string "secret" to an array of Bytes using UTF8
        m.Initialise("HmacSHA256", kg.Key)                   'initialize m using HmacSHA512 algorithm and the secret key
        m.Update(data.GetBytes("UTF8"))                      'encodes post data to an array of Bytes and loads it to be signed
        Result = m.Sign                                      'sign the loaded data using the secret key, return the calc signature data
    Catch
        MessageBox($"HashHmac: ${LastException.Message}"$)
    End Try
    Return Result
End Sub

Public Sub MessageBox(Message As String)
    TextAreaOut.Text = TextAreaOut.Text & CRLF & Message
End Sub

Sr Oparra
Muchas Gracias.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…