WebSocket Market Data

Real-time market data streaming over WebSockets. Stream live quotes for selected symbols using symbol-level subscriptions. Available to PRO subscribers.

Overview

WebSocket-based real-time market data streaming with:

  • Symbol-level subscriptions for efficient bandwidth usage
  • Low-latency quote updates
  • Automatic reconnection support
  • Premium entitlement required

Note: This feature requires a PRO subscription. Non-PRO users will receive an ENTITLEMENT_REQUIRED error.

Connection Endpoint

Connect to our WebSocket server for real-time market data streaming.

WebSocket URL

wss://api.paperinvest.io/v1/ws/market

Connection Example

Connection

WS
import { io } from 'socket.io-client';


// Connect to the namespace via URL; keep Socket.IO path default '/socket.io'
const socket = io('https://api.paperinvest.io/v1/ws/market', {
  path: '/socket.io',
  transports: ['websocket'],
  auth: { token: `Bearer ${YOUR_JWT}` }
});


// Connection event handlers
socket.on('connect', () => {
  console.log('WebSocket connected');
});


socket.on('disconnect', (reason) => {
  console.log('WebSocket disconnected:', reason);
});

Client Messages

Messages sent from client to server for managing subscriptions.

Subscribe Message

Subscribe to real-time quotes for specific symbols:

Subscribe Message

JSON
{
  "type": "subscribe",
  "symbols": ["AAPL", "MSFT", "GOOGL"],
  "channels": ["quote"]
}

Unsubscribe Message

Remove symbols from your active subscriptions:

Unsubscribe Message

JSON
{
  "type": "unsubscribe",
  "symbols": ["AAPL"]
}

MessageBodyDescription
subscribe
{ symbols: string[], channels?: string[] }
Add symbols to subscription list
unsubscribe
{ symbols: string[] }
Remove symbols from subscription list

Note: channels parameter is reserved for future extensions (e.g., trade, book). Currently only quote channel is supported.

Server Events

Events emitted from the server to connected clients.

EventPayloadDescription
connected
Connection infoSuccessful WebSocket connection established
subscribed
Subscription confirmationSymbols successfully added to subscription
unsubscribed
Unsubscribe confirmationSymbols successfully removed from subscription
quote
Quote dataReal-time quote update for subscribed symbol
error
Error detailsError message including entitlement failures

Event Payloads

Event Payloads

JSON
// Connected Event
{
  "message": "Connected to market data stream",
  "clientId": "ws_1715743859000",
  "plan": "pro",
  "timestamp": 1715743859000
}


// Quote Event
{
  "symbol": "AAPL",
  "bid": 175.20,
  "ask": 175.30,
  "bidSize": 300,
  "askSize": 200,
  "timestamp": 1715743859000
}


// Error Event
{
  "code": "ENTITLEMENT_REQUIRED",
  "message": "PRO subscription required for market data streaming"
}

Implementation Examples

Complete examples for implementing WebSocket market data streaming.

Full Implementation

WS
import { io } from 'socket.io-client';


class MarketDataStream {
  constructor(token) {
    this.token = token;
    this.socket = null;
    this.subscriptions = new Set();
  }


  connect() {
    this.socket = io('https://api.paperinvest.io', {
      path: '/v1/ws/market',
      transports: ['websocket'],
      auth: { token: `Bearer ${this.token}` }
    });


    this.socket.on('connected', (info) => {
      console.log('Connected to market data:', info);
      // Resubscribe to any existing symbols after reconnect
      if (this.subscriptions.size > 0) {
        this.subscribe(Array.from(this.subscriptions));
      }
    });


    this.socket.on('subscribed', (data) => {
      console.log('Subscribed to:', data.symbols);
      data.symbols.forEach(s => this.subscriptions.add(s));
    });


    this.socket.on('quote', (quote) => {
      this.handleQuote(quote);
    });


    this.socket.on('error', (error) => {
      console.error('WebSocket error:', error);
      if (error.code === 'ENTITLEMENT_REQUIRED') {
        console.error('PRO subscription required');
      }
    });


    this.socket.on('disconnect', (reason) => {
      console.log('Disconnected:', reason);
      // Socket.IO will automatically reconnect
    });
  }


  subscribe(symbols) {
    this.socket.emit('subscribe', {
      symbols: symbols,
      channels: ['quote']
    });
  }


  unsubscribe(symbols) {
    this.socket.emit('unsubscribe', { symbols });
    symbols.forEach(s => this.subscriptions.delete(s));
  }


  handleQuote(quote) {
    // Process real-time quote update
    console.log(`${quote.symbol}: Bid ${quote.bid} @ ${quote.bidSize} - Ask ${quote.ask} @ ${quote.askSize}`);
  }


  disconnect() {
    if (this.socket) {
      this.socket.disconnect();
    }
  }
}


// Usage
const stream = new MarketDataStream('YOUR_JWT_TOKEN');
stream.connect();
stream.subscribe(['AAPL', 'MSFT', 'GOOGL']);


// Later...
// stream.unsubscribe(['AAPL']);
// stream.disconnect();

Requirements

Requirements

Auth
Authorization: Bearer <JWT>
Plan: PRO subscription required

Best Practices

Connection Management

  • Single Connection: Use one WebSocket connection per application and manage subscriptions dynamically
  • Reconnection: Implement automatic reconnection with exponential backoff
  • Subscription State: Maintain local subscription state for reconnection recovery

Performance Optimization

  • Batch Operations: Group subscribe/unsubscribe operations when possible
  • Symbol Validation: Validate symbols client-side before subscribing
  • Throttling: Implement client-side throttling for subscription changes

Error Handling

  • Graceful Degradation: Handle entitlement and rate limit errors gracefully
  • Logging: Log connection events and errors for debugging
  • Heartbeat: Monitor connection health with periodic ping/pong