Overview
WebSocket API overview, connection lifecycle, and channel model
Use the WebSocket API for market streams and private account updates.
Endpoint
| Environment | URL |
|---|---|
| Production | wss://pulse.obsdn.trade/ws |
| Testnet | wss://pulse.staging.obsdn.trade/ws |
Quick Start
# Using wscat (production)
wscat -c wss://pulse.obsdn.trade/ws
# Testnet
wscat -c wss://pulse.staging.obsdn.trade/wsconst ws = new WebSocket("wss://pulse.obsdn.trade/ws")
ws.onopen = () => {
ws.send(
JSON.stringify({
op: "sub",
channel: "ticker",
params: { market: "BTC-PERP" },
})
)
}
ws.onmessage = (event) => {
console.log(JSON.parse(event.data))
}Message Model
Subscribe
{
"op": "sub",
"channel": "CHANNEL_NAME",
"params": { "market": "MARKET_ID" }
}Unsubscribe
{
"op": "unsub",
"channel": "CHANNEL_NAME",
"params": { "market": "MARKET_ID" }
}The params field is channel-specific. Market channels use { "market": "BTC-PERP" }, the oracle channel uses { "asset": "BTC" }, and private user channels require no params, though order and position accept an optional { "market": "BTC-PERP" } filter.
Auth (for private channels)
Send before subscribing to any private channel.
{
"op": "auth",
"params": {
"key": "your_api_key",
"timestamp": "1734567890",
"signature": "your_signature"
}
}The signature is computed as base64(HMAC-SHA256(api_secret, "${api_key},${timestamp}")), using standard base64 encoding.
timestamp is a Unix time in seconds (string) and must be within ±60 seconds of server time, otherwise the auth message is rejected.
import { createHmac } from "node:crypto"
const timestamp = Math.floor(Date.now() / 1000).toString()
const signature = createHmac("sha256", apiSecret).update(`${apiKey},${timestamp}`).digest("base64")Connection
On connect, the server sends a welcome message with a unique connection identifier:
{ "type": "welcome", "connection_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }Auth Response
After a successful auth message, the server responds with:
{ "type": "authenticated", "address": "0xYourWalletAddress" }The address field confirms which wallet the connection is authenticated as.
Heartbeat
The server sends periodic pings and will disconnect if it receives no pong within 60 seconds. Clients may send their own pings for keepalive (the server will respond with a pong); they are not required to.
{ "op": "ping" }{ "type": "pong" }Subscribed Confirmation
After a successful subscription, the server sends:
{
"type": "subscribed",
"channel": "CHANNEL_NAME",
"params": { "market": "BTC-PERP" }
}The params field echoes back the subscription parameters (omitted if no params were provided).
Channel Summary
| Channel | Auth | params | Snapshot | Updates |
|---|---|---|---|---|
book | No | { market } | Yes | Yes |
trade | No | { market } (optional) | Yes | Yes |
ticker | No | { market } | Yes | Yes |
oracle | No | { asset } | Yes | Yes |
candle | No | { market } | Yes | Yes |
order | Yes | { market } (optional) | Yes | Yes |
position | Yes | { market } (optional) | Yes | Yes |
portfolio | Yes | None | Yes | Yes |
notification | Yes | None | No | Yes |
Connection Guidance
- Implement automatic reconnect with exponential backoff.
- Resubscribe to all channels after reconnect.
- Process messages in-order per channel/market stream.
- Validate order book checksums and resubscribe on mismatch.
- Respond to server pings with a pong; reconnect if disconnected.