Public WebSocket API
WebSocket Connection Management
WebSocket endpoint is wss://api.whitebit.com/ws
The API is based on JSON RPC of WebSocket protocol.
⚠️️ Connection Timeout ⚠️️
- Server closes websocket connection after 60 seconds of inactivity
- Inactivity is defined as no messages sent by the client
Maintaining Connection
To keep the websocket connection active:
- Send periodic ping messages every 50 seconds
- Handle potential connection closures gracefully in your application logic
Example Implementation
// Establish websocket connection
const socket = new WebSocket("wss://api.whitebit.com/ws");
// Set up periodic ping
setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({
id: 0,
method: "ping",
params: [],
}));
}
}, 50000); // Every 50 seconds❗ Rate limit 1000 ws connections per minute and 200 requests per minute in one connection.❗
All endpoints return time in Unix-time format.
⤴️ Request message
JSON Structure of request message:
id- Integer. Should be unique to handle response for your request.method- String. Name of request.params- Array. Here you pass params for method.
🚫 WebSocket connection will be closed if invalid JSON was sent.
Types of request messages
- Query (
ping,candles_request, etc) - Subscription (
candles_subscribe,lastprice_subscribe, etc). Repeated subscription will be cancelled for the same data type.
⤵️ Response message
JSON Structure of response message:
id- Integer. Id of request.result- Null for failure, for success - look for responses belowerror- Null for success, JSON Object for failure:message- Detailed textcode- Error code
| Code | Message |
|---|---|
| 1 | invalid argument |
| 2 | internal error |
| 3 | service unavailable |
| 4 | method not found |
| 5 | service timeout |
Types of response messages
- Query result
- Subscription status (success/failed)
- Update events
Examples
Example messages for request with response:
⤴️ Request
{
"id": 0,
"method": "ping",
"params": []
}⤵️ Response
{
"id": 0,
"result": "pong",
"error": null
}Example subscription:
⤴️ Request
{
"id": 0,
"method": "candles_subscribe",
"params": []
}⤵️ Response
{
"id": 0,
"result": {
"status": "success"
},
"error": null
}🔄 Update events
{
"id": null,
"method": "candles_update",
"params": [] // look below for params
}API
Service
Ping
⤴️ Request
{
"id": 0,
"method": "ping",
"params": []
}⤵️ Response
{
"id": 0,
"result": "pong",
"error": null
}Time
⤴️ Request
{
"id": 1,
"method": "time",
"params": []
}⤵️ Response
{
"id": 1,
"result": 1493285895,
"error": null
}Kline
Query
The requested interval must meet the following conditions:
- If the number is less than 60, then 60 must be divisible by the requested number without a remainder;
- Less than 3600 (1 hour) - the number must be divisible by 60 without a remainder, and 3600 must be divisible by the requested number without a remainder;
- Less than 86400 (day) - the number must be whitened by 3600 without a remainder, and 86400 must be divisible by the number without a remainder;
- Less than 86400 * 7 (week) - the number must be divisible by 86400 without a remainder;
- Equal to 86400 * 7;
- Equal to 86400 * 30.
⤴️ Request
{
"id": 2,
"method": "candles_request",
"params": [
"ETH_BTC", // market
1659569940, // start time
1660894800, // end time
3600 // interval in seconds
]
}⤵️ Response
{
"id": 2,
"result": [
[
1580860800, // time
"0.020543", // open
"0.020553", // close
"0.020614", // highest
"0.02054", // lowest
"7342.597", // volume in stock
"151.095481849", // volume in deal
"ETH_BTC" // market
],
],
"error": null
}Subscribe
Update interval: 0.5 sec
⤴️ Request
{
"id": 3,
"method": "candles_subscribe",
"params": [
"BTC_USD", // market
900 // interval in seconds
]
}⤵️ Response
{
"id": 3,
"result": {
"status": "success"
},
"error": null
}🔄 Update events
{
"id": null,
"method": "candles_update",
"params": [
[
1580895000, // time
"0.020683", // open
"0.020683", // close
"0.020683", // high
"0.020666", // low
"504.701", // volume in stock
"10.433600491", // volume in money (deal)
"ETH_BTC" // market
]
]
}Unsubscribe
⤴️ Request
{
"id": 4,
"method": "candles_unsubscribe",
"params": []
}⤵️ Response
{
"id": 4,
"result": {
"status": "success"
},
"error": null
}Last price
Query
⤴️ Request
{
"id": 5,
"method": "lastprice_request",
"params": [
"ETH_BTC" // market
]
}⤵️ Response
{
"id": 5,
"result": "0.020553",
"error": null
}Subscribe
Update interval: 1 sec
⤴️ Request
{
"id": 6,
"method": "lastprice_subscribe",
"params": [
"ETH_BTC", // markets
"BTC_USDT",
]
}⤵️ Response
{
"id": 6,
"result": {
"status": "success"
},
"error": null
}🔄 Update events
{
"id": null,
"method": "lastprice_update",
"params": [
"ETH_BTC", // market
"0.020683" // price
]
}Unsubscribe
⤴️ Request
{
"id": 7,
"method": "lastprice_unsubscribe",
"params": []
}⤵️ Response
{
"id": 7,
"result": {
"status": "success"
},
"error": null
}Market statistics
Query
⤴️ Request
{
"id": 5,
"method": "market_request",
"params": [
"ETH_BTC", // market
86400 // period in seconds
]
}⤵️ Response
{
"id": 5,
"result": {
"period": 86400, // period in seconds
"last": "0.020981", // last price
"open": "0.02035", // open price that was at 'now - period' time
"close": "0.020981", // price that closes this period
"high": "0.020988", // highest price
"low": "0.020281", // lowest price
"volume": "135220.218", // volume in stock
"deal": "2776.587022649" // volume in money
},
"error": null
}Subscribe
You can subscribe only for 86400s (24h from now).
Update interval: 1 sec
⤴️ Request
{
"id": 6,
"method": "market_subscribe",
"params": [
"ETH_BTC", // markets
"BTC_USDT",
]
}⤵️ Response
{
"id": 6,
"result": {
"status": "success"
},
"error": null
}🔄 Update events
{
"id": null,
"method": "market_update",
"params": [
"ETH_BTC", // market
{
// response same as 'market_request'
"period": 86400, // period in seconds
"last": "0.020964", // last price
"open": "0.020349", // open price that was at 'now - period' time
"close": "0.020964", // price that closes this period
"high": "0.020997", // highest price
"low": "0.020281", // lowest price
"volume": "135574.476", // volume in stock
"deal": "2784.413999488" // volume in money
}
]
}Unsubscribe
⤴️ Request
{
"id": 7,
"method": "market_unsubscribe",
"params": []
}⤵️ Response
{
"id": 7,
"result": {
"status": "success"
},
"error": null
}Market statistics for current day UTC
Query
⤴️ Request
{
"id": 14,
"method": "marketToday_query",
"params": [
"ETH_BTC" // only one market per request
]
}⤵️ Response
{
"id": 14,
"result": {
"last": "0.020981", // last price
"open": "0.02035", // open price that was at 'now - period' time
"high": "0.020988", // highest price
"low": "0.020281", // lowest price
"volume": "135220.218", // volume in stock
"deal": "2776.587022649" // volume in money
},
"error": null
}Subscribe
Update interval: 1 sec
⤴️ Request
{
"id": 15,
"method": "marketToday_subscribe",
"params": [
"ETH_BTC", // markets
"BTC_USDT",
]
}⤵️ Response
{
"id": 15,
"result": {
"status": "success"
},
"error": null
}🔄 Update events
{
"id": null,
"method": "marketToday_update",
"params": [
"ETH_BTC", // market
{
// response same as 'market_request'
"last": "0.020964", // last price
"open": "0.020349", // open price that was at 'now - period' time
"high": "0.020997", // highest price
"low": "0.020281", // lowest price
"volume": "135574.476", // volume in stock
"deal": "2784.413999488" // volume in money
}
]
}Unsubscribe
⤴️ Request
{
"id": 16,
"method": "marketToday_unsubscribe",
"params": []
}⤵️ Response
{
"id": 16,
"result": {
"status": "success"
},
"error": null
}Market trades
Query
⤴️ Request
{
"id": 8,
"method": "trades_request",
"params": [
"ETH_BTC", // market
100, // limit
41358445 // largest id from which you want to request trades
]
}⤵️ Response
{
"id": 8,
"result": [
{
"id": 41358530, // trade id
"time": 1580905394.70332, // time in milliseconds
"price": "0.020857", // trade price
"amount": "5.511", // trade amount
"type": "sell" // type of trade (buy/sell)
},
],
"error": null
}
Subscribe
Update interval: real-time
❗ For each websocket connection, you can subscribe to either one or several specific markets, or all markets. Every following subscription will replace the existing one.
Note: To subscribe to all markets, send the request with an empty params array.
⤴️ Request
Subscribe to specific markets:
{
"id": 9,
"method": "trades_subscribe",
"params": [
"ETH_BTC", // markets
"BTC_USDT",
]
}Subscribe to all markets:
{
"id": 9,
"method": "trades_subscribe",
"params": []
}⤵️ Response
{
"id": 9,
"result": {
"status": "success"
},
"error": null
}🔄 Update events
{
"id": null,
"method": "trades_update",
"params": [
"ETH_BTC", // market
[ // response same as 'market_request'
{
"id": 41358530, // trade id
"time": 1580905394.70332, // time in milliseconds
"price": "0.020857", // trade price
"amount": "5.511", // trade amount
"type": "sell", // type of trade (buy/sell)
"rpi": true // Indicates whether the trade involved a Retail Price Improvement (RPI) order
}
]
]
}Unsubscribe
⤴️ Request
{
"id": 10,
"method": "trades_unsubscribe",
"params": []
}⤵️ Response
{
"id": 10,
"result": {
"status": "success"
},
"error": null
}Market depth
Query
This endpoint allows clients to request the current market depth for a specific cryptocurrency pair.
⤴️ Request
{
"id": 11,
"method": "depth_request",
"params": [
"ETH_BTC", // market
100, // limit, max value is 100
"0" // price interval units. "0" - no interval, available values - "0.00000001", "0.0000001", "0.000001", "0.00001", "0.0001", "0.001", "0.01", "0.1"
]
}⤵️ Response
{
"id": 11,
"result": {
"timestamp": 1689600180.5164471, // timestamp of the update from matchengine
"asks": [ // sorted ascending
["0.020846", "29.369"], // [price, amount]
],
"bids": [ // sorted descending
["0.02083", "9.598"], // [price, amount]
]
},
"error": null
}
Subscribe
This endpoint allows clients to subscribe to market depth data updates. After successful subscription, the server immediately sends a full snapshot of the current order book as the first depth_update message. Subsequent messages are incremental updates containing only changes. The server pushes updates every 100ms to subscribed clients when there are actual changes to the order book.
⤴️ Request
{
"id": 12,
"method": "depth_subscribe",
"params": [
"ETH_BTC", // market
100, // limit. available values - 1, 5, 10, 20, 30, 50, 100
"0", // price interval units. "0" - no interval, available values - "0.00000001", "0.0000001", "0.000001", "0.00001", "0.0001", "0.001", "0.01", "0.1"
true // multiple subscription flag. true - add, false - unsubscribe from all
]
}The fourth parameter - Multiple subscription flag - allows you to subscribe to market depths as many markets as you want. The only restriction is one subscription with specific parameters per market.
INFO: If 10 seconds have elapsed without a change in the depth subscription, a snapshot message will be pushed again
⤵️ Response
{
"id": 12,
"result": {
"status": "success"
},
"error": null
}🔄 Update events
Update events provide real-time updates to the subscribed market depth. The first message after subscription is a full snapshot of the order book, while subsequent messages are incremental updates.
First message (full snapshot):
{
"id": null,
"method": "depth_update",
"params": [
true,
{
"timestamp": 1689600180.5164471, // timestamp of the update from matchengine
"update_id": 214403,
"asks": [ // sorted ascending - full order book snapshot
["0.020846", "29.369"],
["0.020850", "15.123"],
["0.020855", "8.456"],
],
"bids": [ // sorted descending - full order book snapshot
["0.020844", "5.949"],
["0.020840", "12.345"],
["0.020835", "20.678"],
],
"event_time": 1749026542.817343
},
"ETH_BTC" // market pair
]
}Subsequent messages (incremental updates):
{
"id": null,
"method": "depth_update",
"params": [
false,
{
"timestamp": 1689600180.5164471, // timestamp of the update from matchengine
"update_id": 214404,
"past_update_id": 214403, // present in incremental updates
"asks": [
["0.020861", "0"], // finished orders will be [price, "0"]
["0.020900", "2.5"],
],
"bids": [
["0.020844", "5.949"],
["0.020800", "0"],
],
"event_time": 1749026542.817343
},
"ETH_BTC" // market pair
]
}💻 Code examples
type IDepth = [string, string];
interface OrderBook {
asks: IDepth[];
bids: IDepth[];
}
const ws = new WebSocket("wss://api.whitebit.com/ws");
const orderBook: OrderBook = { asks: [], bids: [] };
const LIMIT = 100;
ws.addEventListener("open", () => {
ws.send(
JSON.stringify({
id: 1,
method: "depth_subscribe",
params: ["ETH_BTC", LIMIT, "0", true]
}),
);
});
ws.addEventListener("message", (event: MessageEvent) => {
const message = JSON.parse(event.data.toString());
if (message.method === "depth_update") {
const updateData = message.params[0] as Partial<OrderBook & { past_update_id?: number }>;
const isFirstMessage = !updateData.past_update_id;
if (isFirstMessage) {
// First message or keepalive snapshot is a full snapshot - replace order book
orderBook.asks = updateData.asks ?? [];
orderBook.bids = updateData.bids ?? [];
} else {
// Subsequent messages are incremental updates
applyUpdates(orderBook.asks, updateData.asks, "ask");
applyUpdates(orderBook.bids, updateData.bids, "bid");
truncateOrderBook(orderBook.asks);
truncateOrderBook(orderBook.bids);
}
}
});
function applyUpdates(orderBookSide: IDepth[], updates: IDepth[] | undefined, side: "ask" | "bid") {
if (updates === undefined) return;
for (const [price, amount] of updates) {
// Find the index of an entry in orderBookSide that matches the given price.
const priceIndex = orderBookSide.findIndex((level) => level[0] === price);
// If the amount is '0', it means this price level should be removed from the orderBookSide.
if (amount === "0") {
if (priceIndex !== -1) {
// Remove the existing price level since the amount is '0'.
orderBookSide.splice(priceIndex, 1);
}
} else {
// If the amount is not '0', either update the existing price level or add a new one.
if (priceIndex === -1) {
// Find the position where the new price level should be inserted.
const insertIndex = orderBookSide.findIndex((level) =>
side === "ask" ? level[0] > price : level[0] < price
);
if (insertIndex === -1) {
// Add to the end if there's no higher price level.
orderBookSide.push([price, amount]);
} else {
// Insert at the correct sorted position.
orderBookSide.splice(insertIndex, 0, [price, amount]);
}
} else {
// Update the amount for the existing price level.
orderBookSide[priceIndex][1] = amount;
}
}
}
}
function truncateOrderBook(orderBookSide: IDepth[]) {
if (orderBookSide.length > LIMIT) {
// Only truncate if the length exceeds the LIMIT
orderBookSide.splice(LIMIT);
}
}Unsubscribe
This endpoint allows clients to unsubscribe from real-time updates of market depth data.
⤴️ Request
{
"id": 13,
"method": "depth_unsubscribe",
"params": []
}⤵️ Response
{
"id": 13,
"result": {
"status": "success"
},
"error": null
}Book Ticker
The Book Ticker stream provides instant snapshot updates to the best bid and ask prices and quantities for a market.
Subscribe
Update interval: instant snapshot of the current best bid and ask (BBO), followed by incremental updates.
⤴️ Request
{
"method": "bookTicker_subscribe",
"params": [
"SHIB_PERP" // Optional: market name. If empty, subscribes to all markets
],
"id": 1
}⤵️ Response
{
"id": 1,
"result": {
"status": "success"
},
"error": null
}🔄 Update events
{
"method": "bookTicker_update",
"params": [
[
1751958383.5933869, // transaction_time - timestamp of the update from matchengine
1751958383.5935569, // message_time - timestamp of the message from websocket
"SHIB_PERP", // market
80670102, // update_id
"0.000011751", // best_bid_price
"12547000", // best_bid_amount
"0.000011776", // best_ask_price
"17424000" // best_ask_amount
]
],
"id": null
}Unsubscribe
⤴️ Request
{
"method": "bookTicker_unsubscribe",
"params": [],
"id": 2
}⤵️ Response
{
"id": 2,
"result": {
"status": "success"
},
"error": null
}Try out WebSocket API directly in the documentation