Kraken Futures Order Endpoint: Complete API Guide for Traders
A hands-on guide to the Kraken Futures order endpoint — covering authentication, sending orders, parsing responses, and error handling with working Python code.
A hands-on guide to the Kraken Futures order endpoint — covering authentication, sending orders, parsing responses, and error handling with working Python code.
Kraken's futures API is one of the more reliable derivatives interfaces in crypto — solid uptime, readable documentation, and a consistent response format that doesn't change under you. But threading together authentication, parameter formatting, and response parsing for your first order still takes work. This guide covers all of it with production-quality Python you can run today. Whether you're building a standalone execution bot or piping signals from a platform like VoiceOfChain directly into Kraken Futures, the same fundamentals apply.
Kraken separates its spot and futures APIs entirely. The futures interface lives at https://futures.kraken.com/derivatives/api/v3 — that /v3 matters because earlier versions are deprecated and will break on certain endpoints without warning. All order management goes through this base URL regardless of which contract you're targeting. Kraken Futures supports two contract families: perpetual contracts prefixed with PI_ (like PI_XBTUSD, PI_ETHUSD, PI_SOLUSD) and fixed maturity futures prefixed with FI_. The most liquid market is PI_XBTUSD — Bitcoin perpetual inverse contract, quoted and settled in USD. Compare that to Binance Futures which uses BTCUSDT as its primary BTC market, or Bybit which offers both inverse and linear perpetuals under different naming conventions. The underlying mechanics differ too — Kraken's inverse contracts mean your USD PnL is non-linear relative to price moves, which matters when sizing positions programmatically. The API uses REST for all order management — placing, editing, canceling, querying positions. WebSocket handles real-time data streams. For order execution specifically, you'll work exclusively with authenticated POST requests to the REST layer. Public endpoints like /tickers and /orderbook require no authentication. Everything touching your account does.
Kraken Futures API keys are completely separate from spot API keys. Generate a dedicated futures key pair in your Kraken Futures account settings under API. Using a spot key on a futures endpoint will return an authentication error, not a helpful message about key type.
Kraken Futures uses HMAC-SHA512 signing — the same family you'll encounter on Binance and OKX, but with its own message construction format. The signature is built by concatenating your URL-encoded POST body, a nonce (millisecond timestamp as a string), and the full endpoint path. That concatenated string gets SHA-256 hashed first, then HMAC-SHA512 signed using your base64-decoded API secret. The result is base64-encoded and passed as the Authent header alongside your APIKey and Nonce headers. The order of concatenation matters: post_data + nonce + endpoint_path. Getting this wrong produces a cryptographic signature that will always fail — Kraken returns authenticationError with no further detail.
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"
BASE_URL = "https://futures.kraken.com/derivatives/api/v3"
def build_signature(endpoint_path, post_data, nonce, secret):
# message = post_data + nonce + endpoint_path
# endpoint_path must be the full path, e.g. '/derivatives/api/v3/sendorder'
message = post_data + nonce + endpoint_path
sha256_hash = hashlib.sha256(message.encode("utf-8")).digest()
secret_bytes = base64.b64decode(secret)
mac = hmac.new(secret_bytes, sha256_hash, hashlib.sha512)
return base64.b64encode(mac.digest()).decode()
def make_signed_request(method, endpoint, params=None):
nonce = str(int(time.time() * 1000))
full_path = f"/derivatives/api/v3{endpoint}"
post_data = urllib.parse.urlencode(params) if params else ""
signature = build_signature(full_path, post_data, nonce, API_SECRET)
headers = {
"APIKey": API_KEY,
"Nonce": nonce,
"Authent": signature,
"Content-Type": "application/x-www-form-urlencoded"
}
url = BASE_URL + endpoint
if method == "GET":
resp = requests.get(url, headers=headers, params=params, timeout=10)
else:
resp = requests.post(url, headers=headers, data=post_data, timeout=10)
resp.raise_for_status()
return resp.json()
The /sendorder endpoint accepts POST requests and handles limit orders, market orders, stop orders, and take-profit orders in a single interface. Minimum required parameters are orderType, symbol, side, and size. Limit orders additionally need limitPrice. Stop orders need stopPrice. Optional flags like postOnly, reduceOnly, and cliOrdId cover most production scenarios. One critical detail about sizing: for inverse perpetuals like PI_XBTUSD and PI_ETHUSD, size is denominated in USD — not the base asset. A size of 5000 means a $5,000 notional position, not 5000 BTC. This is fundamentally different from how Bybit handles its USDT-margined contracts (where size is in base asset units) or how OKX structures its linear perpetuals. When porting position-sizing logic between exchanges, this is the most common source of errors.
def send_order(
symbol,
side,
order_type,
size,
limit_price=None,
stop_price=None,
reduce_only=False,
post_only=False,
client_order_id=None
):
# symbol: e.g. 'PI_XBTUSD' (BTC perp), 'PI_ETHUSD' (ETH perp), 'PI_SOLUSD'
# side: 'buy' or 'sell'
# order_type: 'lmt', 'mkt', 'stp', 'take_profit'
# size: notional USD value for inverse contracts
params = {
"orderType": order_type,
"symbol": symbol,
"side": side,
"size": size,
}
if limit_price is not None:
params["limitPrice"] = limit_price
if stop_price is not None:
params["stopPrice"] = stop_price
if reduce_only:
params["reduceOnly"] = "true"
if post_only:
params["postOnly"] = "true"
if client_order_id:
params["cliOrdId"] = client_order_id
return make_signed_request("POST", "/sendorder", params)
# Place a post-only limit buy on BTC perpetual
result = send_order(
symbol="PI_XBTUSD",
side="buy",
order_type="lmt",
size=5000, # $5,000 notional
limit_price=65000, # at $65,000
post_only=True # maker-only: guarantees maker fee, rejected if it would take
)
print(result)
Kraken Futures returns a consistent structure where result is either 'success' or 'error'. On success, order details live inside sendStatus — specifically sendStatus.orderEvents, an array that can contain multiple events if your order partially fills on placement. On error, the top-level error field is a readable string like insufficientFunds, wouldNotReducePosition, or marketSuspended. The trap that catches most first-time builders: Kraken can return result: 'success' while the order itself was rejected at the matching engine. You have to inspect orderEvents for entries with type 'REJECT'. Skipping this check means your bot thinks orders are live when they were silently dropped. Platforms like Gate.io and Bitget use numeric error codes for similar rejection reasons — Kraken's readable strings are easier to handle, but only if you actually check them.
import time
from typing import Optional, Dict, Any
RETRYABLE_ERRORS = {"apiLimitExceeded", "serverError", "Unavailable"}
MAX_RETRIES = 3
BACKOFF_BASE = 1.5
def place_order_safe(
symbol: str,
side: str,
size: int,
price: Optional[float] = None,
retries: int = MAX_RETRIES
) -> Dict[str, Any]:
order_type = "lmt" if price else "mkt"
for attempt in range(retries):
try:
response = send_order(
symbol=symbol,
side=side,
order_type=order_type,
size=size,
limit_price=price
)
if response.get("result") == "success":
status = response["sendStatus"]
events = status.get("orderEvents", [])
# Always check for matching-engine-level rejection
if events and events[0].get("type") == "REJECT":
reason = events[0].get("reason", "unknown")
return {"success": False, "error": reason, "retryable": False}
return {
"success": True,
"order_id": status.get("order_id"),
"status": status.get("status"),
"events": events
}
error = response.get("error", "unknownError")
if error in RETRYABLE_ERRORS and attempt < retries - 1:
wait = BACKOFF_BASE ** attempt
print(f"Retryable error '{error}', waiting {wait:.1f}s...")
time.sleep(wait)
continue
return {"success": False, "error": error, "retryable": False}
except requests.exceptions.Timeout:
if attempt < retries - 1:
time.sleep(BACKOFF_BASE ** attempt)
continue
return {"success": False, "error": "timeout", "retryable": True}
except requests.exceptions.RequestException as exc:
return {"success": False, "error": str(exc), "retryable": False}
return {"success": False, "error": "max_retries_exceeded", "retryable": False}
# Buy $2,000 of ETH perpetual at market
result = place_order_safe("PI_ETHUSD", "buy", 2000)
if result["success"]:
print(f"Order placed: {result['order_id']}")
else:
print(f"Order failed: {result['error']}")
Rate limits on Kraken Futures order endpoints are stricter than their public data endpoints. If you're firing orders rapidly from signal execution, implement token-bucket rate limiting in your client layer before you hit production. Exceeding limits returns apiLimitExceeded, which is retryable — but your retry backoff needs to be long enough to actually clear the window.
Kraken Futures supports six order types covering the full range of algorithmic trading needs. Here's what's available and when each makes sense:
| Order Type | API Value | Required Params | Best Use Case |
|---|---|---|---|
| Limit | lmt | limitPrice, size | Maker entries, post-only orders |
| Market | mkt | size only | Signal execution, immediate fills |
| Stop Market | stp | stopPrice, size | Stop-loss triggered at market |
| Stop Limit | stp | stopPrice + limitPrice | Stop with price floor control |
| Take Profit Market | take_profit | stopPrice, size | Automated profit-taking |
| Trailing Stop | trailing_stop | trailingStopDeviationUnit | Dynamic stop following price |
The authentication and order functions above are plumbing. The interesting part is what triggers them. Running a bot that places random orders based on a fixed schedule is noise; running one that responds to real market conditions is edge. VoiceOfChain is a real-time trading signal platform that aggregates on-chain data, funding rate shifts, liquidation cascades, and technical confluences into structured alerts. The typical integration pattern is lightweight: a webhook listener receives a VoiceOfChain signal event (for example, 'BTC funding rate flipped strongly negative + price holding above 200 EMA + large spot bid wall detected'), validates the signal parameters against your risk rules, and calls place_order_safe() against the Kraken Futures /sendorder endpoint. Before you connect signal execution to live order flow, add one more layer: query /openpositions first. Kraken's inverse contracts have non-linear PnL — stacking a new buy order on top of an existing long without accounting for current exposure is how bots blow up accounts on gap moves. A disciplined bot checks current position size, calculates maximum acceptable additional exposure, and respects that limit regardless of what the signal says. On the infrastructure side, exchanges like Binance Futures and Bybit impose tight rate limits on order endpoints. Kraken is similar. If your signal source fires frequently — as real-time platforms often do during volatile periods — implement a token-bucket or sliding-window rate limiter in your request layer. Hitting the limit during a fast market is the worst time to discover your retry logic is broken.
The Kraken Futures /sendorder endpoint is well-structured and consistent once you understand two things: the specific SHA256 + HMAC-SHA512 signature construction, and the requirement to inspect orderEvents for matching-engine rejections even when result is 'success'. The Python patterns in this guide cover authentication, order placement, and production-grade error handling with retry backoff — enough to ship a working execution layer. From here, the natural next steps are implementing position tracking via GET /openpositions, adding WebSocket subscriptions for real-time fill notifications so you're not polling, and connecting your execution layer to a signal source. Platforms like VoiceOfChain handle signal intelligence — market structure, on-chain flows, funding dynamics. The Kraken Futures API handles execution. Put them together correctly and you have the core of a functioning algorithmic trading system built on infrastructure that won't buckle under load.