◈   ⌘ api · Intermediate

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.

Uncle Solieditor · voc · 06.05.2026 ·views 10
◈   Contents
  1. → Understanding the Kraken Futures API Architecture
  2. → Setting Up Authentication for the Kraken Futures API
  3. → Placing Orders with the /sendorder Endpoint
  4. → Parsing Responses and Handling Errors Robustly
  5. → Order Types and Key Parameters Reference
  6. → Connecting Real-Time Signals to Kraken Futures Execution
  7. → Frequently Asked Questions
  8. → Conclusion

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.

Understanding the Kraken Futures API Architecture

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.

Setting Up Authentication for the Kraken Futures API

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

Placing Orders with the /sendorder Endpoint

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)

Parsing Responses and Handling Errors Robustly

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.

Order Types and Key Parameters Reference

Kraken Futures supports six order types covering the full range of algorithmic trading needs. Here's what's available and when each makes sense:

Kraken Futures Order Types and Required Parameters
Order TypeAPI ValueRequired ParamsBest Use Case
LimitlmtlimitPrice, sizeMaker entries, post-only orders
Marketmktsize onlySignal execution, immediate fills
Stop MarketstpstopPrice, sizeStop-loss triggered at market
Stop LimitstpstopPrice + limitPriceStop with price floor control
Take Profit Markettake_profitstopPrice, sizeAutomated profit-taking
Trailing Stoptrailing_stoptrailingStopDeviationUnitDynamic stop following price

Connecting Real-Time Signals to Kraken Futures Execution

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.

Frequently Asked Questions

What is the correct base URL for the Kraken Futures order endpoint?
The base URL is https://futures.kraken.com/derivatives/api/v3. The sendorder endpoint is a POST to /sendorder relative to that base, giving the full URL https://futures.kraken.com/derivatives/api/v3/sendorder. Always use v3 — earlier versions are deprecated and behave unpredictably.
How is Kraken Futures authentication different from the Kraken spot API?
They use different signing algorithms and require separate API keys. Kraken Futures uses SHA256 + HMAC-SHA512 with a specific message construction (post_data + nonce + endpoint_path). Spot API keys will not authenticate on futures endpoints — generate a dedicated key pair in your Futures account settings.
Why does my order return 'success' but never appears in open orders?
Kraken returns result: 'success' at the API layer even when the matching engine rejects the order. You must inspect sendStatus.orderEvents for entries where type is 'REJECT'. The rejection reason field will tell you exactly why — common causes are insufficient margin, post-only conflict, or a reduce-only violation.
What unit is the size parameter for PI_XBTUSD and PI_ETHUSD?
Size is denominated in USD for inverse perpetuals. A size of 5000 means a $5,000 notional position — not 5000 BTC or ETH. This is different from linear contracts on Bybit and OKX where size is typically in base asset units. Confusing this is the most common sizing bug when porting cross-exchange logic.
How do I cancel an order on Kraken Futures?
POST to /cancelorder with either order_id (Kraken's UUID) or cliOrdId (your custom client order ID if you set one at placement). The response follows the same result: 'success' or 'error' pattern as sendorder, with a cancelStatus object containing the cancellation details.
Does Kraken Futures have a testnet or paper trading environment?
Yes. Kraken provides a full demo environment at demo-futures.kraken.com with an identical API structure to production. Generate separate demo API keys in the demo account settings, change your BASE_URL to point at the demo host, and all order management works exactly as in production — safe to stress-test your bot before going live.

Conclusion

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.

◈   more on this topic
◉ basics Mastering the ccxt library documentation for crypto traders ⌂ exchanges Mastering the Binance CCXT Library for Crypto Traders ⌬ bots Best Crypto Trading Bots 2025: Profitable AI-Powered Strategies