Short answer: To use the Kraken API in Python, call api.kraken.com with requests: public endpoints need no key, and private ones need API-Key and API-Sign headers. API-Sign is an HMAC-SHA512 of the URI path plus SHA256(nonce + POST data), keyed with your Base64-decoded secret. Every private request also needs an always-increasing nonce, which is why one key shared across processes causes errors. Kraken lists no official Python SDK, and Spot test access is by request.
Debug signing with a sample or testnet key and budget your requests: HMAC signature generator and API rate limit calculator.
Two details on Kraken's REST API need care: the nonce and the separate counters behind its rate limit errors. This guide follows Kraken's official documentation as read on 4 November 2026; general concepts are in crypto exchange API integration.
What was run and what was not. Samples ran on 4 November 2026 on Python 3.11.3 against public endpoints and Kraken's published signature example. No private endpoint was called, not even with a fake key, because of the IP lockout rule described below. Live authentication, orders, validate and private streams are untested here.
This is a technical guide, not a recommendation to use Kraken or any strategy, and availability depends on your jurisdiction and Kraken's terms. For readers in Turkey, Article 99/A of Capital Markets Law No. 6362 treats activity by foreign-based crypto-asset platforms directed at Turkish residents as unauthorized service provision, so foreign platforms may not target them. Automated trading can lose money.
Kraken API Python setup: Spot, Derivatives and Kraken Pro keys
Kraken runs two separate engines, Spot and Derivatives, each with its own hosts, authentication and limits.
| Item | Spot | Derivatives |
|---|---|---|
| REST | https://api.kraken.com | https://futures.kraken.com |
| WebSocket | wss://ws.kraken.com/v2 | wss://futures.kraken.com/ws/v1 |
| Private headers | API-Key, API-Sign | APIKey, Authent |
- Python. Kraken's SDK page lists official SDKs for Go and Rust. Its only Python entry,
kraken-wsclient-py, is under community libraries, covers Spot WebSocket only and is not officially maintained. - Kraken Pro keys. The documents read describe no separate Pro API; keys are created in Kraken Pro under Settings, then API. See the exchange API key guide.
- Permissions. For Spot trading, the permissions page lists Query Funds, Query Open Orders and Trades, Create and Modify Orders, and Cancel/Close Orders. Leave Withdraw Funds off, as API key security for trading bots explains.
- FIX. The overview lists FIX 4.4 for both engines, aimed at institutional use; the FIX vs REST guide explains the trade-offs.
Kraken API Python example: public endpoints
Public endpoints under /0/public need no key and return an error array that you must check on every response.
from decimal import Decimal, ROUND_DOWN
import requests
BASE = "https://api.kraken.com/0/public"
def get(method, **params):
body = requests.get(f"{BASE}/{method}", params=params, timeout=10).json()
if body["error"]: # failures arrive in this array
raise RuntimeError(body["error"])
return body["result"]
def floor_to(value, step):
step = Decimal(step)
return (Decimal(value) / step).to_integral_value(rounding=ROUND_DOWN) * step
print(get("Time")["rfc1123"], get("SystemStatus")["status"])
key, pair = next(iter(get("AssetPairs", pair="XBTUSD").items()))
last = get("Ticker", pair="XBTUSD")[key]["c"][0] # c = last trade [price, volume]
price = floor_to(Decimal(last) * Decimal("0.95"), pair["tick_size"]) # hypothetical
print(key, pair["altname"], pair["wsname"], pair["tick_size"], pair["ordermin"], pair["costmin"])
print(last, price)
Output on 4 November 2026:
Wed, 04 Nov 26 19:48:04 +0000 online
XXBTZUSD XBTUSD XBT/USD 0.1 0.00006 0.5
80013.70000 76013.0
XBTUSD comes back keyed as XXBTZUSD, and WebSocket v2 calls it BTC/USD, so keep a symbol map. Kraken's error page names tick_size, ordermin and costmin as the fields behind its order rejections.
Hypothetical example. A limit 5% below 80,013.7 USD is 76,013.015, which floors to 76,013.0 at a 0.1 tick. At 0.00006 BTC, the minimum order, the cost is about 4.56 USD, above the 0.5 USD costmin. This shows the rounding only.
How to sign Kraken requests: the API-Sign test vector
Kraken publishes a full signature example, so you can prove your signing code correct before you own a key.
import base64, hashlib, hmac, urllib.parse
import requests
def kraken_sign(path, data, secret):
encoded = (str(data["nonce"]) + urllib.parse.urlencode(data)).encode()
message = path.encode() + hashlib.sha256(encoded).digest()
mac = hmac.new(base64.b64decode(secret), message, hashlib.sha512)
return base64.b64encode(mac.digest()).decode()
def prepare(method, api_key, secret, **params):
path = f"/0/private/{method}"
headers = {"API-Key": api_key, "API-Sign": kraken_sign(path, params, secret),
"Content-Type": "application/x-www-form-urlencoded"}
return requests.Request("POST", "https://api.kraken.com" + path, headers=headers,
data=urllib.parse.urlencode(params)).prepare()
# Kraken's published documentation example, not a live key
SECRET = "kQH5HW/8p1uGOVjbgWA7FunAmGO8lsSUXNsu3eow76sz84Q18fWxnyRzBHCd3pd5nE9qa99HAZtuZuj6F1huXg=="
EXPECTED = "4/dpxb3iT4tp/ZCVEwSnEsLxx0bqyhLpdfOpc6fn7OR8+UClSV5n9E6aSS8MPtnRfp32bAb0nmbRn6H8ndwLUQ=="
req = prepare("AddOrder", "example-public-key", SECRET, nonce="1616492376594",
ordertype="limit", pair="XBTUSD", price=37500, type="buy", volume=1.25)
print(req.headers["API-Sign"] == EXPECTED)
print(req.body)
Output on 4 November 2026:
True
nonce=1616492376594&ordertype=limit&pair=XBTUSD&price=37500&type=buy&volume=1.25
The secret and expected value come from Kraken's authentication guide and belong to no live account. prepare builds the request without sending it; to send a real one, use requests.Session().send(req, timeout=10), which was not run.
- The path in the signature starts at
/0/private. - The secret must be Base64-decoded first, and the string you sign must be the body you send.
- Add
otpif the key has two-factor authentication enabled. - Do not test a wrong key by retrying. Kraken says repeated
EAPI:Invalid keyresponses triggerEGeneral:Temporary lockoutfor every key on that IP address, clearing after about 20 minutes.
Kraken nonce: why shared API keys break
Each request's nonce must be higher than the last one accepted for that API key, so two processes sharing a key will sooner or later reject each other's requests.
Kraken's guide specifies an always-increasing unsigned 64-bit integer, usually a Unix timestamp in milliseconds, that cannot be reset to a lower value. Out-of-order requests, shared keys and clock drift cause EAPI:Invalid nonce, and too many invalid nonces can bring temporary bans. Its error page advises a counter with a mutex when threads share a key:
import threading, time
class NonceSource:
"""One per API key, shared by every thread that uses the key."""
def __init__(self):
self._lock, self._last = threading.Lock(), 0
def next(self):
with self._lock:
self._last = max(self._last + 1, int(time.time() * 1000))
return str(self._last)
source, out = NonceSource(), []
threads = [threading.Thread(target=lambda: out.extend(source.next() for _ in range(1000)))
for _ in range(4)]
for t in threads: t.start()
for t in threads: t.join()
print(len(out), len(set(out))) # 4,000 nonces, all distinct
It printed 4000 4000. Working rules:
- Use one key per process, because a mutex protects threads, not separate processes.
- Keep the host clock synchronized, and never let it move backward under a time-based nonce.
- Kraken's optional nonce window adds tolerance between nonce values.
Kraken API rate limit exceeded: which counter?
The error text tells you which counter you hit: EAPI:Rate limit exceeded is the REST call counter, and EOrder:Rate limit exceeded is the per-pair trading counter.
| Error | Meaning | Response |
|---|---|---|
EAPI:Rate limit exceeded | REST counter for this key passed its maximum | Pause; continuing to call extends the restriction |
EOrder:Rate limit exceeded | Trading counter for this pair reached its threshold | Reduce order activity; amend instead of cancel and replace |
EService: Throttled | Too many concurrent requests | Retry after the timestamp in the message |
| Item | Starter | Intermediate | Pro |
|---|---|---|---|
| REST counter maximum | 15 | 20 | 20 |
| REST decay per second | 0.33 | 0.5 | 1 |
| Trading counter threshold, per pair | 60 | 125 | 180 |
| Trading decay per second | 1 | 2.34 | 3.75 |
| Open orders per pair | 60 | 80 | 225 |
Ledger and trade history calls add 2 to the REST counter and other calls add 1, except AddOrder and CancelOrder, which use the trading limiter. That limiter is shared across REST, WebSocket and FIX. It charges more for canceling young orders: Add Order adds 1, while a cancel adds 8 under 5 seconds of resting time and nothing after 300 seconds.
Hypothetical example. Downloading 50 ledger pages adds 100 to the REST counter. To stay at or under the maximum, a Starter key must spread them over about (100 - 15) / 0.33 = 258 seconds, and a Pro key over (100 - 20) / 1 = 80 seconds.
Is there a Kraken testnet?
Kraken has no open Spot testnet: Spot UAT is by request through an account manager, and the self-serve futures demo in its developer docs did not respond as an API when tested.
- Spot UAT. The quickstart says it uses a separate base URL and isolated keys; the docs name UAT hosts only for FIX. A support article limits test access to qualified clients.
- Futures demo: conflicting sources. The Exchange overview and quickstart still list
demo-futures.kraken.comas self-service. Kraken's API Testing Environment article (updated 29 October 2026) says it was decommissioned at 13 UTC on Monday, 14 July, without a year; 14 July last fell on a Monday in 2025. On 4 November 2026 our REST and WebSocket requests got an HTTP 301 to a Kraken marketing page. Treat it as unavailable unless Kraken says otherwise. validate. AddOrder takesvalidate=true, which validates without trading and returns no order ID. It needs a real key and was not run.
Kraken's FAQ also suggests very small or far-from-market orders. Those are real orders with real risk, so they belong after review and hard limits.
Kraken Futures API in Python
Derivatives REST uses APIKey and Authent headers, where Authent is built from postData + nonce + endpoint path, and public endpoints carry no cost.
import base64, hashlib, hmac
import requests
def authent(post_data, nonce, endpoint_path, secret):
digest = hashlib.sha256((post_data + nonce + endpoint_path).encode()).digest()
mac = hmac.new(base64.b64decode(secret), digest, hashlib.sha512)
return base64.b64encode(mac.digest()).decode()
data = requests.get("https://futures.kraken.com/derivatives/api/v3/tickers", timeout=10).json()
t = next(x for x in data["tickers"] if x["symbol"] == "PF_XBTUSD")
print(data["result"], t["symbol"], t["bid"], t["ask"], t["suspended"])
secret = base64.b64encode(b"throwaway secret, never registered").decode()
print(len(authent("symbol=PF_XBTUSD", "1415957147987", "/api/v3/sendorder", secret)))
Output on 4 November 2026, from the public endpoint:
success PF_XBTUSD 80018 80019 False
88
On the same inputs, authent matched sign_message in CryptoFacilities' REST-v3-Python, from the GitHub organization Kraken's testing article links. Kraken publishes no expected value, and it was not sent to a private endpoint.
- Path. Sign
/api/v3/sendorder, without the/derivativesprefix in the URL. - Inputs. The nonce is optional. Hash parameters URL-encoded, as sent; Kraken said it aimed to retire hashing decoded values on 1 October 2025.
- Budget. Clients can spend 500 every 10 seconds on
/derivativesendpoints.sendorder,editorderandcancelordercost 10 each, andopenorderscosts 2. Going over returnsapiLimitExceeded. - Success is not placement.
result: successonly means the request was assessed; readsendStatus.status, which can sayinsufficientAvailableFunds.
Derivatives add leverage and liquidation risk, and nothing here suggests using them. Independent controls are in trading bot risk management.
Kraken WebSocket API v2 in Python
Spot WebSocket v2 streams public channels from wss://ws.kraken.com/v2 with no key, using a method and params message.
import asyncio, json
import websockets # pip install websockets
async def main():
async with websockets.connect("wss://ws.kraken.com/v2") as ws:
await ws.send(json.dumps({"method": "subscribe",
"params": {"channel": "ticker", "symbol": ["BTC/USD"]}}))
while True:
msg = json.loads(await asyncio.wait_for(ws.recv(), 15))
if msg.get("channel") == "status":
print(msg["data"][0]["system"], msg["data"][0]["api_version"])
elif msg.get("method") == "subscribe":
print("subscribed", msg["success"])
elif msg.get("channel") == "ticker":
d = msg["data"][0]
print(msg["type"], d["symbol"], d["bid"], d["ask"])
return
asyncio.run(main())
Output on 4 November 2026:
online v2
subscribed True
snapshot BTC/USD 80015.3 80015.4
Private channels such as executions and balances use wss://ws-auth.kraken.com/v2 and a token from the GetWebSocketsToken REST endpoint, valid for 15 minutes; the key needs the Access WebSocket API permission. That path was not run. For depth data, the book channel and its checksum follow the ideas in the local order book guide.
Frequently asked questions
Does Kraken have an official Python SDK?
Kraken's SDK page lists official SDKs for Go and Rust. Its Python entry, kraken-wsclient-py, is a community library covering Spot WebSocket only and is not officially maintained.
Is there a Kraken testnet?
Not an open one for Spot: UAT access is by request through an account manager. Developer docs list a futures demo at demo-futures.kraken.com, but a support article says it was decommissioned, and it redirected when tested on 4 November 2026.
What does EAPI:Rate limit exceeded mean?
The REST call counter for that API key passed its maximum of 15 or 20, depending on tier. Pause while the counter decays. EOrder:Rate limit exceeded is a different, per-pair trading counter.
Is the Kraken Pro API different from the Spot API?
The documents read describe Spot and Derivatives engines and no separate Pro API. Kraken's support article creates API keys in Kraken Pro under Settings, then API.
Sources
- Kraken: Exchange overview (hosts, sandbox row) (opens in a new tab)
- Kraken: Spot REST Authentication (API-Sign example, nonce) (opens in a new tab)
- Kraken: Spot REST Rate Limits (opens in a new tab)
- Kraken: Spot Trading Limits (opens in a new tab)
- Kraken: Error messages (opens in a new tab)
- Kraken: API key permissions and WebSocket token validity (opens in a new tab)
- Kraken: Quickstart (UAT) (opens in a new tab)
- Kraken Support: API Testing Environment (demo decommission notice, updated 29 October 2026) (opens in a new tab)
- Kraken Support: Advanced API FAQ (test environment, validate) (opens in a new tab)
- Kraken: Derivatives REST (Authent, responses) (opens in a new tab)
- Kraken: Derivatives Rate Limits (opens in a new tab)
- Kraken: Spot WebSocket hosts and ticker channel (opens in a new tab)
- Kraken Support: How to create an API key on Kraken Pro (opens in a new tab)
- Kraken: SDKs (official and community libraries) (opens in a new tab)
- Capital Markets Law No. 6362 (consolidated text, Article 99/A, Turkish) (opens in a new tab)
This guide is general information about software and markets, not investment, legal or tax advice. Automated trading can lose money, past or backtested performance does not guarantee future results, and the rules that apply depend on your jurisdiction and your exchange's terms. Sources, checks and corrections: see the editorial policy.