timothyjgraham
timothyjgraham

Reputation: 1232

Formulating POST request to CoinSpot API

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.

Upvotes: 5

Views: 1210

Answers (4)

Raihan Shafique
Raihan Shafique

Reputation: 81

Here is my code in python working in python version 3.6.2

import os
coinSpotApiKey = os.environ['coinSpotReadAPIKey']
coinSpotSecretKey = os.environ['coinspotSecretKey']

import requests
import hmac
import hashlib
import time

# Your API key and secret

api_key = coinSpotApiKey
secret_key = coinSpotSecretKey

# API endpoint
url = 'https://www.coinspot.com.au/api/v2/ro/my/balances'

def myBalance():

    # Create a nonce (must be unique and incrementing)
    nonce = int(time.time() * 1000)

    # Prepare the data payload
    data = f'{{"nonce":"{nonce}"}}'

    # Convert the data to JSON and encode as bytes
    post_data = data.encode('utf-8')

    # Create the HMAC signature
    signature = hmac.new(
        secret_key.encode('utf-8'),
        post_data,
        hashlib.sha512
    ).hexdigest()

    # Set up headers
    headers = {
        'key': api_key,
        'sign': signature,
        'Content-Type': 'application/json',
    }

    # Make the POST request

    response = requests.post(url, headers=headers, data=f'{{"nonce":"{nonce}"}}')

    return(response)

Upvotes: 0

Quintin Humphreys
Quintin Humphreys

Reputation: 64

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();
    }

Upvotes: 0

felix_fisher
felix_fisher

Reputation: 21

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.

Upvotes: 2

ellioseven
ellioseven

Reputation: 141

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.

Upvotes: 1

Related Questions