Embed REST Authentication
Authentication Parameters
For the Embed REST API, the following parameters are used for authentication:
API-KeyHTTP header parameter: your public API key.API-SignHTTP header parameter: HMAC-SHA512 signature of the request.API-NonceHTTP header parameter: always increasing, unsigned 64-bit integer.
Optionally, the following header can be included:
Kraken-VersionHTTP header parameter (optional): API version string (e.g.,2025-04-15). If not specified, the latest version is used.
Setting the API-Key Parameter
The value for the API-Key HTTP header parameter is your public API key.
Contact your Kraken account representative to obtain API credentials.
From your API key-pair, clearly identify which key is public and which key is private.
- The public key is sent in the
API-Keyheader parameter. - The private key is never sent, it is only used to encode the signature for
API-Signheader parameter.
Setting the API-Sign Parameter
The value for the API-Sign HTTP header parameter is a signature generated from encoding your private API key, nonce, encoded payload, and URI path.
HMAC-SHA512 of (URI path + SHA256(nonce + JSON body)) and base64 decoded secret API key
Algorithm Steps
- Build the message: Concatenate the nonce with the request body (JSON stringified)
- For GET requests: use only the nonce
- For POST/PUT requests:
nonce + JSON.stringify(body)
- Hash the message: Compute SHA256 of the encoded message
- Concatenate with path: Combine the URL path bytes with the SHA256 hash
- Sign: Generate HMAC-SHA512 using your base64-decoded secret
- Encode: Base64 encode the signature
Examples
The following code snippets demonstrate how to generate the signature in Python, Go, and JavaScript.
- Python
- Go
- JavaScript
import json
import time
import hashlib
import hmac
import base64
def get_kraken_signature(urlpath, data, secret, nonce):
"""
Generate Kraken Embed API signature.
Args:
urlpath: API endpoint (e.g., '/b2b/assets')
data: Request body dict (None for GET requests)
secret: Base64-encoded API secret
nonce: Always-increasing integer
Returns:
Base64-encoded signature string
"""
if data is None:
encoded = str(nonce).encode('utf-8')
else:
encoded = (str(nonce) + json.dumps(data)).encode('utf-8')
message = urlpath.encode() + hashlib.sha256(encoded).digest()
mac = hmac.new(base64.b64decode(secret), message, hashlib.sha512)
return base64.b64encode(mac.digest()).decode()
# Example usage
api_secret = "your-api-secret-here"
nonce = int(time.time() * 1000000000) # Nanoseconds
endpoint = "/b2b/assets"
signature = get_kraken_signature(endpoint, None, api_secret, nonce)
print(f"API-Sign: {signature}")
package main
import (
"crypto/hmac"
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
"encoding/json"
"fmt"
"strconv"
"time"
)
// GetKrakenSignature generates the Kraken Embed API signature.
func GetKrakenSignature(urlpath string, data interface{}, secret string, nonce int64) (string, error) {
var encoded string
if data == nil {
encoded = strconv.FormatInt(nonce, 10)
} else {
jsonData, err := json.Marshal(data)
if err != nil {
return "", err
}
encoded = strconv.FormatInt(nonce, 10) + string(jsonData)
}
sha := sha256.New()
sha.Write([]byte(encoded))
shaSum := sha.Sum(nil)
message := append([]byte(urlpath), shaSum...)
secretBytes, err := base64.StdEncoding.DecodeString(secret)
if err != nil {
return "", err
}
mac := hmac.New(sha512.New, secretBytes)
mac.Write(message)
macSum := mac.Sum(nil)
return base64.StdEncoding.EncodeToString(macSum), nil
}
func main() {
apiSecret := "your-api-secret-here"
nonce := time.Now().UnixNano() // Nanoseconds
endpoint := "/b2b/assets"
signature, err := GetKrakenSignature(endpoint, nil, apiSecret, nonce)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("API-Sign: %s\n", signature)
}
import crypto from 'crypto';
/**
* Generate Kraken Embed API signature.
* @param {string} urlpath - API endpoint (e.g., '/b2b/assets')
* @param {Object|null} data - Request body (null for GET requests)
* @param {string} secret - Base64-encoded API secret
* @param {number} nonce - Always-increasing integer
* @returns {string} Base64-encoded signature
*/
function getKrakenSignature(urlpath, data, secret, nonce) {
const encoded = data === null
? String(nonce)
: String(nonce) + JSON.stringify(data);
const sha256Hash = crypto.createHash('sha256').update(encoded).digest();
const message = Buffer.concat([Buffer.from(urlpath), sha256Hash]);
const secretBuffer = Buffer.from(secret, 'base64');
const hmac = crypto.createHmac('sha512', secretBuffer);
hmac.update(message);
return hmac.digest('base64');
}
// Example usage
const apiSecret = 'your-api-secret-here';
const nonce = Date.now() * 1000000; // Nanoseconds
const endpoint = '/b2b/assets';
const signature = getKrakenSignature(endpoint, null, apiSecret, nonce);
console.log(`API-Sign: ${signature}`);
Setting the API-Nonce Parameter
The value for the API-Nonce HTTP header parameter is an always increasing, unsigned 64-bit integer for each request made with a particular API key.
While a simple counter would provide a valid nonce, a more usual method is to use a UNIX timestamp in milliseconds. There is no way to reset the nonce to a lower value, so be sure to use a generation method that won't produce numbers less than the previous nonce.
Problems can arise from requests arriving out of order due to API keys being shared across processes, or from system clock drift/recalibration.
Examples
- Python
- Go
- JavaScript
import time
# Nonce must be in nanoseconds (19 digits)
nonce = int(time.time() * 1000000000)
import "time"
// Nonce must be in nanoseconds (19 digits)
nonce := time.Now().UnixNano()
// Nonce must be in nanoseconds (19 digits)
const nonce = Date.now() * 1000000;
Complete Request Example
Here's a complete example making an authenticated GET request to list assets:
- Python
- JavaScript
import os
import json
import time
import hashlib
import hmac
import base64
import requests
API_KEY = os.environ.get("KRAKEN_API_KEY")
API_SECRET = os.environ.get("KRAKEN_API_SECRET")
BASE_URL = "https://embed.kraken.com"
def get_kraken_signature(urlpath, data, secret, nonce):
if data is None:
encoded = str(nonce).encode("utf-8")
else:
encoded = (str(nonce) + json.dumps(data)).encode("utf-8")
message = urlpath.encode() + hashlib.sha256(encoded).digest()
mac = hmac.new(base64.b64decode(secret), message, hashlib.sha512)
return base64.b64encode(mac.digest()).decode()
def list_assets():
endpoint = "/b2b/assets"
nonce = int(time.time() * 1000000000) # Nanoseconds
signature = get_kraken_signature(endpoint, None, API_SECRET, nonce)
headers = {
"API-Key": API_KEY,
"API-Sign": signature,
"API-Nonce": str(nonce),
}
response = requests.get(BASE_URL + endpoint, headers=headers)
return response.json()
assets = list_assets()
print(assets)
import crypto from 'crypto';
const API_KEY = process.env.KRAKEN_API_KEY;
const API_SECRET = process.env.KRAKEN_API_SECRET;
const BASE_URL = 'https://embed.kraken.com';
function getKrakenSignature(urlpath, data, secret, nonce) {
const encoded = data === null
? String(nonce)
: String(nonce) + JSON.stringify(data);
const sha256Hash = crypto.createHash('sha256').update(encoded).digest();
const message = Buffer.concat([Buffer.from(urlpath), sha256Hash]);
const secretBuffer = Buffer.from(secret, 'base64');
const hmac = crypto.createHmac('sha512', secretBuffer);
hmac.update(message);
return hmac.digest('base64');
}
async function listAssets() {
const endpoint = '/b2b/assets';
const nonce = Date.now() * 1000000; // Nanoseconds
const signature = getKrakenSignature(endpoint, null, API_SECRET, nonce);
const response = await fetch(BASE_URL + endpoint, {
method: 'GET',
headers: {
'API-Key': API_KEY,
'API-Sign': signature,
'API-Nonce': String(nonce),
},
});
return response.json();
}
const assets = await listAssets();
console.log(assets);
Query Parameters in Signature
When your request includes query parameters, they must be included in the URL path used for signature generation:
// Include query params in the signature path
const params = { 'page[size]': 10, quote: 'USD' };
const queryString = new URLSearchParams(params).toString();
const signaturePath = `/b2b/assets?${queryString}`;
const signature = getKrakenSignature(signaturePath, null, API_SECRET, nonce);
Troubleshooting
| Error | Cause | Solution |
|---|---|---|
Invalid signature | Signature doesn't match | Verify secret encoding, nonce, and body format |
Invalid nonce | Nonce is not increasing | Ensure nonce > previous nonce |
Missing API-Key | Header not set | Check header name is exactly API-Key |