While reading about how to create ALGO trades using the API, I stumbled across the existence of a SPOT Testnet.
After following the instructions on how to setup an RSA key, writing the necessary code, and checking if it produces the same result as the example bash script ( https://testnet.binance.vision/#faq-rsa-how-to ), attempting to use any of the USER_DATA type endpoints I hit a roadblock.
In the limited available endpoints (which don’t 404, including but not limited to the entirety of /wapi/ and /api/v3/order/test) all of them return -1022 “Signature for this request is not valid”.
I’m at a loss at what could be wrong on my side. I already double-chcked the following:
there is no trailing \n at the end of the request string, because I get the same signature in bash and in C#
the C# code works on the production SPOT API ( https://api.binane.com ), I only change the signature generator code when using the Testnet, and I have double-checked that the RSA code path runs for testnet
API key is properly set and present in the header, and the private key parameters are correctly loaded into memory
tried different URLEncode methods, and even tried the lack of it, same result
double-checked the URL, and noticed no anomaly at all
also checked for other anomalies, and I can’t see unexpected results, like double URLEncode, or other library-induced anomalies
Here is an example (trimmed) request URL: https://testnet.binance.vision/api/v3/openOrders?symbol=BTCUSDT&recvWindow=4000×tamp=1604526649584&signature=XEDg6PKquDk[...]NTupzk%3D
Is there perhaps some fine print I could’ve missed? Are RSA keys even enabled for testnet? Or perhaps there is a typo in the bash script, and the RSA signature must be passed in a different query parameter?
It seems like something must’ve glitched in the system when I created the first RSA key, because creating a new RSA key with the same private-public key pair made the bash script work.
The only difference between the two ways I created the key is that the first time I created an API key, I had a newline after -----END PUBLIC KEY-----, but this time I didn’t, and that made the bash script work.
However, even though the bash script works, I still get the same error in my code, which is weird, because debugging the bash script and my code, the exact same signature and request URL is generated, except my code URLEncoded the special characters with upper-case hexadecimal characters, not lowercase ones. Even after changing the URLEncoder to output lower-case hexadecimal characters (watching out not to corrupt the signature by accident), I get a byte-by-byte match on the signature when comparing against the bash script.
I re-checked a ton of times:
the code works in production environment with HMACSHA256 key
the exact same code runs for both production and testnet, except the API URL is different, and the if case for RSA signing runs instead of the HMACSHA256 checksum
the URL matches byte-by-byte except the timestamp and the signature
the signature generation now matches byte-by-byte compared to the bash script
Are there perhaps other secret requirements, like other custom headers, or User-Agent string?
Even editing the URL in the bash script, it works in the bash script, but not in the C# code.
The URL I used is GET https://testnet.binance.vision/api/v3/account?recvWindow=4000×tamp=1604678626552&signature=<signature>
The URL looks good to me, this may not be the issue, but have a try to remove recvWindow which is not mandatory.
At this point, I don’t have concern for the issue from testnet server side, and it’s hard to what could be improved from client side. If you could provide a simple script and share with us, we may be have another look.
It turns out everything was functional from the very get-go, except I had URLEncode issues.
At first the URLEncode wasn’t functional correctly, so the + character was at first not encoded (so it was treated as a %20 space), and after noticing that, I made a fatal typo where I was encoding it was %2d instead of %2b.
The reason I did not notice this mistake is because I compared the URLs by eye; so the moral of the story is to always use tools while debugging to keep human error out as much as possible