# Kraken API in Python: nonce, signing and rate limits

URL: https://fincodelabs.com/en/blog/kraken-api-python · Publisher: Fincode (Fincode Yazılım ve Teknoloji A.Ş.), Istanbul, Turkey · Category: Exchange APIs · Published: 2026-11-05 · Updated: 2026-11-05

Kraken API Python guide: API-Sign test vector, nonce rules, rate limit exceeded errors, Spot UAT and the futures demo status, Derivatives auth and WebSocket v2.

**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.

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](https://fincodelabs.com/en/blog/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.

**Kraken Exchange APIs, from the Exchange overview and authentication guides, 4 November 2026**

| 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](https://fincodelabs.com/en/blog/exchange-api-key-how-to).
- **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](https://fincodelabs.com/en/blog/api-key-security-trading-bots) explains.
- **FIX.** The overview lists FIX 4.4 for both engines, aimed at institutional use; the [FIX vs REST guide](https://fincodelabs.com/en/blog/broker-api-integration-fix-rest) 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.

```python
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.

```python
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 `otp` if the key has two-factor authentication enabled.
- Do not test a wrong key by retrying. Kraken says repeated `EAPI:Invalid key` responses trigger `EGeneral:Temporary lockout` for 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:

```python
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.

**Rate limit errors, from Kraken's REST limits, trading limits and error pages, 4 November 2026**

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

**Counters by verification tier, from the same pages, 4 November 2026**

| 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.com` as 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 takes `validate=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.

```python
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 `/derivatives` prefix 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 `/derivatives` endpoints. `sendorder`, `editorder` and `cancelorder` cost 10 each, and `openorders` costs 2. Going over returns `apiLimitExceeded`.
- **Success is not placement.** `result: success` only means the request was assessed; read `sendStatus.status`, which can say `insufficientAvailableFunds`.

Derivatives add leverage and liquidation risk, and nothing here suggests using them. Independent controls are in [trading bot risk management](https://fincodelabs.com/en/blog/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.

```python
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](https://fincodelabs.com/en/blog/websocket-order-book).

## 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)](https://docs.kraken.com/exchange/guides/overview)
- [Kraken: Spot REST Authentication (API-Sign example, nonce)](https://docs.kraken.com/exchange/guides/rest/authentication)
- [Kraken: Spot REST Rate Limits](https://docs.kraken.com/exchange/guides/rest/ratelimits)
- [Kraken: Spot Trading Limits](https://docs.kraken.com/exchange/guides/general/ratelimits)
- [Kraken: Error messages](https://docs.kraken.com/exchange/guides/general/errors)
- [Kraken: API key permissions and WebSocket token validity](https://docs.kraken.com/exchange/guides/rest/api-keys)
- [Kraken: Quickstart (UAT)](https://docs.kraken.com/home/guides/quickstart)
- [Kraken Support: API Testing Environment (demo decommission notice, updated 29 October 2026)](https://support.kraken.com/articles/360024809011-api-testing-environment-derivatives)
- [Kraken Support: Advanced API FAQ (test environment, validate)](https://support.kraken.com/articles/advanced-api-faq)
- [Kraken: Derivatives REST (Authent, responses)](https://docs.kraken.com/exchange/guides/futures/rest)
- [Kraken: Derivatives Rate Limits](https://docs.kraken.com/exchange/guides/futures/ratelimits)
- [Kraken: Spot WebSocket hosts and ticker channel](https://docs.kraken.com/exchange/api-reference/spot-websocket)
- [Kraken Support: How to create an API key on Kraken Pro](https://support.kraken.com/articles/how-to-create-an-api-key-on-kraken-pro)
- [Kraken: SDKs (official and community libraries)](https://docs.kraken.com/home/sdks)
- [Capital Markets Law No. 6362 (consolidated text, Article 99/A, Turkish)](https://www.mevzuat.gov.tr/mevzuatmetin/1.5.6362.pdf)

> 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](https://fincodelabs.com/en/editorial-policy).

---

Published by Fincode (Fincode Yazılım ve Teknoloji A.Ş.), a software company in Istanbul, Turkey: https://fincodelabs.com/en/blog/kraken-api-python

Cite as: Fincode, "Kraken API in Python: nonce, signing and rate limits", updated November 5, 2026, https://fincodelabs.com/en/blog/kraken-api-python
