Fixing Kraken API Errors: Auth, Codes and Rate Limits
Master Kraken API error handling — from unauthorized errors and invalid signatures to rate limits. Includes Python code examples for authentication setup and error recovery.
Master Kraken API error handling — from unauthorized errors and invalid signatures to rate limits. Includes Python code examples for authentication setup and error recovery.
Working with the Kraken API is a rite of passage for any serious crypto algo trader. The exchange offers one of the most reliable and well-documented REST APIs in the industry — but when you're setting up your first trading bot or building a portfolio dashboard, you will almost certainly run into a wall of cryptic error messages. A kraken api error unauthorized response when you are sure the credentials are right. A rate limit error that kills your bot at 3 AM. An invalid signature that makes zero sense until you understand exactly how Kraken's HMAC authentication works. These errors are not random. Every Kraken API error maps to a specific cause, and once you understand the patterns, they are almost always fixable in minutes. Whether you're connecting to check prices or automating full execution, this guide covers the real causes and the actual fixes — with working code.
The Kraken API always returns a consistent JSON envelope. Every response has two top-level fields: error and result. If the error array is empty, the request succeeded. If anything is in that array, something went wrong. Each error string follows a Category:Subcategory format, which makes them machine-readable and easy to branch on in your code. This is actually more structured than what you get from Binance or KuCoin, where errors sometimes come back as HTTP status codes, sometimes as custom message fields, depending on the endpoint version. Knowing the category tells you immediately whether you are dealing with a credentials problem, a request problem, or a server-side issue — and that determines your retry strategy.
| Error Code | Category | Most Likely Cause |
|---|---|---|
| EAPI:Invalid key | Authentication | API key copied with whitespace, deleted, or wrong account |
| EAPI:Invalid signature | Authentication | Signature calculation error — wrong nonce or POST data encoding |
| EAPI:Invalid nonce | Authentication | Nonce not strictly increasing, or clock drift between requests |
| EAPI:Rate limit exceeded | Rate Limiting | Too many private endpoint calls in a short window |
| EAPI:Feature disabled | Permissions | API key missing required permission (e.g. Trade, Withdraw) |
| EGeneral:Invalid arguments | Request | Missing or malformed request parameter |
| EOrder:Insufficient funds | Order | Account balance too low to place the order |
| EService:Unavailable | Server | Kraken servers temporarily down — retry with backoff |
| EService:Busy | Server | Server overloaded — brief pause then retry |
The kraken api authentication error category is where most developers get stuck on their first integration. The two most frequent offenders are EAPI:Invalid key and EAPI:Invalid signature. EAPI:Invalid key means Kraken cannot find your API key at all — it either does not exist, was deleted, or was copied incorrectly. This one is usually a copy-paste issue, often a trailing newline or whitespace character that is invisible but breaks the lookup. EAPI:Invalid signature is trickier because the key exists but the signature you computed does not match what Kraken expects. Kraken uses HMAC-SHA512 authentication where the signature is computed from a combination of the nonce, the URL-encoded POST body, and the endpoint path — in a specific order. Any deviation breaks it silently.
The nonce deserves special attention. Kraken requires nonces to be strictly increasing integers — each new request must have a nonce larger than the previous one. If you are running multiple bot instances sharing the same API key, or if your server clock drifts, or if you simply reuse a nonce by accident, you will get EAPI:Invalid nonce errors that appear completely random. The safest approach is to use millisecond timestamps as your nonce source and make sure each request generates a fresh one. Never hardcode a nonce for testing.
Pro tip: EAPI:Invalid nonce is often caused by running the same API key on two machines simultaneously. Each machine generates nonces independently, and Kraken only accepts strictly increasing values per key. Solution: use dedicated API keys per bot instance.
Here is a complete Python implementation of Kraken API authentication. This follows the official signature algorithm exactly and includes a private endpoint call to fetch your account balance. Notice how the nonce is embedded in both the POST data and the signature computation — this is the step most people get wrong when rolling their own implementation.
import hashlib
import hmac
import base64
import time
import urllib.parse
import requests
API_KEY = "your_api_key_here"
API_SECRET = "your_api_secret_here"
def get_kraken_signature(urlpath, data, secret):
postdata = urllib.parse.urlencode(data)
encoded = (str(data['nonce']) + postdata).encode()
message = urlpath.encode() + hashlib.sha256(encoded).digest()
mac = hmac.new(base64.b64decode(secret), message, hashlib.sha512)
return base64.b64encode(mac.digest()).decode()
def kraken_request(uri_path, data):
headers = {
'API-Key': API_KEY,
'API-Sign': get_kraken_signature(uri_path, data, API_SECRET)
}
resp = requests.post(
'https://api.kraken.com' + uri_path,
headers=headers,
data=data
)
return resp.json()
# Fetch account balance
data = {'nonce': str(int(1000 * time.time()))}
result = kraken_request('/0/private/Balance', data)
if result['error']:
print(f"Auth failed: {result['error']}")
else:
balances = result['result']
print(f"BTC balance: {balances.get('XXBT', '0')}")
print(f"USD balance: {balances.get('ZUSD', '0')}")
The get_kraken_signature function is the core of every authenticated request. It takes the URL path (like /0/private/Balance), the POST data dict including the nonce, and your API secret. The computation chain is: URL-encode the POST data, prepend the nonce string, SHA256-hash that, prepend the raw URL path bytes, then HMAC-SHA512 the whole thing using your base64-decoded secret. The result is base64-encoded and sent in the API-Sign header. If any step is out of order, you will get EAPI:Invalid signature every time.
Public endpoints like the ticker, orderbook, and OHLC data do not require authentication at all. These are useful for building price monitors, checking spreads, or pulling historical candle data for analysis. The kraken api price endpoint is /0/public/Ticker and accepts a comma-separated list of trading pairs. Compared to similar public APIs on Coinbase and Bybit, Kraken returns more data per call — including VWAP, trade count, and 24-hour volume alongside the bid/ask. Platforms like VoiceOfChain use aggregated price feeds across multiple exchanges to generate trading signals, combining real-time data from Kraken, Binance, and OKX for cross-exchange validation.
import requests
def get_kraken_price(pair="XBTUSD"):
"""Fetch current ticker - no authentication required"""
url = f"https://api.kraken.com/0/public/Ticker?pair={pair}"
resp = requests.get(url)
data = resp.json()
if data['error']:
raise ValueError(f"Kraken API error: {data['error']}")
ticker = data['result'][pair]
return {
'last': float(ticker['c'][0]),
'bid': float(ticker['b'][0]),
'ask': float(ticker['a'][0]),
'vwap_24h': float(ticker['p'][1]),
'volume_24h': float(ticker['v'][1]),
'trades_24h': int(ticker['t'][1])
}
# Get BTC/USD and ETH/USD prices in one call
def get_multiple_prices(pairs):
pair_str = ','.join(pairs)
url = f"https://api.kraken.com/0/public/Ticker?pair={pair_str}"
resp = requests.get(url)
data = resp.json()
if data['error']:
raise ValueError(f"Kraken error: {data['error']}")
results = {}
for pair, ticker in data['result'].items():
results[pair] = {
'last': float(ticker['c'][0]),
'ask': float(ticker['a'][0]),
'bid': float(ticker['b'][0])
}
return results
prices = get_multiple_prices(['XBTUSD', 'ETHUSD', 'SOLUSD'])
for pair, p in prices.items():
print(f"{pair}: ${p['last']:,.2f} (bid ${p['bid']:,.2f} / ask ${p['ask']:,.2f})")
Kraken's rate limiting system is one of the more nuanced ones in the industry. Public endpoints allow roughly one request per second per IP address. Private endpoints use a counter-based system tied to your account verification tier. When the counter exceeds the limit, you get EAPI:Rate limit exceeded. The counter starts at a maximum value (15 for Starter, 20 for Intermediate and Pro tiers) and increments by 1 per request. It decays back down over time — at a rate of roughly 1 per second for Starter accounts, and faster for higher tiers. This means burst requests drain the counter quickly, but spacing your calls out lets it recover. Compare this to Binance's weight-based system or Bybit's category-specific request limits — Kraken's approach rewards steady, evenly-spaced calls over aggressive bursting. Gate.io and KuCoin both use similar decay mechanisms for their private APIs. The practical implication: if your bot fires 20 private requests in under 5 seconds, it will hit the limit and need to back off. Design for cadence, not throughput.
import time
def safe_kraken_request(uri_path, data, max_retries=4):
"""Kraken request with exponential backoff and error classification"""
for attempt in range(max_retries):
# Always refresh nonce on every attempt
data['nonce'] = str(int(1000 * time.time()))
result = kraken_request(uri_path, data)
# Success
if not result.get('error'):
return result['result']
errors = result['error']
# Rate limited — exponential backoff
if 'EAPI:Rate limit exceeded' in errors:
wait = 2 ** attempt # 1s, 2s, 4s, 8s
print(f"Rate limited. Backing off {wait}s (attempt {attempt+1}/{max_retries})")
time.sleep(wait)
continue
# Auth errors — fix the key/secret, no point retrying
if any('EAPI:Invalid' in e for e in errors):
raise Exception(f"Authentication error — check key/secret/nonce: {errors}")
# Server busy — short pause then retry
if any('EService' in e for e in errors):
print(f"Kraken service error: {errors}. Retrying in 2s...")
time.sleep(2)
continue
# All other errors — raise immediately
raise Exception(f"Kraken API error: {errors}")
raise Exception(f"Request failed after {max_retries} attempts")
# Usage example — place a limit order with retry handling
try:
order_data = {
'ordertype': 'limit',
'type': 'buy',
'volume': '0.001',
'pair': 'XBTUSD',
'price': '60000'
}
result = safe_kraken_request('/0/private/AddOrder', order_data)
print(f"Order placed: {result['txid']}")
except Exception as e:
print(f"Order failed: {e}")
Rate limit tip: Kraken recommends spacing private API calls at least 1 second apart for Starter accounts. For production bots, use a token bucket or leaky bucket algorithm to smooth out your request cadence rather than relying solely on retry logic. If you trade programmatically at volume, upgrading your account verification tier doubles the rate limit headroom.
Tools like VoiceOfChain's signal platform avoid this problem entirely for price monitoring by subscribing to Kraken's WebSocket feed instead of polling REST endpoints. WebSocket connections bypass the per-request rate limits for market data, making them far more efficient for real-time price tracking in bots. For private order management, the WebSocket private feed also supports authenticated order placement and status updates without hitting REST limits.
Kraken API errors follow a consistent, logical pattern once you know the vocabulary. Authentication errors (EAPI:Invalid key, EAPI:Invalid signature, EAPI:Invalid nonce) are almost always a credentials or nonce generation problem — fix the setup once and they go away permanently. Rate limit errors are a design signal telling you to space out your requests or use WebSockets for market data. Server errors (EService:Unavailable, EService:Busy) are transient and handled cleanly with exponential backoff. Build your error handling layer around these three categories from day one, and your Kraken-connected bots will be genuinely production-ready. If you want pre-built signals without managing raw API connections yourself, platforms like VoiceOfChain handle the exchange connectivity layer and deliver actionable alerts directly — letting you focus on strategy rather than infrastructure.