Skip to main content

Quickstart β€” Your First Trade in 5 Minutes

This guide walks you through a complete integration: fetch public market data, authenticate, place an order on testnet, and subscribe to real-time updates via WebSocket.


Prerequisites​

Use testnet first

All examples below target testnet so you can experiment without risking real funds. Switch to production URLs when you're ready.

ProductProductionTestnet
Spot RESThttps://api.btse.com/spothttps://testapi.btse.io/spot
Spot WebSocketwss://ws.btse.com/ws/spotwss://testws.btse.io/ws/spot

Step 1 β€” Fetch Public Market Data (No Auth Required)​

Get a list of all tradeable spot markets to find the symbol you want to trade.

Endpoint: GET /public-api/market/v1/markets

No headers required. Returns price, volume, and trading pair configuration for every market. Market data is served by the Markets API.

See Markets Information for the full field reference.

example
GET/public-api/market/v1/markets

Python

import requests

resp = requests.get("https://testapi.btse.io/public-api/market/v1/markets")
symbols = resp.json()["data"]["symbols"]

# Find BTC-USDT
btc = next(s for s in symbols if s["symbol"] == "BTC-USDT")
print(f"BTC-USDT minOrderSize: {btc['minOrderSize']}, active: {btc['active']}")

Node.js

const resp = await fetch(
"https://testapi.btse.io/public-api/market/v1/markets"
);
const { data } = await resp.json();

const btc = data.symbols.find((s) => s.symbol === "BTC-USDT");
console.log(`BTC-USDT minOrderSize: ${btc.minOrderSize}, active: ${btc.active}`);

curl

curl https://testapi.btse.io/public-api/market/v1/markets?symbol=BTC-USDT

Step 2 β€” Sign an Authenticated Request​

Private endpoints require three headers. The signature is HMAC-SHA384(secret, path + nonce + body).

See Authentication for the full specification.

Headers for every private request:

HeaderValue
request-apiYour API key
request-nonceCurrent UTC timestamp in milliseconds
request-signHMAC-SHA384 signature

Signature input = urlPath + nonce + bodyString

  • For GET requests, bodyString is empty string ""
  • For POST/PUT/DELETE, bodyString is the raw JSON body
  • The Spot v4 urlPath includes the /spot prefix (e.g. /spot/api/v4/trade/orders)
example

Python β€” signing helper

import hmac, hashlib, time, json, requests

API_KEY = "your-api-key"
API_SECRET = "your-api-secret"
BASE_URL = "https://testapi.btse.io"

def signed_request(method, path, body=None):
nonce = str(int(time.time() * 1000))
body_str = json.dumps(body) if body else ""
message = path + nonce + body_str
signature = hmac.new(
API_SECRET.encode(), message.encode(), hashlib.sha384
).hexdigest()

headers = {
"request-api": API_KEY,
"request-nonce": nonce,
"request-sign": signature,
"Content-Type": "application/json",
}
url = BASE_URL + path
if method == "GET":
return requests.get(url, headers=headers)
elif method == "POST":
return requests.post(url, headers=headers, json=body)
elif method == "DELETE":
return requests.delete(url, headers=headers)

Node.js β€” signing helper

import crypto from "crypto";

const API_KEY = "your-api-key";
const API_SECRET = "your-api-secret";
const BASE_URL = "https://testapi.btse.io";

async function signedRequest(method, path, body) {
const nonce = Date.now().toString();
const bodyStr = body ? JSON.stringify(body) : "";
const message = path + nonce + bodyStr;
const signature = crypto
.createHmac("sha384", API_SECRET)
.update(message)
.digest("hex");

const headers = {
"request-api": API_KEY,
"request-nonce": nonce,
"request-sign": signature,
"Content-Type": "application/json",
};

const resp = await fetch(BASE_URL + path, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
return resp.json();
}

Step 3 β€” Place a Test Order​

Place a limit buy order for BTC-USD on testnet.

Endpoint: POST /spot/api/v4/trade/orders

Required permission: Trading

The response includes status: 2 (ORDER_INSERTED) on success. See Error Codes β†’ API Status Enum for all status codes.

See Place order for the full field reference.

example
POST/spot/api/v4/trade/orders

Python

order = {
"symbol": "BTC-USD",
"orderSide": "BUY",
"orderType": "LIMIT",
"orderPrice": 20000,
"orderSize": 0.001,
}

resp = signed_request("POST", "/spot/api/v4/trade/orders", order)
result = resp.json()
print(f"Order ID: {result[0]['orderId']}, status: {result[0]['status']}")

Node.js

const order = {
symbol: "BTC-USD",
orderSide: "BUY",
orderType: "LIMIT",
orderPrice: 20000,
orderSize: 0.001,
};

const result = await signedRequest("POST", "/spot/api/v4/trade/orders", order);
console.log(`Order ID: ${result[0].orderId}, status: ${result[0].status}`);

Response

[
{
"orderId": "990db9b6-2ed4-4c68-b46e-827c88cc3884",
"clOrderId": "",
"status": 2,
"market": "BTC-USD",
"type": 76,
"orderSide": "BUY",
"orderPrice": 20000.0,
"postOnly": false,
"timestamp": 1660208800123,
"userQuoteCurrency": "USD",
"orderCurrency": "base",
"originalOrderBaseSize": 0.001,
"currentOrderBaseSize": 0.001,
"remainingOrderBaseSize": 0.001,
"filledBaseSize": 0,
"totalFilledBaseSize": 0,
"avgFilledPrice": 0,
"time_in_force": "GTC"
}
]

Step 4 β€” Subscribe to Real-Time Updates via WebSocket​

Open a WebSocket connection to receive live order updates and trade fills.

Connection flow:

  1. Connect to wss://testws.btse.io/ws/spot
  2. Send ping every 15 seconds to keep alive (server responds pong)
  3. Authenticate with authKeyExpires to access private topics
  4. Subscribe to topics: notificationApiV3 (order updates), fills (trade fills)

WS authentication signature:

HMAC-SHA384(secret, "/ws/spot" + nonce)

See WebSocket Authentication for details.

example

Python (using websockets library)

import asyncio, websockets, json, hmac, hashlib, time

WS_URL = "wss://testws.btse.io/ws/spot"
API_KEY = "your-api-key"
API_SECRET = "your-api-secret"

async def main():
async with websockets.connect(WS_URL) as ws:
# 1. Authenticate
nonce = str(int(time.time() * 1000))
sig = hmac.new(
API_SECRET.encode(),
f"/ws/spot{nonce}".encode(),
hashlib.sha384,
).hexdigest()

await ws.send(json.dumps({
"op": "authKeyExpires",
"args": [API_KEY, nonce, sig],
}))

# 2. Subscribe to order notifications
await ws.send(json.dumps({
"op": "subscribe",
"args": ["notificationApiV3"],
}))

# 3. Listen for messages
async for msg in ws:
if msg == "pong":
continue
data = json.loads(msg)
print(json.dumps(data, indent=2))

asyncio.run(main())

Node.js (using ws library)

import WebSocket from "ws";
import crypto from "crypto";

const WS_URL = "wss://testws.btse.io/ws/spot";
const API_KEY = "your-api-key";
const API_SECRET = "your-api-secret";

const ws = new WebSocket(WS_URL);

ws.on("open", () => {
// 1. Authenticate
const nonce = Date.now().toString();
const sig = crypto
.createHmac("sha384", API_SECRET)
.update("/ws/spot" + nonce)
.digest("hex");

ws.send(JSON.stringify({
op: "authKeyExpires",
args: [API_KEY, nonce, sig],
}));

// 2. Subscribe to order notifications
ws.send(JSON.stringify({
op: "subscribe",
args: ["notificationApiV3"],
}));

// 3. Keep alive
setInterval(() => ws.send("ping"), 15000);
});

ws.on("message", (msg) => {
const str = msg.toString();
if (str === "pong") return;
console.log(JSON.parse(str));
});

Step 5 β€” Cancel the Test Order​

Clean up by cancelling the order you placed.

Endpoint: DELETE /spot/api/v4/trade/orders

Pass the orderId from Step 3. See Cancel order for the full reference.

example
DELETE/spot/api/v4/trade/orders

Python

resp = signed_request(
"DELETE",
"/spot/api/v4/trade/orders?symbol=BTC-USD&orderId=990db9b6-2ed4-4c68-b46e-827c88cc3884",
)
print(resp.json())

Node.js

const result = await signedRequest(
"DELETE",
"/spot/api/v4/trade/orders?symbol=BTC-USD&orderId=990db9b6-2ed4-4c68-b46e-827c88cc3884"
);
console.log(result);

What's Next?​

GoalResource
Explore all spot endpointsSpot API Overview
Try endpoints interactivelyAPI Explorer
Trade futuresFutures API Overview
Manage wallets & withdrawalsWallet API Overview
Build a real-time orderbookOrderbook Incremental Updates
Understand error responsesError Codes