Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

WebSocket API

Three endpoints share the same API-key namespace.

Machine-readable spec. Everything on this page is also published as an AsyncAPI 3.0 document: /docs/asyncapi.yaml. Feed it to a code generator, an agent, or npx @asyncapi/cli validate — it defines all three endpoints, the X-API-Key scheme, the ?cex= parameter, and all six message types.

Endpoints

URLRegionCoverageUse it for
wss://jp.cryptolisting.wsAWS Tokyo (ap-northeast-1a, apne1-az4)Binance + Upbit + BithumbBots in Tokyo / global
wss://kr.cryptolisting.wsAWS Seoul (ap-northeast-2c, apne2-az3)Upbit + BithumbKorea-based bots trading Upbit or Bithumb
wss://us.cryptolisting.wsAWS N. Virginia (us-east-1a, use1-az1)RobinhoodBots trading Robinhood (US)

Pick one per bot — the closest to your trading region. The Seoul endpoint removes the Seoul → Tokyo network hop on Upbit and Bithumb detection. Binance is dispatched only from the Tokyo endpoint. The same key authenticates on all three, but rate limits and connection caps are tracked independently.

Frames are binary; payloads are UTF-8 JSON.

Query parameters

ParameterRequiredDescriptionExample
cexNoComma-separated list of exchangesbinance,upbit

See Exchange Filtering.

Lifecycle

Client                              Server
  |                                   |
  |--- WSS handshake + API key -----→ |
  |←---- 101 Switching Protocols -----|
  |                                   |
  |←---- welcome --------------------|  (immediate)
  |←---- renewal_notice -------------|  (if <24 h left; also mid-session
  |                                   |   when the threshold is crossed)
  |←---- changelog ------------------|  (any valid entry not yet given to you)
  |←---- PING (control frame) -------|  (every 15 s)
  |--- PONG ------------------------→ |  (handled by your WS lib)
  |←---- heartbeat (JSON) -----------|  (every 30 s)
  |←---- announcement ---------------|  (when detected)
  |--- {"type":"test"} -------------→ |  (optional)
  |←---- test_announcement ---------|  (only to you)
  |←---- close (1000, key_expired) -|  (if key expires)

Handshake

If the key fails validation, the server rejects the upgrade with an HTTP error:

CodeCause
426Malformed upgrade request (missing/invalid Sec-WebSocket-Key or Upgrade)
401Missing X-API-Key header
403Invalid, revoked, or expired key
429Rate, per-IP, distinct-IP, or absolute-cap limit hit (or cooldown active)

See Error Handling for retry strategy.

Welcome

Sent once after a successful handshake. Confirms tier and limits. See welcome.

Keep-alive

The server sends a WebSocket PING control frame every 15 s (with 0–5 s jitter on the first). Your library responds with PONG automatically — Python websockets, Node.js ws, Go gorilla/websocket, Rust tokio-tungstenite all handle it without configuration.

If the server does not receive a PONG within 30 s of the last ping, it closes the connection.

Two different things, don’t mix them up:

  • Don’t reconnect on “no announcement for N seconds”. Listings are sparse; you’d loop during quiet periods.
  • Do treat total silence — no PING and no heartbeat for 60 s — as a dead connection, close it and reconnect. Your library’s close/error callbacks only fire when the peer says goodbye. A server that vanishes without a FIN or RST (host stopped, IP moved, path cut) sends nothing at all, and a client that only reads stays “connected” forever. If your library exposes TCP keepalive or a client-side ping with a pong timeout (Python websockets does both by default), turn it on. See Detecting dead connections.

Heartbeat

A JSON heartbeat message every 30 s, every tier. Lets your client confirm the connection is alive without waiting for a rare announcement. See heartbeat.

Announcements

When an event is detected, every subscriber whose filter matches receives an announcement. See announcement.

The envelope is identical on all four publishers — only title carries the exchange’s own language. A real Upbit KRW listing, as delivered on wss://kr.cryptolisting.ws?cex=upbit:

{
  "type": "announcement",
  "title": "플루언트(BLEND) 신규 거래지원 안내 (KRW, BTC, USDT 마켓)",
  "ticker": "BLEND",
  "publisher": "upbit",
  "listingType": "spot_listing",
  "detectedTimestampUs": 1710345000005000,
  "dispatchTimestampUs": 1710345000006000,
  "abnormalDetectionLatency": false,
  "markets": "KRW,BTC,USDT"
}

ticker is pre-extracted from the Korean title, so a Binance-shaped handler works on Upbit unchanged. Same for the two other Upbit event classes — 거래지원 종료 안내 → spot_delisting, 유의 종목 지정 해제 안내 → caution_released. See Exchange Filtering.

Every announcement also carries abnormalDetectionLatency. When true, the event was detected under unusual conditions — take precautions before acting on it.

Disconnection

The server may close the connection with a close frame. The reason field tells you why — see Error Handling.

Client-to-server messages

The only supported client message is the test request:

{"type":"test"}

Returns a fake test_announcement. Limits:

LimitValueEffect on excess
Message rate3 / minuteConnection closed (rate_limit_exceeded)
Frame size1 KBConnection closed (frame_too_large)
Test rate1 / minutetest_rate_limited error response