Kline (Candlestick)
Channel Name
spot:kline:{symbol}:{interval}
Authentication: not required (public channel).
Supported intervals: 1m, 5m, 15m, 1h, 4h, 1d. See Enums — K-line Intervals.
Description
Provides the latest candle as a snapshot on subscribe, then pushes a running OHLCV update after every fill that falls within the current candle's time window. When the window elapses, the next push carries is_closed: true. Subscribing to multiple intervals for the same symbol produces one push per interval per fill.
Subscribe
Send:
{ "type": "subscribe", "channel": "spot:kline:DFUSDT:1m" }
Response:
{ "type": "subscribed", "channel": "spot:kline:DFUSDT:1m" }
A spot_kline_snapshot is sent immediately after the ack.
Push Format
spot_kline_snapshot
Sent once on subscribe. Contains the latest completed or in-progress candle from the database.
{
"type": "spot_kline_snapshot",
"channel": "spot:kline:DFUSDT:1m",
"data": {
"symbol": "DFUSDT",
"interval": "1m",
"open_time": 1778399940,
"close_time": 1778399999,
"open": "0.4800",
"high": "0.5100",
"low": "0.4700",
"close": "0.5000",
"volume": "10000",
"quote_volume": "4900",
"trade_count": 234,
"is_closed": false
}
}
spot_kline_update
Pushed after every fill that lands inside the current candle's window. The data format is identical to spot_kline_snapshot.
{
"type": "spot_kline_update",
"channel": "spot:kline:DFUSDT:1m",
"data": {
"symbol": "DFUSDT",
"interval": "1m",
"open_time": 1778399940,
"close_time": 1778399999,
"open": "0.4800",
"high": "0.5100",
"low": "0.4700",
"close": "0.5010",
"volume": "10030",
"quote_volume": "4915",
"trade_count": 235,
"is_closed": false
}
}
When is_closed transitions to true, the candle is complete. The next push will carry the new candle's open_time.
| Field | Type | Description |
|---|---|---|
symbol | string | Market identifier. |
interval | string | Candle interval, e.g. 1m. |
open_time | integer | Candle open — unix seconds. |
close_time | integer | Candle close — unix seconds. Equal to open_time + interval_seconds − 1. |
open | string (decimal) | Opening price of the candle. |
high | string (decimal) | Highest fill price so far in this candle. |
low | string (decimal) | Lowest fill price so far in this candle. |
close | string (decimal) | Most recent fill price in this candle. |
volume | string (decimal) | Total base volume in this candle. |
quote_volume | string (decimal) | Total quote volume in this candle. |
trade_count | integer | Number of fills in this candle. |
is_closed | boolean | true once the candle's time window has elapsed. |
All timestamps are unix seconds.
Update Cadence
- One
spot_kline_updateper fill that lands in the interval's time window. - Subscribing to
1m + 5m + 1hfor the same symbol produces three pushes per fill (one per interval, each updating the respective candle). - No fixed polling timer — updates are purely event-driven.
Because each push replaces the running candle completely, a missed push is overwritten by the next one. No resync is needed. See Snapshot ↔ Live Sequencing.
Code Example
const ws = new WebSocket('wss://api-sepolia.p99.world/ws');
// Local candle state keyed by interval
const candles = {};
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'subscribe', channel: 'spot:kline:DFUSDT:1m' }));
ws.send(JSON.stringify({ type: 'subscribe', channel: 'spot:kline:DFUSDT:1h' }));
setInterval(() => ws.send(JSON.stringify({ type: 'ping' })), 30000);
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'spot_kline_snapshot' || msg.type === 'spot_kline_update') {
const d = msg.data;
candles[d.interval] = d;
if (d.is_closed) {
console.log(`[${d.interval}] Candle closed: O=${d.open} H=${d.high} L=${d.low} C=${d.close} V=${d.volume}`);
// Advance your chart to the next candle
} else {
console.log(`[${d.interval}] Live candle: C=${d.close} V=${d.volume}`);
// Repaint the live (rightmost) bar on your chart
}
}
};