# Kraken Futures API: Authent, PF_ symbols and demo status

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

Kraken Futures API read 5 Nov 2026: REST map with costs, Authent and challenge signing tested, PF_ symbols after the inverse delisting, demo status.

**Short answer:** The **Kraken Futures API** is Kraken's Derivatives interface: REST at `futures.kraken.com/derivatives/api/v3` and a streaming-only WebSocket at `wss://futures.kraken.com/ws/v1`, signed with a separate Derivatives key. On 5 November 2026 its public endpoints listed 209 `PF_` perpetuals and 10 `FF_` fixed-maturity futures but no inverse contracts, and the self-service demo host redirected to a Kraken web page.

On 5 November 2026 Kraken's Derivatives pages disagreed with each other and with the live endpoints, so each claim here was tested against them. Spot and nonces are in the [Kraken API Python guide](https://fincodelabs.com/en/blog/kraken-api-python).

**What ran.** On 5 November 2026, Python 3.11.3 with requests 2.31 and websockets 13.1 called public REST endpoints and the public WebSocket; signing was checked offline. No key was used and no order sent, so authenticated calls and private feeds are untested.

This is a technical guide, not a recommendation of Kraken or of derivatives trading. Futures are leveraged and positions can be liquidated, so losses can be fast and large (see the [liquidation price calculator](https://fincodelabs.com/en/tools/liquidation-price-calculator)). 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 crypto-asset platforms directed at Turkish residents as unauthorized.

## Kraken Futures API documentation: hosts, keys and REST map

Derivatives has its own hosts, keys and cost-based rate limit, separate from Spot.

- **Hosts.** History (`/api/history/v2/`) and charts (`/api/charts/v1/`) share the REST host.
- **Keys.** Created in the Derivatives account settings, up to 50, each with its own nonce. General API access stops short of withdrawals, which have a separate switch to leave off ([API key security](https://fincodelabs.com/en/blog/api-key-security-trading-bots)).
- **Fees need Spot.** Since 22 June 2026 the Futures fee-schedule endpoints no longer show the fees charged; Kraken points to Spot `GetTradeVolume` with a Spot key.

**REST map, OpenAPI file and rate-limit guide, 5 November 2026**

| Endpoint | Purpose | Cost |
| --- | --- | --- |
| `POST /sendorder` | `lmt`, `post`, `mkt`, `ioc`, `fok`, `stp`, `take_profit`, `trailing_stop` | 10 |
| `POST /editorder` | Change size or prices | 10 |
| `POST /cancelorder` | By `order_id` or `cliOrdId` | 10 |
| `POST /batchorder` | Up to 500 send, edit and cancel instructions | 9 + batch size |
| `POST /cancelallordersafter` | Dead man's switch | 25 |
| `GET /openorders`, `/openpositions`, `/accounts` | Orders, positions, cash, `flex` and margin accounts | 2 each |
| `GET /instruments`, `/tickers`, `/instruments/status` | Public data | None |

Private calls share 500 per 10 seconds, history calls 100 tokens per 10 minutes. The error list calls `apiLimitExceeded` per IP; the rate-limit guide is silent, so assume bots on one address share it.

## Kraken futures symbols: PF_, FF_, OF_ and the end of PI_

On 5 November 2026 the live symbols were `PF_` perpetuals and `FF_` fixed-maturity futures, plus `OF_` options on request; no inverse symbol answered.

**Symbols from the public endpoints, 5 November 2026, 19:10 UTC**

| Prefix | API type | Count | Example |
| --- | --- | ---: | --- |
| `PF_` | `flexible_futures`, perpetual | 209 | `PF_XBTUSD` |
| `FF_` | `flexible_futures`, expiring 6 Nov 2026 to 26 Mar 2027 | 10 | `FF_ETHUSD_261225` |
| `OF_` | options, only with `contractType=options` or `all` | 146 | `OF_XBTUSD_261106_79500_P` |
| `PI_`, `FI_` | `futures_inverse` | 0 | `PI_XBTUSD`: `contractNotFound` |

A banner on Kraken's inverse contract page, updated 30 October 2026, says inverse futures are delisted on 30 October, with BTC, ETH, LTC and XRP contracts settling at 16:00 UTC and leftover collateral moving to spot after 15 November, 08:00 UTC. It gives no year, but `/instruments?expired=true` lists `FI_XBTUSD_261030`, last trading 30 October 2026.

Kraken's pages lag: the WebSocket guide subscribes to `PI_XBTUSD`, the OpenAPI examples use `PF_BTCUSD` (`contractNotFound`), and the CLI page counts 317 perpetuals. Load symbols from `/instruments` at startup.

- `PF_XBTUSD` reports pair `BTC:USD` on `/instruments` but `XBT:USD` on its ticker; lookups ignore case.
- `tradeable` is always `true` on `/instruments`, expired markets included (OpenAPI file); check `suspended`, `postOnly` and `isExpired`.

## Kraken futures API status: instruments versus platform

Market-level status is public, but the Derivatives OpenAPI file read on 5 November 2026 has no public platform-status endpoint.

**Derivatives status sources, 5 November 2026**

| Question | Source | Key |
| --- | --- | --- |
| Halted or post-only? | `suspended`, `postOnly` on `/instruments`, `/tickers` | No |
| Price dislocated, volatility extreme? | `/instruments/status` | No |
| Maintenance or incident? | Spot `SystemStatus` advisories for `futures_*` or `all` | No |
| Account notices? | `/notifications`; maintenance with priority high means downtime | Read-only |

In Spot's `SystemStatus`, `emergency` lists open incidents and `upcoming_maintenance` lists work due within 72 hours, dropped once it starts (`MaintenanceSchedule` shows 7 days); match `affected_services` on `futures_*` or `all`. This market check needs no key:

```python
from decimal import Decimal, InvalidOperation, ROUND_DOWN
import requests

BASE = "https://futures.kraken.com/derivatives/api/v3"

def get(path):
    r = requests.get(BASE + path, timeout=10)
    try:
        body = r.json()
    except ValueError:                        # HTML after a redirect
        body = {}
    if not (r.status_code == 200 and body.get("result") == "success"):
        raise RuntimeError(f"{path}: HTTP {r.status_code}, {body.get('error', 'no JSON')}")
    return body

def check_market(symbol):
    rows = [i for i in get("/instruments")["instruments"] if i["symbol"].upper() == symbol.upper()]
    if len(rows) == 0 or len(rows) > 1:      # unknown or delisted, or ambiguous
        raise LookupError(f"{symbol}: {len(rows)} instruments match")
    flags = {**rows[0], **get(f"/instruments/{rows[0]['symbol']}/status")}
    problems = [k for k in ("suspended", "postOnly", "isExpired", "experiencingDislocation",
                            "experiencingExtremeVolatility") if flags.get(k)]
    return rows[0], problems

def to_wire(value, step, upper):
    try:
        d = Decimal(str(value)).quantize(step, rounding=ROUND_DOWN)
    except InvalidOperation:
        d = Decimal("NaN")
    if not d.is_finite() or d <= 0 or d > upper:   # inf, nan, text, zero after rounding
        raise ValueError("rejected " + repr(value))
    return format(d, "f")

inst, problems = check_market("pf_xbtusd")
step = Decimal(1).scaleb(-inst["contractValueTradePrecision"])
cap = Decimal(str(inst["maxPositionSize"]))
print(inst["symbol"], inst["tickSize"], step, inst.get("makerProtectionMillis", 0), problems)
for size in ("0.00012345", float("1e400"), float("1e-400"), "abc"):   # hypothetical
    try:
        print(to_wire(size, step, cap))
    except ValueError as e:
        print(e)
for sym in ("PI_XBTUSD", "PF_BTCUSD"):
    try:
        check_market(sym)
    except LookupError as e:
        print(e)
```

Output on 5 November 2026:

```
PF_XBTUSD 1 0.0001 0 []
0.0001
rejected inf
rejected 0.0
rejected 'abc'
PI_XBTUSD: 0 instruments match
PF_BTCUSD: 0 instruments match
```

- `float("1e400")` (`inf`) and `float("1e-400")` (`0.0`) are rejected before sending; a missing `makerProtectionMillis` means zero.
- Unknown symbols returned HTTP 404 with `contractNotFound`, absent from the documented error list. The status endpoint returned `invalidArgument` for invented names but success, every flag false, for the delisted `PI_XBTUSD`, so check `/instruments` first. Match error codes by prefix.
- `/openpositions` without a key returned HTTP 200 with `authenticationError`, so check `result`, not only the HTTP code.

## Kraken futures API authentication: Authent and challenge

REST `Authent` and the WebSocket `signed_challenge` share one recipe, SHA-256 and then HMAC-SHA-512 with the Base64-decoded secret; Kraken publishes a challenge test vector.

The REST message is postData + nonce + path, the path starting at `/api/v3`; the nonce is optional. Since 20 February 2024 Kraken wants parameters hashed URL-encoded, as sent; its REST guide, read 5 November 2026, still says it aims to retire the old method on 1 October 2025, not whether it did.

```python
import base64, hashlib, hmac, json, urllib.parse, uuid

def kf_sign(message, secret):
    key = base64.b64decode(secret, validate=True)      # a bad secret fails here, offline
    digest = hashlib.sha256(message.encode()).digest()
    return base64.b64encode(hmac.new(key, digest, hashlib.sha512).digest()).decode()

# Kraken's published challenge example, Derivatives WebSocket guide
print(kf_sign("c100b894-1729-464d-ace1-52dbce11db42",
              "7zxMEF5p/Z8l2p2U7Ghv6x14Af+Fx+92tPgUdVQ748FOIrEoT9bgT+bTRfXc5pz8na+hL/QdrCVG7bh9KpT0eMTm")
      == "4JEpF3ix66GA2B+ooK128Ift4XQVtc137N9yeg4Kqsn9PI0Kpzbysl9M1IeCEdjg0zl00wkVqcsnG4bmnlMb3A==")

def batch_body(instructions):
    sends = [i for i in instructions if i["order"] == "send"]
    ids = [i.setdefault("cliOrdId", str(uuid.uuid4())) for i in sends]  # added in place
    if not all(ids):
        raise ValueError("empty cliOrdId")
    if len(set(ids)) < len(ids):
        raise ValueError("repeated cliOrdId")
    if not all(i[k] > 0 for i in instructions
               for k in ("size", "limitPrice", "stopPrice") if k in i):  # 0.0, nan
        raise ValueError("size and prices must be above 0")
    payload = json.dumps({"batchOrder": instructions}, separators=(",", ":"),
                         allow_nan=False)              # inf from 1e400 raises
    return urllib.parse.urlencode({"json": payload}, quote_via=urllib.parse.quote)

secret = base64.b64encode(b"throwaway, never registered").decode()
order = {"order": "send", "order_tag": "1", "orderType": "post", "symbol": "PF_XBTUSD",
         "side": "buy", "size": 0.0001, "limitPrice": 50000}        # hypothetical
body = batch_body([order])
authent = kf_sign(body + "/api/v3/batchorder", secret)  # postData + nonce ("") + path
old_style = kf_sign(urllib.parse.unquote(body) + "/api/v3/batchorder", secret)
print(body[:40], len(authent), authent == old_style)
for bad in ([dict(order, cliOrdId="")], [order, dict(order)],
            [dict(order, limitPrice=float("1e-400"))], [dict(order, size=float("1e400"))]):
    try:
        batch_body(bad)
    except ValueError as e:
        print(e)
```

Output on 5 November 2026:

```
True
json=%7B%22batchOrder%22%3A%5B%7B%22orde 88 False
empty cliOrdId
repeated cliOrdId
size and prices must be above 0
Out of range float values are not JSON compliant
```

`True` reproduces Kraken's example; `False` shows that hashing decoded JSON changes `Authent`. On four inputs the function matched `sign_message` in CryptoFacilities' REST-v3-Python, a client from September 2021 that signs batch JSON unencoded. Private subscribes need `api_key`, `original_challenge` and `signed_challenge` (not run here); an unsigned `open_orders` subscribe got an alert.

## Kraken futures sendorder: statuses that mean rejection

In Kraken's REST guide, `result: success` only means the request was assessed; whether the order was placed is in `sendStatus.status`.

- **Allow-list statuses.** The enum has 33 values, such as `insufficientAvailableFunds` and `wouldCauseLiquidation`, and its description disagrees (`clientOrderIdTooLong` versus `clientOrderIdTooBig`), so treat unknown values as rejections.
- **Maker Protection.** Since 24 September 2026, selected markets hold liquidity-taking orders and edits for `makerProtectionMillis` (20 ms at launch, at most 100 ms) while post-only orders and cancels pass at once, so a batch need not run in listed order; 152 of 219 futures listed 20 ms on 5 November 2026.
- **Dead man's switch.** Kraken suggests `cancelallordersafter` every 15 to 20 seconds with a 60-second timeout, about 17 of the 500 per 10 seconds at 15-second calls.
- **Client IDs.** `cliOrdId` is unique and at most 100 characters; `/orders/status` keeps finished orders 5 seconds only, so fall back to open orders and fills ([client order IDs](https://fincodelabs.com/en/blog/client-order-id), [reduce-only orders](https://fincodelabs.com/en/blog/reduce-only-order)).

> **Hypothetical example: editing size.** An order for 0.0100 BTC has filled 0.0040, leaving 0.0060 open. An edit to `size=0.0050` in the default `qtyMode`, `RELATIVE`, leaves 0.0050 open, 0.0090 in total. With `qtyMode=ABSOLUTE` the total becomes 0.0050, leaving 0.0010 open.

## Kraken futures WebSocket API: feeds and alerts

The Derivatives WebSocket only streams: public feeds such as `ticker` and `book` need no key, private feeds need the signed challenge, and orders go through REST or FIX.

```python
import asyncio, json
import websockets

async def ticker(product):
    async with websockets.connect("wss://futures.kraken.com/ws/v1") as ws:
        await ws.send(json.dumps({"event": "subscribe", "feed": "ticker",
                                  "product_ids": [product]}))
        while True:
            msg = json.loads(await asyncio.wait_for(ws.recv(), 15))
            if "event" in msg:
                print(msg)
                if msg["event"] in ("alert", "error"):
                    return
            elif msg.get("feed") == "ticker":
                print(msg["product_id"], msg["bid"], msg["ask"], msg["markPrice"],
                      msg.get("funding_rate"), msg["post_only"], msg["suspended"])
                return

asyncio.run(ticker("PF_XBTUSD"))
asyncio.run(ticker("PI_XBTUSD"))
```

Output on 5 November 2026:

```
{'event': 'info', 'version': 1}
{'event': 'subscribed', 'feed': 'ticker', 'product_ids': ['PF_XBTUSD']}
PF_XBTUSD 76105.0 76106.0 76109.40445531809 3.500396284565308 False False
{'event': 'info', 'version': 1}
{'event': 'alert', 'message': "Couldn't subscribe to invalid product `PI_XBTUSD`"}
```

- An invalid product returns an `alert`, even alongside a valid one, so check each product.
- Field styles mix: `funding_rate` (perpetuals only) and `post_only` sit beside `markPrice`; REST says `fundingRate`. For funding, see [perpetual futures and funding rate](https://fincodelabs.com/en/blog/perpetual-futures-funding-rate) and the [funding rate calculator](https://fincodelabs.com/en/tools/funding-rate-calculator).
- Ping at least every 60 seconds (websockets pings every 20 by default) and resubscribe after reconnecting; limits are 100 connections and 100 requests per connection per second. For depth, see the [order book guide](https://fincodelabs.com/en/blog/websocket-order-book).

## Kraken futures demo API: what is left for testing

No self-service Derivatives sandbox answered on 5 November 2026, and Kraken's pages disagree on whether one exists.

**Kraken futures demo: sources and test, 5 November 2026**

| Source | What it says |
| --- | --- |
| Support article 360024809011, updated 29 October 2026 | Demo decommissioned at 13 UTC on Monday, 14 July, year not given (a Monday in 2025); testing for qualified clients via the API team; old sign-up steps still shown |
| Derivatives introduction, Exchange overview, quickstart | `demo-futures.kraken.com` is self-service |
| Test at 19:09 UTC | HTTP 301 to a Kraken futures page for REST and WebSocket; REST then ended on the Kraken Pro web app (HTML) |

What remains:

- Kraken's qualified-client environment, via the API team; criteria are not published.
- Kraken's CLI paper trading simulates futures orders on live prices without a key; Kraken recommends it, but it cannot test your signing or Kraken's order checks.
- Small live orders, which are real trades: set hard limits and kill switches first ([trading bot risk management](https://fincodelabs.com/en/blog/trading-bot-risk-management)).

For integration work in general, see [exchange API integration](https://fincodelabs.com/en/services/exchange-api-integration); naming Kraken here does not mean Fincode integrates it or has built on it.

## Frequently asked questions

### Does Kraken Futures have a testnet or demo API?

Not a self-service one: on 5 November 2026 demo-futures.kraken.com redirected to a Kraken web page. Kraken's support article says the demo was decommissioned and offers testing to qualified clients.

### Can I use my Kraken Spot API key for futures?

No. Derivatives keys come from the Derivatives account settings and sign with APIKey and Authent headers; Spot keys use API-Key and API-Sign.

### How do I check the Kraken Futures API status?

Use /instruments/status and /tickers for markets, and the advisories in Spot's public SystemStatus, filtered for futures services or all, for maintenance and incidents.

### Why does PI_XBTUSD return contractNotFound?

Kraken delisted inverse futures on 30 October 2026, and on 5 November no PI_ or FI_ symbol answered. Perpetuals use PF_, such as PF_XBTUSD.

## Sources

- [Kraken: Derivatives REST (Authent, URL-encoding change, responses)](https://docs.kraken.com/exchange/guides/futures/rest)
- [Kraken: Derivatives Rate Limits (costs, history pool, WebSocket limits)](https://docs.kraken.com/exchange/guides/futures/ratelimits)
- [Kraken: Derivatives WebSocket (challenge signing example)](https://docs.kraken.com/exchange/guides/futures/websockets)
- [Kraken: Derivatives WebSocket reference (feeds)](https://docs.kraken.com/exchange/api-reference/futures-websocket)
- [Kraken: Derivatives introduction (hosts, keys, demo text)](https://docs.kraken.com/exchange/guides/futures/introduction)
- [Kraken: Futures REST OpenAPI file (endpoints, statuses, errors)](https://docs.kraken.com/openapi/futures-rest.yaml)
- [Kraken: Maker Protection (Derivatives)](https://docs.kraken.com/exchange/guides/futures/maker-protection)
- [Kraken Support: API Testing Environment, Derivatives (updated 29 October 2026)](https://support.kraken.com/articles/360024809011-api-testing-environment-derivatives)
- [Kraken Support: Inverse Coin-M contract specifications and delisting notice (updated 30 October 2026)](https://support.kraken.com/articles/360022835911-inverse-crypto-collateral-perpetual-contract-specifications-derivatives)
- [Kraken: Exchange overview (sandbox row)](https://docs.kraken.com/exchange/guides/overview)
- [Kraken: Quickstart (futures sandbox text)](https://docs.kraken.com/home/guides/quickstart)
- [Kraken: kraken-cli (paper trading, separate futures keys)](https://docs.kraken.com/home/cli)
- [CryptoFacilities: REST-v3-Python reference client](https://github.com/CryptoFacilities/REST-v3-Python)
- [Kraken Status](https://status.kraken.com)
- [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-futures-api

Cite as: Fincode, "Kraken Futures API: Authent, PF_ symbols and demo status", updated November 6, 2026, https://fincodelabs.com/en/blog/kraken-futures-api
