Skip to main content
Blink provides three WebSocket channels for real-time data:
ChannelURLAuthUse Case
Market/ws/marketNoneOrderbook snapshots, trades, market events
Price/ws/priceNonePyth oracle price ticks
User/ws/userAPI credsFills, cancels, balance updates

Market WebSocket

Subscribe to orderbook updates and trades for specific tokens:
from py_blink_client import BlinkMarketWs

def on_snapshot(msg):
    """Full orderbook snapshot — sent on subscribe and periodically."""
    print(f"Orderbook: {len(msg['bids'])} bids, {len(msg['asks'])} asks")
    if msg['bids']:
        print(f"  Best bid: {msg['bids'][0]['price']} x {msg['bids'][0]['size']}")
    if msg['asks']:
        print(f"  Best ask: {msg['asks'][0]['price']} x {msg['asks'][0]['size']}")

def on_trade(msg):
    """A trade was executed."""
    print(f"Trade: {msg['side']} {msg['size']} @ {msg['price']}")

def on_market_created(msg):
    """A new market was created."""
    print(f"Market created: {msg['market_id']}")

def on_market_status(msg):
    """Market status changed (resolved, halted, etc.)."""
    print(f"Market {msg['market_id']}: {msg['status']}")

ws = BlinkMarketWs("https://api.blink15.com")
ws.on_snapshot = on_snapshot
ws.on_trade = on_trade
ws.on_market_created = on_market_created
ws.on_market_status = on_market_status

# Connect
ws.start()

# Subscribe to specific tokens
ws.subscribe([yes_token_id, no_token_id])

# Unsubscribe
ws.unsubscribe([yes_token_id])

# Disconnect
ws.stop()

Snapshot Format

{
  "type": "orderbook_snapshot",
  "asset_id": "abc123...",
  "bids": [
    {"price": "0.55", "size": "150"},
    {"price": "0.54", "size": "200"}
  ],
  "asks": [
    {"price": "0.57", "size": "100"},
    {"price": "0.58", "size": "175"}
  ],
  "timestamp": 1711929600
}

Gap Recovery

If you suspect missed messages (e.g., after a network blip), request a fresh snapshot:
ws.resync(yes_token_id)

Price WebSocket

Subscribe to Pyth oracle price ticks by stock symbol:
from py_blink_client import BlinkPriceWs

def on_tick(msg):
    print(f"{msg['asset_id']}: ${msg['price']} (conf: {msg['confidence']})")

ws = BlinkPriceWs("https://api.blink15.com")
ws.on_price_tick = on_tick
ws.start()

# Subscribe by symbol name
ws.subscribe(["BTCUSD", "ETHUSD", "SOLUSD"])

Tick Format

{
  "type": "price_tick",
  "asset_id": "BTCUSD",
  "price": "227.45",
  "confidence": "0.02",
  "timestamp": 1711929600
}
Price ticks arrive multiple times per second, 24/7.

User WebSocket

Receive private events for your account through two unified callbacks:
  • on_state_changed — full snapshot of your USDC balance, positions, and open orders. Delivered after every mutation (fill, cancel, settlement, redemption).
  • on_notification — discrete events like fills, cancellations, and rejections with enriched data (market symbol, token type).
from py_blink_client import BlinkUserWs

def on_state(msg):
    """Full user state snapshot — balance, positions, orders."""
    print(f"USDC: {msg['usdc_balance']}, Available: {msg['available_usdc']}")
    print(f"Positions: {len(msg['positions'])}, Orders: {len(msg['open_orders'])}")
    for pos in msg['positions']:
        print(f"  {pos['token_id'][:12]}.. balance={pos['balance']}")

def on_notification(msg):
    """Discrete event — fill, cancel, rejection, etc."""
    kind = msg['kind']
    data = msg['data']
    if kind == 'order_fill':
        print(f"Fill: {data['side']} {data['quantity']} @ {data['price']} ({data.get('symbol', '?')})")
    elif kind == 'order_cancelled':
        print(f"Cancelled: {data['order_id']}")
    elif kind == 'order_rejected':
        print(f"Rejected: {data['reason']}")
    elif kind == 'order_accepted':
        print(f"Accepted: {data['order_id']} {data['side']} @ {data['price']}")

ws = BlinkUserWs("https://api.blink15.com", creds)  # creds from client.create_or_derive_api_creds()
ws.on_state_changed = on_state
ws.on_notification = on_notification
ws.start()

# User WS auto-subscribes to your account — no manual subscribe needed

# Disconnect
ws.stop()

Authentication

The User WebSocket authenticates using the same API credentials from create_or_derive_api_creds():
creds = client.create_or_derive_api_creds()

ws = BlinkUserWs("https://api.blink15.com", creds)
The SDK sends the auth payload automatically on connection.

State Changed Format

Delivered on connect (auth snapshot) and after every user-affecting mutation:
{
  "type": "state_changed",
  "usdc_balance": "125320000",
  "available_usdc": "115320000",
  "positions": [
    {"token_id": "abc123...", "balance": "10000000", "avg_entry_price": "0.51"}
  ],
  "open_orders": [
    {"order_id": "uuid", "market_id": "uuid", "side": "buy", "price": "0.45", "size": "20000000", "size_remaining": "20000000"}
  ]
}

Notification Format

Discrete events with enriched data:
{
  "type": "notification",
  "kind": "order_fill",
  "data": {
    "trade_id": "uuid",
    "market_id": "uuid",
    "symbol": "SPYX",
    "token_type": "Up",
    "side": "buy",
    "price": "0.51",
    "quantity": "19000000",
    "usdc_amount": "9690000"
  }
}
Notification kinds: order_fill, order_cancelled, order_accepted, order_rejected.

Auto-Reconnection

All three WebSocket classes automatically reconnect on disconnection and re-subscribe to previously subscribed assets:
# This "just works" — if the connection drops, it reconnects
# and re-subscribes to all your tokens/symbols
ws = BlinkMarketWs("https://api.blink15.com")
ws.on_snapshot = on_snapshot
ws.start()
ws.subscribe([token_a, token_b])
# If connection drops, it reconnects and re-subscribes to token_a and token_b

Full Example: Live Trading Bot

from py_blink_client import (
    ClobClient, BlinkMarketWs, BlinkUserWs,
    OrderArgs, Side
)

client = ClobClient(
    host="https://api.blink15.com",
    key="0xYOUR_KEY",
)
creds = client.create_or_derive_api_creds()

# Track orderbook state
best_bid = None
best_ask = None

def on_snapshot(msg):
    global best_bid, best_ask
    if msg['bids']:
        best_bid = float(msg['bids'][0]['price'])
    if msg['asks']:
        best_ask = float(msg['asks'][0]['price'])
    print(f"Book: {best_bid} / {best_ask}")

def on_notification(msg):
    kind = msg['kind']
    data = msg['data']
    if kind == 'order_fill':
        print(f"FILLED: {data['side']} {data['quantity']} @ {data['price']}")
    elif kind == 'order_rejected':
        print(f"REJECTED: {data['reason']}")

# Start WebSockets
market_ws = BlinkMarketWs("https://api.blink15.com")
market_ws.on_snapshot = on_snapshot
market_ws.start()

user_ws = BlinkUserWs("https://api.blink15.com", creds)
user_ws.on_notification = on_notification
user_ws.start()

# Subscribe to a market
markets = client.get_markets()
market = next(m for m in markets if m.status == "Active")
market_ws.subscribe([market.yes_token_id])

# Place orders based on live data
import time
time.sleep(2)  # wait for first snapshot

if best_ask and best_ask < 0.55:
    client.create_and_post_order(OrderArgs(
        token_id=market.yes_token_id,
        side=Side.BUY,
        price=best_ask,
        size=50,
    ))
    print(f"Bought 50 @ {best_ask}")