Formulating POST request to CoinSpot API

Viewed 630

I am pulling my hair out trying to query the CoinSpot API.

The endpoint for the Read Only API is: https://www.coinspot.com.au/api/ro

The documentation states:

All requests to the API will need to include the following security data.

Headers: key - Your API key generated from the settings page sign - The POST data is to be signed using your secret key according to HMAC-SHA512 method. Post Params: nonce - Any integer value which must always be greater than the previous requests nonce value.

I try to query the 'List My Balances' endpoint via: https://www.coinspot.com.au/api/ro/my/balances

However, the code I have formulated below always returns an error: "invalid/missing nonce".

I have tried so many different variations and approaches but it is always the same error.

require(httr)

key <- "68z...39k"
secret <- "71A...48i"

result <- POST("https://www.coinspot.com.au/api/ro/my/balances",
               body = list('nonce'=as.integer(as.POSIXct(Sys.time()))), add_headers("key"=key,"sign"=openssl::sha512("https://www.coinspot.com.au/api/ro/my/balances",key = secret)))

content(result)

Any help much appreciated.

3 Answers

For me, I was missing the JSON string encoded postdata in the body, including the nonce. As soon as I added that, it started working.

Ive struggled with this too- the coinspot API guide isn't very clear.

I figured out you are meant to encode the postdata in correct json format using sha512 and add that to the sign header. See example below querying account balances on v2 of the api.

require(httr)

api_key = "68z...39k"
api_secret = "71A...48i"
base_url = "https://www.coinspot.com.au/api/v2/ro"
request = "/my/balances"
nonce =  as.character(as.integer(Sys.time()))
postdata = paste0('{"nonce":"',nonce,'"}') # important to get the quotes correct
api_sign = digest::hmac(api_secret, postdata, algo="sha512",raw=F)

result = POST(paste0(base_url, request),
              body = list("nonce"=nonce), 
              add_headers(c("key"=api_key,
                            "sign"=api_sign)),
              encode="json"
)
cat(rawToChar(result$content))

You would change what is in postdata based on what you are doing with the API- this is a simple example to build on. If you want to see what postdata should look like prior to encryption in sign, use cat(rawToChar(result$request$options$postfields)) after making a request.

Heres my code in c# using Restsharp and Newtonsoft

        //put the nonce at the beginning
        JObject joBody = JObject.Parse(@"{'nonce': '" + DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString() + "'}");
        joBody.Merge(originalBody);

        var client = new RestClient(_coinspotSettings.BaseURL);
        RestRequest request = new RestRequest(endpoint, Method.POST);
        request.AddJsonBody(JsonConvert.SerializeObject(joBody));
        request.AddHeader("key", coinspotAccount.APIKey);
        request.AddHeader("sign", SignData(coinspotAccount, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(joBody))).ToLower());
        request.AddHeader("Content-Type", "application/json");

    private string SignData(CoinspotAccount coinspotAccount, byte[] JSONData)
    {
        var HMAC = new HMACSHA512(Encoding.UTF8.GetBytes(coinspotAccount.APISecret));
        byte[] EncodedBytes = HMAC.ComputeHash(JSONData);

        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i <= EncodedBytes.Length - 1; i++)
            stringBuilder.Append(EncodedBytes[i].ToString("X2"));

        return stringBuilder.ToString();
    }
Related