Authentication
To use an API key with the Bitcoin Suisse REST API, certain information has to be transmitted in the headers of each request.
At the bottom of this page you can find example code inC#
, Python
and Java
.Request headers
When you created yourAPI Key
, you also got an API Secret
(see API Keys).
The API Secret
is used to create a signature for each request. This ensures that your request was not tampered with when it reaches the Bitcoin Suisse servers.The following information must be provided in the HTTP headers of each request.
Name | Header example | Description |
---|---|---|
API key | X-Auth: BTCS api-key | "BTCS" followed by your API key (with a space in between). |
Nonce | X-Auth-Nonce: 11223344556677889900 | Random string with a length of exactly 20 chars. Only a-z/A-Z/0-9 characters allowed. Needs to be unique for each request. |
Timestamp | X-Auth-Timestamp: 2023‐09‐15T12:16:44:01Z | Timestamp of the request. Must follow ISO 8601 "Date and time in UTC" format. Must be in the range of +/- 10s of the current server time. |
Version | X-Auth-Version: v1 | Which version of the authentication mechanism should be used. Currently only v1 is supported. |
Signature | X-Auth-Signature: signature | Signature of the request payload to verify that the content of the request has not been changed. Has to be calculated for every request. |
Customer number | customer-number: BTCS-CUS-123456 | The customer to act as, optional on some of the endpoints. To find out which customers your API Key can access, use the Customer Management endpoint. |
Example request:
curl --request GET \
--url https://api.bitcoinsuisse.com/trading/api/v3/Accounts \
--header 'X-Auth: BTCS put-your-api-key-here' \
--header 'X-Auth-Nonce: 12345678901234567898' \
--header 'X-Auth-Signature: put-the-base64-encoded-request-signature-here' \
--header 'X-Auth-Timestamp: 2021-03-26 11:33:52.9100000 +00:00' \
--header 'X-Auth-Version: v1' \
--header 'accept: */*' \
--header 'client-number: BTCS-CUS-123456'
Signature calculation
The signature has to be calculated for each request. It is calculated as follows:
- Concatenate the following information in this exact order to get the
signature message
(string):- "BTCS": String, no spaces, no quotation marks
apiKey
: Your Bitcoin SuisseAPI Key
(not theAPI secret
)host
: Host name without schema, e.g.:api.bitcoinsuisse.com
(no trailing/
)path
: Path of the request, e.g.:/auth/api/v1/Customers
queryString
: The query string including the?
, e.g.:?param=123
contentType
TheContent-Type
header of the HTTP request, e.g.:application/json
nonce
: Alphanumeric (a-z/A-Z/0-9) string with a length of exactly 20 chars, must be unique for each requesttimestamp
: Timestamp of the request, must be in the range of +/- 10s of the current server timeversion
: Version of the authentication mechanism, currentlyv1
requestBody
: The body of the HTTP request as string
- Initialize a
HMAC/SHA512
algorithm, using theAPI secret
as cryptographic key- Use
ASCII
encoding when converting theAPI Secret
to bytes
- Use
- Using the previously initialized
HMAC/SHA512
algorithm, hash thesignature message
- Use
UTF8
encoding when converting thesignature message
to bytes
- Use
- Finally, use
base64
encoding to encode the hash
C# Example
This example shows how to calculate the signature, add the required headers to a request and send it. It will print the response to the console.
using var client = new System.Net.Http.HttpClient();
var apiKey = ""; // TODO: Your API Key
var secret = ""; // TODO: Your API Secret
var customer = ""; // TODO: Your customer number (e.g. BTCS-CUS-000000)
var host = "sandbox-api.btcsqa.net";
// simple GET request, doesn't have query params, content type or request body
var path = "/auth/api/v1/Customers";
var queryString = string.Empty;
var contentType = string.Empty;
var nonce = Guid.NewGuid().ToString("N")[..20]; // must be unique for each request
var timestamp = System.DateTime.UtcNow.ToString("o"); // must be ISO8601 format
var version = "v1";
var requestBody = string.Empty;
var signatureMessage = "BTCS" +
apiKey +
host +
path +
queryString +
contentType +
nonce +
timestamp +
version +
requestBody;
var keyBytes = Encoding.ASCII.GetBytes(secret);
var hmacsha512 = new System.Security.Cryptography.HMACSHA512(keyBytes);
var hashBytes = hmacsha512.ComputeHash(Encoding.UTF8.GetBytes(signatureMessage));
var signature = Convert.ToBase64String(hashBytes);
//client.DefaultRequestHeaders.Add("customer-number", customer); // needed for most requests, see API specifications
client.DefaultRequestHeaders.Add("X-Auth", "BTCS " + apiKey);
client.DefaultRequestHeaders.Add("X-Auth-Nonce", nonce);
client.DefaultRequestHeaders.Add("X-Auth-Timestamp", timestamp);
client.DefaultRequestHeaders.Add("X-Auth-Version", version);
client.DefaultRequestHeaders.Add("X-Auth-Signature", signature);
var request = await client.GetAsync($"https://{host}{path}{queryString}");
var response = await request.Content.ReadAsStringAsync();
Console.WriteLine(request.StatusCode);
Console.WriteLine(response);
Python Example
This example shows how to calculate the signature, add the required headers to a request and send it. It will print the response to the console.
Save this code into a file (e.g.main.py
), fill in your credentials (apiKey
, secret
, customerNumber
) and then run it using python .\main.py
.
Make sure to use python3.import requests
import random
from datetime import datetime
import hashlib
import hmac
import base64
apiKey = "" # TODO: Your API Key
secret = "" # TODO: Your API Secret
customerNumber = "" # TODO: Your Customer Number (e.g. BTCS-CUS-123456)
timestamp = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
print("Timestamp: " + str(timestamp))
nonce = str(random.randrange(10_000_000_000_000_000_000, 100_000_000_000_000_000_000))
print("Nonce: " + str(nonce))
version = "v1"
schema = "https://"
url = "sandbox-api.btcsqa.net/trading/api/v3/Accounts"
queryString = ""
contentType = ""
payload = ""
message = "BTCS" + apiKey + url + queryString + contentType + nonce + timestamp + version + payload
print("Signature message: " + message)
signature = hmac.new(bytes(secret, 'ASCII'), bytes(message, 'utf-8'), hashlib.sha512)
signature = base64.b64encode(signature.digest()).decode()
print("Signature: " + signature)
headers = {
"X-Auth": "BTCS " + apiKey,
"X-Auth-Signature": signature,
"X-Auth-Nonce": nonce,
"X-Auth-Timestamp": timestamp,
"X-Auth-Version": version,
"accept": "*/*",
"content-type": contentType,
"customer-number": customerNumber
}
print("Request: " + schema + url)
response = requests.request("GET", schema + url, data=payload, headers=headers)
print(response, response.text)
Java Example
This example shows how to calculate the signature, add the required headers to a request and send it. It will print the response to the console.
This example relies on the Apache Commons Codec package.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Random;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
public class Program {
public static void main(String[] args) {
String customerNumber = ""; // TODO: Your customer number (e.g. BTCS-CUS-000000)
String query = "";
String path = "/trading/api/account/getaccountstatement";
String requestContent = "{\"messageType\":\"GetAccountStatement\","
+ "\"accountNumber\":\"BTCS-ACC-BTC-795185\","
+ "\"dateFrom\":\"2021-04-01T00:00:00Z\","
+ "\"dateTo\":\"2021-05-04T00:00:00+02:00\"}";
// sendRequest("POST", customerNumber, path, query, requestContent);
// The Java HttpRequest struggles to handle empty content with content-length = 0
// so better to send an empty json object
path = "/trading/api/instrument/getinstruments";
requestContent = "{}";
sendRequest("POST", customerNumber, path, query, requestContent);
path = "/auth/api/v1/apikey/getassociatedclients";
requestContent = "";
sendRequest("GET", "", path, query, requestContent);
}
static final String ApiKeyHeaderName = "X-Auth";
static final String ApiKeyHeaderParamName = "BTCS";
static final String SignatureHeaderName = "X-Auth-Signature";
static final String NonceHeaderName = "X-Auth-Nonce";
static final String TimeStampHeaderName = "X-Auth-TimeStamp";
static final String VersionHeaderName = "X-Auth-Version";
static final String Version = "v1";
static final String CustomerNumberHeaderName = "customer-number";
static final char[] ValidChars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
.toCharArray();
static final Random random = new Random();
public static String generate20CharsNonce() {
// must be exactly 20 chars long, and unique from call to call
int len = 20;
StringBuilder sb = new StringBuilder(len);
for (int i=0; i<len; i++) {
char c = ValidChars[random.nextInt(ValidChars.length)];
sb.append(c);
}
return sb.toString();
}
public static void sendRequest(
String httpMethod,
String customerNumber,
String path,
String query,
String requestContent
) {
String apiKey = ""; // TODO: Your API Key
String secret = ""; // TODO: Your API Secret
String host = "sandbox-api.btcsqa.net";
String contentType = "application/json";
String nonce = generate20CharsNonce(); // must be exactly 20 chars long, and unique from call to call
String version = "v1";
DateTimeFormatter dtf = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS")
.withZone(ZoneId.from(ZoneOffset.UTC));
Instant utcNow = Instant.now();
String timestamp = dtf.format(utcNow) + "Z";
String message = "BTCS"
+ apiKey
+ host
+ path
+ query
+ contentType
+ nonce
+ timestamp
+ version
+ requestContent;
System.out.println(message);
byte[] key = secret.getBytes();
HmacUtils hm256 = new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key);
byte[] rawHmac = hm256.hmac(message);
String signature = new String(Base64.encodeBase64(rawHmac));
System.out.println(signature);
HttpClient client = HttpClient.newHttpClient();
HttpRequest.Builder rb = HttpRequest.newBuilder()
.uri(URI.create("https://" + host + path + query))
.header("X-Auth", "BTCS " + apiKey)
.header("X-Auth-Signature", signature)
.header("X-Auth-Nonce", nonce)
.header("X-Auth-TimeStamp", timestamp)
.header("X-Auth-Version", version)
.header("Content-Type", contentType);
if (!customerNumber.isEmpty())
rb = rb.header("client-number", customerNumber);
if (httpMethod.equals("GET"))
rb = rb.GET();
else if (httpMethod.equals("POST"))
rb = rb.POST(HttpRequest.BodyPublishers.ofString(requestContent, StandardCharsets.UTF_8));
HttpRequest request = rb.build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200)
throw new RuntimeException("Status code: " + response.statusCode() + "\r\n" + response.body());
System.out.println(response.body());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}