## 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 in `C#`, `Python` and `Java`. ### Request headers When you created your `API Key`, you also got an `API Secret` (see [API Keys](/api/pages/getting-started/api-keys#2-create-an-api-key)). 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](https://docs.bitcoinsuisse.com/api/#operation/ListCustomers) endpoint. | Example request: ```bash 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: 1. Concatenate the following information in this exact order to get the `signature message` (string): 1. "BTCS": String, no spaces, no quotation marks 2. `apiKey`: Your Bitcoin Suisse `API Key` (not the `API secret`) 3. `host`: Host name without schema, e.g.: `api.bitcoinsuisse.com` (no trailing `/`) 4. `path`: Path of the request, e.g.: `/auth/api/v1/Customers` 5. `queryString`: The query string including the `?`, e.g.: `?param=123` 6. `contentType` The `Content-Type` header of the HTTP request, e.g.: `application/json` 7. `nonce`: Alphanumeric (a-z/A-Z/0-9) string with a length of exactly 20 chars, must be unique for each request 8. `timestamp`: Timestamp of the request, must be in the range of +/- 10s of the current server time 9. `version`: Version of the authentication mechanism, currently `v1` 10. `requestBody`: The body of the HTTP request as string 2. Initialize a `HMAC/SHA512` algorithm, using the `API secret` as cryptographic key - Use `ASCII` encoding when converting the `API Secret` to bytes 3. Using the previously initialized `HMAC/SHA512` algorithm, hash the `signature message` - Use `UTF8` encoding when converting the `signature message` to bytes 4. 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. ```csharp 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. ```python 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](https://mvnrepository.com/artifact/commons-codec/commons-codec) package. ```java 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 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); } } } ```