유효하지 않은 키 오류의 일반적인 원인

최종 업데이트: 2025년 6월 5일

성공적인 비공개 호출을 위해서는 적절한 엔드포인트로 HTTP POST 요청을 보내야 합니다.

이 요청에는 인코딩된 Post_data를 해싱 알고리즘의 일부로 사용하는 헤더 API-Sign(서명)이 포함됩니다.

헤더에 포함된 서명과 요청에 포함된 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']}

유효하지 않은 키 오류의 원인이 될 수 있는 한 가지 징후는 여러 매개변수를 필요로 하지 않는 엔드포인트(Balance, OpenOrders)에 대한 호출이 성공하는 경우입니다. 이러한 호출에서 계속해서 유효한 응답을 받는다면, 불일치 이론이 더 타당해 보입니다.

*위 예시에서 Validate Parameter는 입력을 검증하기만 하고 주문을 제출하지는 않습니다. 실시간 거래에서는 이 매개변수를 사용하지 않아야 합니다.*

본문과 헤더의 콘텐츠 유형이 일치하지 않는 경우에도 유효하지 않은 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"}}

그러나 헤더의 콘텐츠 유형을 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에 잘못된 값이 생성되어 유효하지 않은 키 오류가 발생합니다.

아래는 전체 엔드포인트 URI “/0/private/AddOrder” 대신 “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']}

이를 명확히 설명하기 위해 아래에 데이터의 두 가지 다른 형식을 참조하십시오.

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

*인증 데이터와 요청 모두에서 형식이 동일하다면 일반 텍스트 또는 퍼센트 인코딩을 사용할 수 있습니다.*

더 많은 도움이 필요하신가요?