Please note that the information below assumes the correct implementation of our Authentication Algorithm as it deals with potential input and formatting errors.
To learn more about our Authentication Algorithm please click HERE
Mismatch between Authentication Data and HTTP request
In order for a successful private call to be made, an HTTP POST request needs to be sent out to the appropriate endpoint.
This request includes the Header API-Sign (signature) which uses the encoded Post_data as part of its hashing algorithm.
If there is a discrepancy between the Signature included in the header and the POST data included in the request, an Invalid API Key error will be returned.
Below is an example of a correctly formulated call in which the data used in the Authentication Algorithm match that in the body of the request:
Python
#!/usr/bin/env python3
import time
import requests
import urllib.parse
import hashlib
import hmac
import base64
api_key = ''
secret_key = ''
nonce = str(int(1000 * time.time()))
# Define the URI path for the Kraken API request
uri_path = '/0/private/AddOrder'
# API URL
api_url = 'https://api.kraken.com'
# Create a dictionary for the request data
# Note that this is the data that will be used to calculate the Authentication Algorithm (API-Sign).
data = {
'nonce': nonce,
'ordertype': 'limit',
'type': 'buy',
'volume': '1',
'pair': 'btcusd',
'price': '58626.4',
'validate': True
}
# Encode the data for the request
postdata = urllib.parse.urlencode(data)
encoded = (str(data['nonce']) + postdata).encode()
# Create a message to be signed
message = uri_path.encode() + hashlib.sha256(encoded).digest()
# Create the HMAC signature
mac = hmac.new(base64.b64decode(secret_key), message, hashlib.sha512)
sigdigest = base64.b64encode(mac.digest())
# Create headers for the request
headers = {}
headers['API-Key'] = api_key
headers['API-Sign'] = sigdigest.decode()
# Make the POST request
# Note that the data below is what is sent in the HTTP request.
req = requests.post(api_url + uri_path, headers=headers, data={
'nonce': nonce,
'ordertype': 'limit',
'type': 'buy',
'volume': '1',
'pair': 'btcusd',
'price': '58626.4',
'validate': True
})
# Print the result
print(req.json())
# Result:
# {'error': [], 'result': {'descr': {'order': 'buy 1.00000000 XBTUSD @ limit 58626.4'}}}
However, when
ordertype
and volume
are interchanged an Invalid Key error is produced.Python
#!/usr/bin/env python3
import time
import requests
import urllib.parse
import hashlib
import hmac
import base64
api_key = ''
secret_key = ''
nonce = str(int(1000 * time.time()))
# Define the URI path for the Kraken API request
uri_path = '/0/private/AddOrder'
# API URL
api_url = 'https://api.kraken.com'
# Create a dictionary for the request data
data = {
'nonce': nonce,
'ordertype': 'limit',
'type': 'buy',
'volume': '1',
'pair': 'btcusd',
'price': '58626.4',
'validate': True
}
# Encode the data for the request
postdata = urllib.parse.urlencode(data)
encoded = (str(data['nonce']) + postdata).encode()
# Create a message to be signed
message = uri_path.encode() + hashlib.sha256(encoded).digest()
# Create the HMAC signature
mac = hmac.new(base64.b64decode(secret_key), message, hashlib.sha512)
sigdigest = base64.b64encode(mac.digest())
# Create headers for the request
headers = {}
headers['API-Key'] = api_key
headers['API-Sign'] = sigdigest.decode()
# Make the POST request
req = requests.post(api_url + uri_path, headers=headers, data={
'nonce': nonce,
'volume': '1',
'type': 'buy',
'ordertype': 'limit',
'volume': '1',
'pair': 'btcusd',
'price': '58626.4',
'validate': True
})
# Print the result
print(req.json())
# Result:
# {'error': ['EAPI:Invalid key']}
One indication that this may be the cause of the Invalid Key error is if calls to endpoints that do not require multiple parameters are successful (Balance, OpenOrders). If you continuously get a valid response from these calls, then the mismatch theory seems more plausible.
*Please note that in the above example, the Validate Parameter was used which simply validates the inputs only but does not submit the order. The parameter should be discarded for live trading*
Mismatch in Content Types
Having a mismatch between the content type of the body and the header can also lead to an Invalid API Key.
Please see below a scenario where both the Header as well as the Post data are URL encoded:
Python
api_key = ""
api_secret = base64.b64decode("")
api_domain = "https://api.kraken.com"
api_path = "/0/private/"
api_endpoint = "Balance" # {"error":[]} IS SUCCESS-EMPTY BALANCE
api_parameters = ""
api_nonce = str(int(time.time() * 1000))
api_postdata = api_parameters + "&nonce=" + api_nonce
api_postdata = api_postdata.encode('utf-8')
api_sha256Data = api_nonce.encode('utf-8') + api_postdata
api_sha256 = hashlib.sha256(api_sha256Data).digest()
api_hmacSha512Data = api_path.encode('utf-8') + api_endpoint.encode('utf-8') + api_sha256
api_hmacsha512 = hmac.new(api_secret, api_hmacSha512Data, hashlib.sha512)
api_sig = base64.b64encode(api_hmacsha512.digest())
api_url = api_domain + api_path + api_endpoint
api_request = urllib2.Request(api_url, api_postdata)
api_request.add_header("Content-Type", "application/x-www-form-urlencoded")
api_request.add_header("API-Key", api_key)
api_request.add_header("API-Sign", api_sig)
api_request.add_header("User-Agent", "Kraken REST API")
print("DEBUG DATA : ")
print("api_url : " + api_url)
print("api_endpoint : " + api_endpoint)
print("api_parameters : " + api_parameters)
print("")
api_reply = urllib2.urlopen(api_request).read()
api_reply = api_reply.decode()
print("API JSON DATA:")
print(api_reply)
sys.exit(0)
# Response:
# API JSON DATA:
# {"error":[],"result":{"ADA":"0.00000000","AIR":"0.0000000000","ALGO":"0.00000000","ATOM":"0.00000000",
# "AVAX":"0.0000000000","BONK":"0.24","BSX":"0.00","C98":"0.00000","CVC":"0.0000000000","DOT":"0.0000000058",
# "DYM":"1.001240","ETH2.S":"0.0000000000","FLOW":"0.0000000000","FLR":"0.0000","GRT":"0.0000000000","ICP":"0.00000000",
# "KAVA":"0.00000000","KFEE":"4619.88","KSM":"0.0457969620","KSM.S":"0.0000000000","MATIC":"0.0000000000",
# "MINA":"1.0067624751","MINA.S":"0.0000000000","PARA":"0.000","POLS":"0.00000","SBR":"0.00000000","SCRT":"0.00000000",
# "SCRT21.S":"0.00000000","SDN":"0.0000000000","SEI":"0.0000","SHIB":"0.00000","SOL":"0.0000069748","SOL.S":"0.0000000000",
# "SOL03.S":"0.0201035317","TIA":"0.000000","TRX":"0.00000000","USDC":"0.00000000","USDT":"0.00068726",
# "USDT.B":"3.53191423","WEN":"158958.59","WIF":"0.00000","XBT.M":"0.0001000103","XETH":"0.0000000000",
# "XTZ":"0.00000000","XXBT":"0.0000000000","XXDG":"24.34451185","XXMR":"0.0000000000","ZCAD":"0.0000",
# "ZEUR":"0.2732","ZUSD":"0.6353"}}
However, when we add the Content Type of the Header as JSON, we get an
EAPI:Invalid Key
Error.Python
api_key = ""
api_secret = base64.b64decode("")
api_domain = "https://api.kraken.com"
api_path = "/0/private/"
api_endpoint = "AddOrder" # {"error":[]} IS SUCCESS-EMPTY BALANCE
# api_parameters = "pair=xbtusd&ordertype=market&type=buy&volume=0.0001&validate=True"
api_parameters = ''
api_nonce = str(int(time.time() * 1000))
api_postdata = api_parameters + "&nonce=" + api_nonce
api_postdata = api_postdata.encode('utf-8')
api_sha256Data = api_nonce.encode('utf-8') + api_postdata
api_sha256 = hashlib.sha256(api_sha256Data).digest()
api_hmacSha512Data = api_path.encode('utf-8') + api_endpoint.encode('utf-8') + api_sha256
api_hmacsha512 = hmac.new(api_secret, api_hmacSha512Data, hashlib.sha512)
api_sig = base64.b64encode(api_hmacsha512.digest())
api_url = api_domain + api_path + api_endpoint
api_request = urllib2.Request(api_url, api_postdata)
print("DEBUG DATA : ")
print("api_url : " + api_url)
print("api_endpoint : " + api_endpoint)
print("api_parameters : " + api_parameters)
print("")
headers = {}
headers['API-Key'] = api_key
headers['API-Sign'] = api_sig
headers['Content-Type'] = 'application/json'
headers['Accepts'] = 'application/json'
headers['User-Agent'] = "Kraken REST API"
api_reply = urllib2.urlopen(api_request).read()
api_reply = api_reply.decode()
data = {'nonce': api_nonce}
req = requests.post(api_url, headers=headers, data=data)
print(req.json())
print("API JSON DATA:")
print(api_reply)
sys.exit(0)
# API JSON DATA:
# {"error":["EAPI:Invalid key"]}
*Note that it is possible use either URL encoded data or JSON encoded data, but the data must match exactly in both the SHA256 input and the HTTP request.*
Missing or incomplete endpoint Path
An Invalid Key error can also be caused by passing an incomplete or missing endpoint URI (for example "AddOrder" as oppose to “/0/private/AddOrder”).
In order for the Authentication Algorithm to correctly create the API-Sign Header, it needs to make use of the URI in its entirety ( for example "/0/private/AddOrder”). If any part of this URI is truncated, it will lead to a wrong value for API-Sign and hence an Invalid Key error.
Below is an example of only “AddOrder” being passed in for encoding rather than the full endpoint URI “/0/private/AddOrder”
Python
api_key = ''
secret_key = ''
# Define the URI path for the Kraken API request
uri_path = 'AddOrder'
# API URL
api_url = 'https://api.kraken.com/0/private/'
# Create a dictionary for the request data
data = {
"nonce": str(int(1000 * time.time())),
"ordertype": 'limit',
'type': 'buy',
'volume': '0.07617478622420963',
'pair': 'SOLUSD',
'price': '127.47',
'validate': 'true'
}
# Encode the data for the request
postdata = urllib.parse.urlencode(data)
encoded = (str(data['nonce']) + postdata).encode()
# Create a message to be signed
message = uri_path.encode() + hashlib.sha256(encoded).digest()
# Create the HMAC signature
mac = hmac.new(base64.b64decode(secret_key), message, hashlib.sha512)
sigdigest = base64.b64encode(mac.digest())
# Create headers for the request
headers = {}
headers['API-Key'] = api_key
headers['API-Sign'] = sigdigest.decode()
# Make the POST request
req = requests.post(api_url + uri_path, headers=headers, data=data)
# Print the result
print(req.json())
# Result:
# {'error': ['EAPI:Invalid key']}
Using Plain Text in the Authentication, But Percent Encoding in the Request
Another common issue that causes an Invalid Key Error is a mismatch of encoding between the POST request and the HTTP authentication.
In the example below, ‘Data’ which is passed to the POST request is URL formatted (with spaces encoded as ‘+’) as application
/x-www-form-urlencoded
content-type whereas ‘data_formatted’ is encoding spaces as ‘%20’. While in both examples the spaces are encoded, the data that is passed to the authentication algorithm and the POST request are not exactly the same. This will lead to an Invalid Key error.
Python
# Define the URI path for the Kraken API request
uri_path = '/0/private/DepositAddresses'
# API URL
api_url = 'https://api.kraken.com'
# Calculate Nonce for both data variables
nonce = str(int(1000 * time.time()))
# Create a dictionary for the request data
data = {
"nonce": nonce,
"asset": 'BTC',
'method': 'Bitcoin Lightning',
'amount': '0.2',
'new': True
}
postdata_data = urllib.parse.urlencode(data)
# Encode the data for the request manually
data_formatted = f'nonce={nonce}&asset=BTC&method=Bitcoin%20Lightning&amount=0.2&new=True'
postdata = data_formatted
encoded = (nonce + postdata).encode()
# Create a message to be signed
message = uri_path.encode() + hashlib.sha256(encoded).digest()
# Create the HMAC signature
mac = hmac.new(base64.b64decode(secret_key), message, hashlib.sha512)
sigdigest = base64.b64encode(mac.digest())
# Create headers for the request
headers = {}
headers['API-Key'] = api_key
headers['API-Sign'] = sigdigest.decode()
# Make the POST request
req = requests.post(api_url + uri_path, headers=headers, data=data)
# Print the result
print(req.json())
# Result:
# {'error': ['EAPI:Invalid key']}
To illustrate this clearly, please see below the 2 different formats for Data:
Plaintext
data = nonce=1719929687102&asset=BTC&method=Bitcoin+Lightning&amount=0.2&new=True
data_formatted = nonce=1719929687102&asset=BTC&method=Bitcoin%20Lightning&amount=0.2&new=True
*It is possible to use either plain text or percent encoded as long as the format is the same in both the Authentication data as well as the request.*