Binance: -1022 Signature for this request is not valid

I am trying to use the Binance Websocket API to send a trade request. I have already successfully implemented communicating with the REST-API to place a order, but the websocket for some reason keeps failing...

This is the error I get:

-1022 Signature for this request is not valid.

Binance API requires you to sign your payload to validate the request. Examples of it being implemented can be found here:

Running websocket_api_client.py with my API-keys works. So it has nothing to do with using invalid API-keys.

This is my code:

        let api_key = "";
        let api_secret = ""; 

        // Make websocket connection.
        let url = url::Url::parse("wss://testnet.binance.vision/ws-api/v3").unwrap();
        let (ws_stream, _) = connect_async(url).await.expect("Failed to connect");
        let (mut send, mut read) = ws_stream.split();
        
        // Get timestamp.
        let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis().to_string(); 

        // Set parameters payload for order request.
        let mut params = std::collections::HashMap::<&str, &str>::new();
        params.insert("symbol", "BTCUSDT");
        params.insert("side", "BUY");
        params.insert("type", "MARKET");
        params.insert("quantity", "0.01");
        params.insert("apiKey", api_key);
        params.insert("timestamp", &*timestamp);

        // URL encode parameters so we can hash the signature.
        let url_encoded = ser::to_string(&params).unwrap();
        println!("url_encoded: {}", url_encoded);

        // Generate signature.
        let mut hmac = HmacSha256::new_from_slice(api_secret.as_bytes()).unwrap();
        hmac.update(url_encoded.as_bytes());
        let signature = hex::encode(hmac.finalize().into_bytes());
        println!("signature: {}", signature);

        // Add signature to parameters.
        params.insert("signature", &*signature);

        
        let json = 
        format!("
        {{
          \"id\": \"1nsfjknfdwkonfkookeeor\",
          \"method\": \"order.place\",
          \"params\": {}
          }}
        ",  serde_json::to_string(&params).unwrap()); 
    

        let json = serde_json::from_str::<serde_json::Value>(&*json).unwrap();
        println!("\n\njson:\n{}\n", json);


        // Send to websocket.
        send.send(Message::Text(json.to_string().trim().to_string())).await;

        // Retrieve data.
        while let Some(message) = read.next().await {
            let data = message.unwrap().into_data();
            let data = &*String::from_utf8(data).unwrap();

            println!("\nresponse: {:?}", data);

        }

This is the full output:

url_encoded: type=MARKET&side=BUY&quantity=0.01&apiKey=my_actual_api_key&timestamp=1704763468960&symbol=BTCUSDT
signature: d0154884d6d9e7a4a369b2f9f68f6337c2da86b40f8bbdf1371f338645e7ba8d


json:
{"id":"1nsfjknfdwkonfkookeeor","method":"order.place","params":{"apiKey":"my_actual_api_key","quantity":"0.01","side":"BUY","signature":"d0154884d6d9e7a4a369b2f9f68f6337c2da86b40f8bbdf1371f338645e7ba8d","symbol":"BTCUSDT","timestamp":"1704763468960","type":"MARKET"}}


response: "{\"id\":\"1nsfjknfdwkonfkookeeor\",\"status\":400,\"error\":{\"code\":-1022,\"msg\":\"Signature for this request is not valid.\"},\"rateLimits\":[{\"rateLimitType\":\"REQUEST_WEIGHT\",\"interval\":\"MINUTE\",\"intervalNum\":1,\"limit\":6000,\"count\":3}]}"

response: "disconnected"

I am stuck on this issue for days already. I think I am overlooking something small like encoding something wrong or whatever. Does anyone have an idea?

I was able to fix it using this code:

        // Sort the parameters alphabetically by key
        let mut sorted_params: Vec<(&&str, &&str)> = params.iter().collect();
        sorted_params.sort_by(|a, b| a.0.cmp(b.0));

        let query_string = sorted_params
            .iter()
            .map(|(k, v)| format!("{}={}", k, v))
            .collect::<Vec<String>>()
            .join("&");

Apparently the order in which the parameters are sent do matter a lot to the API (bad design if you ask me). The parameters should be alphabetically and the signature should be the last property in the parameters of the JSON-message to the websocket.

I also got rid of the url encoding and just concattenated the strings in the format key=value&....

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.