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 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://").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();
        let signature = hex::encode(hmac.finalize().into_bytes());
        println!("signature: {}", signature);

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

        let json = 
          \"id\": \"1nsfjknfdwkonfkookeeor\",
          \"method\": \"\",
          \"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.

        // Retrieve data.
        while let Some(message) = {
            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


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
            .map(|(k, v)| format!("{}={}", k, v))

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