Perpetuals Kronos X v2.0 “Pacifica” Member API

Kronos X Member API

Kronos X is a multilateral trading facility for perpetual futures and spot crypto-asset markets. This documentation covers everything a member firm needs to connect: three transports over one deterministic matching engine, with identical semantics, identical risk controls and one shared recovery model.

Member portal

Alongside the API, every member firm gets a web portal. Venue operations issue the login (your member code and a password) during onboarding; since 19 August 2026 the sign-in also asks for a six-digit code from an authenticator app, enrolled at your first sign-in from a QR code on the sign-in page (Member Portal User Guide, section 1.1). API keys and the API itself are unaffected.

Positions and risk
Balances, equity, initial and maintenance margin, your equity-to-MM ratio and risk status, member-net positions with unrealised profit and loss, and the ADL queue rank per position.
Markets and your orders
Live order book with depth, recent venue prints, your working orders, and your untriggered conditional orders shown alongside the visible book.
RFQ trading
The full request-for-quote surface for RFQ-mode markets: request quotes with a ticket (including barrier terms on knock-out markets), watch incoming quotes and accept, quote other members' requests from the open board, withdraw your standing quotes, and track your live barrier contracts with entry, barrier, take profit, distance to knock-out, unrealised profit and loss and margin, plus your recently settled contracts with their termination reason. Once venue operations have registered Authorised Users for your member, the tab's Trader ID field carries the Authorised User's id on every request, quote and acceptance (code 2021 without it; cancels are never gated).
End clients
Per-clientUid sub-positions and activity. Margin and liquidation still run on your member net position; these records are the exact attribution behind it.
Reports
Trade and ledger history with CSV download, and activity statistics per instrument and per end client, generated from the venue's durable records.
Credentials and limits
Your live rate limits and order-to-trade regime, your registered Authorised Users, a kill switch, and the keys card: self-service issuance and revocation of your API credentials. A member holds up to 5 keys per scope (TRADE and READ_ONLY); issuing a key adds it and existing keys keep working, so rotation is a failover: issue the new key, migrate traffic, revoke the old one. A new key takes effect immediately and its secret is shown once; revocation is per key, immediate, and ends live WebSocket and FIX sessions using that key. You can also change your portal password there, under Credentials.

What makes this venue different

Four properties shape every integration decision. They are worth reading before you write code, because each one removes a class of bug that is expensive to find later.

Deterministic core
A single-writer matching engine with exact integer arithmetic. The same command sequence always produces the same state, byte for byte, so any dispute about a figure is answerable by reproducing it from the verified snapshot with the binary version that produced it, rather than by argument.
Ack after durable
No acknowledgement and no event leaves the venue before the journal has made it durable. When you hold an ack, the venue cannot forget the order, even through power loss.
One recovery model
Every transport shares a single durable, totally ordered event stream. After any disconnect you page it from a cursor and prove you missed nothing. There is no per-transport replay to implement.
Member-level risk, client-level records
Margin, position limits and liquidation are computed on your member net position. Per-end-client sub-positions are kept exactly, for reporting and reconciliation, and are never read by the risk engine.

Environments

EnvironmentRESTWebSocketFIX 4.4
Sandbox https://sandbox.mtf.perpetuals.net wss://sandbox.mtf.perpetuals.net sandbox.mtf.perpetuals.net:9879
Production https://production.mtf.perpetuals.com wss://production.mtf.perpetuals.com confirmed at onboarding

All transports are TLS only with a publicly trusted certificate. No certificate pinning is required. WebSocket paths are /ws/public for market data and /ws/private for account data and order entry.

The sandbox host is sandbox.mtf.perpetuals.net since Member API revision 3.83: three nodes behind that one entry host, replacing the single-node sandbox.mtf.perpetuals.com from the date venue operations announce. Each environment publishes one entry host, which sends new connections to the node that accepts writes; never pin a node. A leader change therefore happens on the sandbox as it can on production: handle the 5030 redirect, the WebSocket close 1001 leader change, reconnect and the FIX leader-change Logout as the REST, WebSocket and FIX pages describe.

Sandbox balances are test money and carry no value. The sandbox runs a price simulator so marks, funding and triggers behave realistically. Full sandbox data resets are announced at least 5 business days in advance via the members Slack channel and a portal notice, and the announcement names the post-reset baseline; API credentials survive a reset unless the announcement says otherwise, and portal logins persist. Margin top-ups and per-member state resets for test members are available on request via the members Slack channel. The full sandbox operations policy is section 1a of the Member API reference.

Build and certify on sandbox. Production endpoints are enabled per member at onboarding, once conformance testing is complete, and production credentials are issued separately from sandbox credentials. Point your integration at the sandbox host until venue operations confirm your production access.

Try before you build. The interactive console at /docs executes every REST endpoint against the live sandbox and signs requests in your browser, so you can exercise the API before writing a signer. The machine-readable description is at /openapi.json.

Quickstart

Fetch reference data, sign one private request, place an order and cancel it. Set KRONOSX_API_KEY and KRONOSX_API_SECRET in your environment first.

import os, time, hmac, hashlib, json, requests

BASE   = "https://sandbox.mtf.perpetuals.net"
KEY    = os.environ["KRONOSX_API_KEY"]
SECRET = os.environ["KRONOSX_API_SECRET"]

def signed(method, path, body=None):
    raw = json.dumps(body, separators=(",", ":")) if body is not None else ""
    ts  = str(int(time.time() * 1000))
    sig = hmac.new(SECRET.encode(), (ts + method + path + raw).encode(),
                   hashlib.sha256).hexdigest()
    headers = {"X-API-KEY": KEY, "X-TIMESTAMP": ts, "X-SIGNATURE": sig,
               "Content-Type": "application/json"}
    # Send the SAME bytes that were signed.
    return requests.request(method, BASE + path, headers=headers,
                            data=raw or None, timeout=10).json()

# 1. Reference data drives all rounding. Never hard-code ticks or quantity steps.
instruments = requests.get(BASE + "/v1/instruments", timeout=10).json()["data"]
btc = next(i for i in instruments if i["symbol"] == "BTC-USD-PERP")
print(btc["symbol"], "tick", btc["tickSize"], "step", btc["qtyStep"], "minNotional", btc["minNotional"])

# 2. Account state. Note: data is an ARRAY, one row per settlement currency.
account = signed("GET", "/v1/account")["data"][0]
print("balance", account["balance"], account["ccy"])

# 3. Place a resting order. clOrdId is yours and is the idempotency key.
order = signed("POST", "/v1/orders", {
    "symbol": "BTC-USD-PERP", "side": "BUY", "type": "LIMIT", "tif": "GTC",
    "price": "60000", "qty": "0.005",
    "clOrdId": "quickstart-1", "clientUid": "CLIENT-A",
})
print(order["code"], order["data"]["status"], order["data"]["orderId"])

# 4. Cancel it.
print(signed("DELETE", "/v1/orders/" + str(order["data"]["orderId"]))["data"]["status"])
import crypto from "node:crypto";

const BASE   = "https://sandbox.mtf.perpetuals.net";
const KEY    = process.env.KRONOSX_API_KEY;
const SECRET = process.env.KRONOSX_API_SECRET;

async function signed(method, path, body) {
  const raw = body === undefined ? "" : JSON.stringify(body);
  const ts  = Date.now().toString();
  const sig = crypto.createHmac("sha256", SECRET)
                    .update(ts + method + path + raw).digest("hex");
  const res = await fetch(BASE + path, {
    method,
    headers: { "X-API-KEY": KEY, "X-TIMESTAMP": ts, "X-SIGNATURE": sig,
               "Content-Type": "application/json" },
    body: raw || undefined,          // the exact bytes that were signed
  });
  return res.json();
}

const { data: instruments } = await (await fetch(BASE + "/v1/instruments")).json();
const btc = instruments.find(i => i.symbol === "BTC-USD-PERP");
console.log(btc.symbol, "tick", btc.tickSize, "step", btc.qtyStep, "minNotional", btc.minNotional);

const account = (await signed("GET", "/v1/account")).data[0];
console.log("balance", account.balance, account.ccy);

const order = await signed("POST", "/v1/orders", {
  symbol: "BTC-USD-PERP", side: "BUY", type: "LIMIT", tif: "GTC",
  price: "60000", qty: "0.005", clOrdId: "quickstart-1", clientUid: "CLIENT-A",
});
console.log(order.code, order.data.status, order.data.orderId);

const cancel = await signed("DELETE", `/v1/orders/${order.data.orderId}`);
console.log(cancel.data.status);
# Public endpoints need no signature.
curl -s https://sandbox.mtf.perpetuals.net/v1/instruments | jq '.data[].symbol'

# Signed GET /v1/account
BASE=https://sandbox.mtf.perpetuals.net
TS=$(($(date +%s) * 1000))
SIG=$(printf '%s' "${TS}GET/v1/account" \
      | openssl dgst -sha256 -hmac "$KRONOSX_API_SECRET" -hex \
      | sed 's/^.*= //')
curl -s "$BASE/v1/account" \
  -H "X-API-KEY: $KRONOSX_API_KEY" \
  -H "X-TIMESTAMP: $TS" \
  -H "X-SIGNATURE: $SIG" | jq .

Authentication

Every private request carries three headers:

HeaderValue
X-API-KEYYour API key.
X-TIMESTAMPUnix milliseconds, as a string.
X-SIGNATURE hex_lowercase(HMAC_SHA256(secret, timestamp + METHOD + pathWithQuery + body))
X-RECV-WINDOW Optional, milliseconds, default 5000, an integer from 1 to 60000 (any other value is refused with code 1002, revision 3.88). The timestamp may lag the venue clock by up to the window and lead it by at most 5000 ms; outside that the request is rejected with code 1002.

A signed write is accepted once (revision 3.88): the same X-API-KEY and X-SIGNATURE on any method but GET answers 1002 request already received and nothing runs, so sign every send, a retry included, with a fresh timestamp and keep its clOrdId. The private WebSocket login signs the connection's challenge nonce, the first frame of every /ws/private connection (WebSocket page).

Sign the bytes you send. Serialize the body once and reuse that string for both the signature and the request. Re-serializing (a different key order, different whitespace) produces a valid-looking request with an invalid signature, which shows up as intermittent 1001 errors that are painful to diagnose. The same rule applies to the query string: some HTTP stacks re-normalize percent-encoding after you build the URL (Python aiohttp/yarl re-encodes commas), so sign the exact final string your client transmits. A comma-bearing test vector is on the REST page.

Verify your signer against this vector before connecting:

secret     = "test-secret"
timestamp  = "1700000000000"
method     = "GET"
path       = "/v1/account"
body       = ""
payload    = "1700000000000GET/v1/account"
signature  = 741b61b6d3740ede7864551612095d2fb73b75a4f70534f45e9e207bdd1f321c

Credential scopes

Credentials carry a scope. A TRADE credential can do everything. A READ_ONLY credential, also called a drop copy, may read and receive the full event stream but is refused on every write, on every transport, with code 1005: order entry, cancellation, amendment and configuration changes are all impossible with it.

Issue a READ_ONLY credential for back office, risk, surveillance and reporting systems, so those components provably cannot trade. A member may hold up to 5 keys of each scope at the same time: issuing a key adds it and never revokes another, and revocation is explicit, per key, immediate, and ends live WebSocket and FIX sessions using the revoked key while the member's other keys keep working. Secrets are shown exactly once, at issuance.

Conventions

Response envelope

{ "code": 0, "msg": "ok", "data": { }, "asOfSeq": 123456789, "ts": 1700000000000 }

asOfSeq is the engine sequence number the response reflects. It is a total order across the entire venue and is directly comparable with WebSocket frames, FIX ExecID values and the recovery cursor, which is what makes cross-transport reconciliation mechanical rather than heuristic.

Rules that prevent real bugs

  1. Exact decimal strings. Every price, quantity, rate and money amount is a JSON string, for example "65000.5". Parse into a decimal type. Binary floating point will eventually produce a reconciliation break.
  2. Strict request bodies. Order entry rejects unknown JSON fields with code 2017 rather than ignoring them. If you believed a field did something, the venue tells you it does not, instead of silently working the order without it.
  3. Tolerant response parsing. The venue adds response fields, event types and enum values without notice. Ignore what you do not recognise; never fail on an unknown value.
  4. Two-level success check. code: 0 means the gateway accepted the request. An order can still be rejected by the engine inside a 200 response: check data.status == "REJECTED" and read data.rejectCode.
  5. Reference data drives rounding. Read GET /v1/instruments at startup and align every price to tickSize and every quantity to qtyStep. Quantities are decimal base-asset units, and price x qty must reach the instrument's minNotional (code 2028 below it). Never hard-code instrument parameters.

Identifiers

FieldMeaning
clOrdId Your order reference, up to 36 characters, unique per member per 24 hours. It is also the idempotency key: resending an identical payload returns the original order with duplicate: true, while reusing the reference with a different payload is rejected with 2009. The KX- prefix is reserved for venue-generated references.
clientUid Your end-client reporting identifier, required on every order. Opaque to the venue, which holds no name, KYC or personal data. It rides every response and notification, including rejections and venue-initiated closes, so all activity reconciles to one end client.
orderId The venue's identifier for an accepted order.

Rate limits

Two independent token buckets per member, shared across all of the member's API keys: 6000 reads per minute and a 40000 per minute order budget. Order placements, batch entries, and amendments all consume the order budget, one unit each; cancels are never throttled. Order-budget traffic does not consume a read token, so heavy order flow never exhausts your read allowance and heavy polling never throttles your order flow. Breach returns code 1003. A batch (POST /v1/orders/batch, WS orders.batch) is charged one unit per entry up front, all or nothing: a denied batch answers 1003 and consumes nothing.

Both buckets are full-capacity and refill continuously, so after a quiet period the whole minute's allowance is available at once. The order bucket is sized deliberately for a member that must push a burst of risk-reducing orders when many end clients liquidate in a short window. Cancels consume neither bucket.

Because the buckets refill continuously rather than at a window edge, a 1003 tells you exactly how long to wait: data.retryAfterMs on REST and WebSocket, the Retry-After and X-RateLimit-Retry-After-Ms headers on REST, and Text(58) on FIX. At the default order capacity that wait is typically one or two milliseconds. Sleep it and resend, rather than pausing for a window that does not exist.

Separately, the order-to-trade regime under RTS 9 counts order messages against trades over a sliding 60 minute window; every batch entry counts as one order message. A block returns code 1004 on new orders, batches and amendments only; cancels are never blocked, so you can always withdraw liquidity.

Choosing a transport

NeedUseWhy
Requests, history, reconciliation, recovery REST The only transport carrying dated history and the cursor backfill.
Live market data and account events WebSocket The widest feed: incremental checksummed books, mark and index prices, funding, typed venue events and guaranteed private channels. FIX 4.4 streams a book and the public trade tape too, so compare the two before adding a socket you may not need.
High-rate order entry WebSocket Order operations can be pipelined, which removes the round-trip ceiling that limits a serialized REST client.
RFQ trading, barrier contracts and yield contracts REST + WebSocket The negotiation flow is REST (create, board, quote, accept; on swap markets offer, board, take) with lifecycle pushes on the private rfq, barriers and swaps channels. RFQ markets have no FIX surface.
Existing FIX infrastructure FIX 4.4 Standard order entry, a full-member execution report drop copy, and streaming market data: snapshot 35=W, incremental 35=X and the public trade tape.
Back office and risk observation Any, with a READ_ONLY credential Provably cannot trade, enforced at the credential.

Most members run REST and WebSocket together. FIX members still need REST, because recovery after a disconnect is a REST call by design.

Market data: FIX or WebSocket. Both carry a real streaming book. FIX gives you a snapshot (35=W) then incremental New, Change and Delete levels (35=X) plus a print-by-print trade tape on the same session as your orders, which is enough for most order-entry and broker integrations. The WebSocket carries strictly more: per-level book checksums for continuous verification, mark and index prices, funding, the typed venue-events feed and the sequence-cursored recovery backfill. Run FIX alone if you need order entry with a book and a tape; add a WebSocket connection if you need any of the rest.

Onboarding checklist

  1. Receive sandbox credentials from venue operations.
  2. Verify your signer against the published vector above.
  3. Fetch /v1/instruments and drive all rounding from it.
  4. Exercise every order type you intend to use, including the rejection paths.
  5. Maintain an order book from the WebSocket with checksum verification for at least five minutes without a mismatch.
  6. Kill the connection mid-flow and prove gap-free recovery from the event cursor.
  7. Handle the venue-initiated flow: executions and cancels for orders you never sent.
  8. Reconcile per-end-client sub-positions against the end-of-day snapshot.
  9. Issue a READ_ONLY credential for your back-office systems.
  10. Agree rate limits and order-to-trade thresholds with venue operations.

Support

Venue operations handle credentials, limits, instrument onboarding and incidents. Sandbox resets and production releases are announced in advance (a release that stops production at least five Business Days ahead on the Website, inside the standard maintenance window of Saturday 02:00 to 06:00 UTC, Member API section 10.7; full sandbox data resets at least 5 business days ahead, via the members Slack channel and a portal notice; the policy is section 1a of the Member API reference). Contract changes follow the versioning policy: additive changes ship without notice and your parsers must tolerate them, while breaking changes ship only under a new major version path or with at least 30 days written notice and a dated migration table.