API 密钥无效的常见原因

上次更新时间: 2025年6月5日

为了成功进行私有调用,需要向相应的端点发送 HTTP POST 请求。

此请求包含 Header API-Sign(签名),它使用编码的 Post_data 作为其哈希算法的一部分。

如果请求头中包含的签名与请求中包含的 POST 数据之间存在差异,则会返回“API 密钥无效”错误。

以下是一个正确构建的调用示例,其中身份验证算法中使用的数据与请求正文中的数据匹配:

python

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'}}}

但是,当 ordertype 和 volume 互换时,会产生“密钥无效”错误。

python

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']}

导致“密钥无效”错误的一个迹象是,如果对不需要多个参数的端点(余额、未结订单)的调用成功。如果您持续从这些调用中获得有效响应,那么不匹配理论似乎更合理。

*请注意,在上述示例中,使用了“验证参数”,它仅验证输入但不提交订单。该参数应在实盘交易中丢弃*

请求正文和请求头的 Content-Type 不匹配也可能导致“API 密钥无效”错误。

请看下面一个场景,其中请求头和 POST 数据都经过 URL 编码:

 

python

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"}}

但是,当我们把请求头的 Content Type 设置为 JSON 时,我们会收到

EAPI: 密钥无效错误。

 

python

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"]}

*请注意,可以使用 URL 编码数据或 JSON 编码数据,但数据在 SHA256 输入和 HTTP 请求中必须完全匹配。*

“密钥无效”错误也可能是由于传递了不完整或缺失的端点 URI(例如“AddOrder”而不是“/0/private/AddOrder”)造成的。

为了使身份验证算法正确创建 API-Sign 请求头,它需要使用完整的 URI(例如“/0/private/AddOrder”)。如果此 URI 的任何部分被截断,将导致 API-Sign 的值错误,从而导致“密钥无效”错误。

以下是一个示例,其中只传递了“AddOrder”进行编码,而不是完整的端点 URI “/0/private/AddOrder”

python

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']}

导致“密钥无效”错误的另一个常见问题是 POST 请求和 HTTP 身份验证之间的编码不匹配。

在下面的示例中,传递给 POST 请求的“Data”是 URL 格式(空格编码为“+”)的 application/x-www-form-urlencoded 内容类型,而“data_formatted”将空格编码为“%20”。

虽然在这两个示例中空格都经过编码,但传递给身份验证算法的数据和 POST 请求的数据并不完全相同。这将导致“密钥无效”错误。

 

python

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']}

为了清楚地说明这一点,请参阅下面数据的 2 种不同格式:

bash

Bash

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

*可以使用纯文本或百分比编码,只要格式在身份验证数据和请求中都相同即可。*

需要更多帮助吗?