Log in

API documentation

Build trading bots and integrations on the same engine the website uses. All endpoints live under https://zarkoin.com/api/v1. Requests and responses are JSON. Decimal values are strings, to keep full precision.

Overview

Public endpoints (market data) need no key. Private endpoints accept an API key you create in Account, API keys. Each key has permissions: READ (balances, orders, positions), SPOT (place and cancel spot orders) and FUTURES (futures trading). Keys can never withdraw funds. Restrict keys to your server’s IP addresses whenever you can.

Symbols are written without a separator, e.g. BTCUSDT. Timestamps are Unix milliseconds.

Authentication

Send three headers with every private request:

X-ZK-APIKEY:    your API key
X-ZK-TIMESTAMP: current Unix time in milliseconds
X-ZK-SIGNATURE: hex( HMAC_SHA256( secret, timestamp + METHOD + pathWithQuery + body ) )

pathWithQuery is the full path including /api/v1 and the query string, for example /api/v1/spot/orders/open?symbol=BTCUSDT. body is the exact JSON you send, serialised compactly with no spaces (empty string for GET and DELETE without a body). The timestamp must be within 10 seconds of our server time.

Rate limits and errors

Each IP can make 600 requests per minute. Placing orders is limited to 60 per 10 seconds per account. Exceeding a limit returns HTTP 429. Errors always have the same shape:

{ "error": { "code": "INSUFFICIENT_BALANCE", "message": "Insufficient USDT balance" } }

Market data

MethodPathDescriptionKey permission
GET/market/marketsSpot markets with tick size, lot size, minimums and feesPublic
GET/market/tickers24-hour statistics for every spot marketPublic
GET/market/ticker?symbol=BTCUSDT24-hour statistics for one marketPublic
GET/market/depth?symbol=BTCUSDT&limit=50Order book snapshotPublic
GET/market/trades?symbol=BTCUSDT&limit=50Recent public tradesPublic
GET/market/klines?symbol=BTCUSDT&interval=1h&limit=500&endTime=Candles: 1m 5m 15m 30m 1h 4h 1d 1wPublic
GET/futures/marketsPerpetual contracts, leverage limits and margin tiersPublic
GET/futures/tickersFutures 24-hour statistics with mark price and fundingPublic
GET/futures/mark?symbol=BTCUSDTMark price, index price, funding rate and next funding timePublic
GET/futures/funding-history?symbol=BTCUSDTPast funding ratesPublic

Spot trading

MethodPathDescriptionKey permission
POST/spot/previewAll-in cost preview: fee, average and worst price, what you receivenone
POST/spot/ordersPlace an orderSPOT
POST/spot/orders/ocoPlace a one-cancels-the-other pair (take profit + stop loss)SPOT
DELETE/spot/orders/:idCancel one order (cancels both legs of an OCO)SPOT
DELETE/spot/orders?symbol=Cancel all open orders (optionally for one market)SPOT
GET/spot/orders/open?symbol=Open ordersREAD
GET/spot/orders/history?symbol=&page=Order historyREAD
GET/spot/orders/:idOne order with its fillsREAD
GET/spot/trades?symbol=&page=Your fillsREAD

Order body:

{
  "symbol": "BTCUSDT",
  "side": "BUY" | "SELL",
  "type": "LIMIT" | "MARKET" | "STOP_LIMIT" | "STOP_MARKET" | "TAKE_PROFIT_LIMIT" | "TAKE_PROFIT_MARKET"
        | "TRAILING_STOP_MARKET",
  "timeInForce": "GTC" | "IOC" | "FOK" | "POST_ONLY",   // limit orders, default GTC
  "price": "60000",          // limit price
  "stopPrice": "59000",      // stop / take-profit trigger
  "quantity": "0.001",       // base amount
  "quoteQuantity": "100",    // market buy by quote amount (instead of quantity)
  "callbackRate": "1.5",     // trailing stop: distance in percent, 0.1–10
  "activationPrice": "62000",// trailing stop: optional, SELL above / BUY below the market
  "clientOrderId": "my-id-1" // optional, letters, digits, - and _
}

A trailing stop tracks the highest price (sell) or lowest price (buy) after activation and executes at market when the price turns back by callbackRate. While it waits, stopPrice shows the current trigger and trailPrice the best price so far.

OCO body. SELL: price above the market and stopPrice below it; BUY: the reverse. Funds are locked once for both legs:

{
  "symbol": "BTCUSDT",
  "side": "SELL",
  "quantity": "0.5",
  "price": "66000",          // take-profit limit leg (rests on the book)
  "stopPrice": "58000",      // stop-loss trigger
  "stopLimitPrice": "57900", // optional; omit for a stop-market leg
  "clientOrderId": "my-oco-1"
}
// → { "ocoGroup": "…", "orders": [limitLeg, stopLeg] }
// A fill on the limit leg cancels the stop leg; the stop triggering cancels the limit leg.

Futures trading

MethodPathDescriptionKey permission
GET/futures/accountFutures wallet: balance, margin, availableREAD
GET/futures/positionsOpen positions with liquidation priceREAD
POST/futures/leverageSet leverage { symbol, leverage }FUTURES
POST/futures/margin-modeSet CROSS or ISOLATED { symbol, marginMode }FUTURES
POST/futures/ordersPlace an orderFUTURES
DELETE/futures/orders/:idCancel one orderFUTURES
GET/futures/orders/openOpen ordersREAD
GET/futures/orders/historyOrder historyREAD
POST/futures/positions/tpslSet take-profit / stop-loss on a positionFUTURES
POST/futures/positions/closeClose a position at marketFUTURES
POST/futures/positions/close-allClose every position at marketFUTURES
GET/futures/positions/historyClosed positions with realised PnLREAD
GET/futures/funding-paymentsFunding you paid or receivedREAD

Order body adds futures fields to the spot shape:

{
  "symbol": "BTCUSDT", "side": "BUY", "type": "LIMIT", "price": "60000", "quantity": "0.01",
  "reduceOnly": false,        // only reduce an existing position
  "triggerBy": "MARK_PRICE",  // or LAST_PRICE, for stop orders
  "tpPrice": "66000",         // optional take-profit attached to the order
  "slPrice": "58000",         // optional stop-loss attached to the order
  "callbackRate": "1.5",      // type TRAILING_STOP_MARKET: distance in percent, 0.1–10
  "activationPrice": "64000"  // trailing stop: optional, SELL above / BUY below the trigger price
}

WebSocket

Connect to wss://zarkoin.com/ws and subscribe to channels. You receive a snapshot immediately and then updates. Messages look like { ch, data, ts }.

MethodPathDescriptionKey permission
SUBtickersAll spot tickers, about once a secondPublic
SUBticker:BTCUSDTOne spot tickerPublic
SUBdepth:BTCUSDTTop 50 order book levelsPublic
SUBtrades:BTCUSDTNew public tradesPublic
SUBkline:BTCUSDT:1mThe current candlePublic
SUBf.ticker:BTCUSDT f.depth:… f.trades:… f.kline:…Futures equivalentsPublic
SUBf.mark:BTCUSDTMark price, index price and funding ratePublic

After authenticating, private events arrive automatically on these channels: orders, f.orders, positions, balances, notifications, deposits, withdrawals.

const ws = new WebSocket('wss://zarkoin.com/ws');

ws.onopen = () => {
  ws.send(JSON.stringify({ op: 'subscribe', channels: ['ticker:BTCUSDT', 'depth:BTCUSDT', 'trades:BTCUSDT', 'kline:BTCUSDT:1m'] }));
  // private events (orders, balances, positions…) need a logged-in session token:
  // ws.send(JSON.stringify({ op: 'auth', token: ACCESS_TOKEN }));
  setInterval(() => ws.send(JSON.stringify({ op: 'ping' })), 20000);
};

ws.onmessage = (ev) => {
  const msg = JSON.parse(ev.data);
  if (msg.ch) console.log(msg.ch, msg.data); // { ch, data, ts }
};

Code examples

Node.js (18+):

import crypto from 'node:crypto';

const API_KEY = process.env.ZK_API_KEY;
const API_SECRET = process.env.ZK_API_SECRET;
const BASE = 'https://zarkoin.com';

async function zk(method, path, body) {
  const ts = Date.now().toString();
  const payload = body ? JSON.stringify(body) : '';           // compact JSON, no spaces
  const signature = crypto
    .createHmac('sha256', API_SECRET)
    .update(ts + method + path + payload)
    .digest('hex');
  const res = await fetch(BASE + path, {
    method,
    headers: {
      'Content-Type': 'application/json',
      'X-ZK-APIKEY': API_KEY,
      'X-ZK-TIMESTAMP': ts,
      'X-ZK-SIGNATURE': signature,
    },
    body: payload || undefined,
  });
  const data = await res.json();
  if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
  return data;
}

// Place a limit buy for 0.001 BTC at 60,000 USDT
const order = await zk('POST', '/api/v1/spot/orders', {
  symbol: 'BTCUSDT', side: 'BUY', type: 'LIMIT', price: '60000', quantity: '0.001', timeInForce: 'GTC',
});
console.log(order);

// List open orders
console.log(await zk('GET', '/api/v1/spot/orders/open?symbol=BTCUSDT'));

Python 3:

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

API_KEY = os.environ["ZK_API_KEY"]
API_SECRET = os.environ["ZK_API_SECRET"].encode()
BASE = "https://zarkoin.com"

def zk(method, path, body=None):
    ts = str(int(time.time() * 1000))
    payload = json.dumps(body, separators=(",", ":")) if body is not None else ""  # compact JSON
    sig = hmac.new(API_SECRET, (ts + method + path + payload).encode(), hashlib.sha256).hexdigest()
    headers = {
        "Content-Type": "application/json",
        "X-ZK-APIKEY": API_KEY,
        "X-ZK-TIMESTAMP": ts,
        "X-ZK-SIGNATURE": sig,
    }
    r = requests.request(method, BASE + path, headers=headers, data=payload or None, timeout=10)
    data = r.json()
    if not r.ok:
        raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
    return data

# Open a 10x long of 0.01 BTC with a stop-loss
print(zk("POST", "/api/v1/futures/leverage", {"symbol": "BTCUSDT", "leverage": 10}))
print(zk("POST", "/api/v1/futures/orders", {
    "symbol": "BTCUSDT", "side": "BUY", "type": "MARKET", "quantity": "0.01", "slPrice": "58000",
}))