WebSocket API

Stream real-time trading data, price feeds, and market events via high-performance WebSocket connections.

Overview

WebSocket URL: wss://turnpike.dev/api/data

Connection Limits:

  • Standard: 5 concurrent connections, 50 messages/second

  • Premium: 20 concurrent connections, 200 messages/second

Connecting

JavaScript/TypeScript

const ws = new WebSocket('wss://turnpike.dev/api/data');

ws.onopen = () => {
  console.log('Connected to Turnpike WebSocket');

  // Subscribe to trades
  ws.send(JSON.stringify({
    method: 'subscribe',
    keys: ['trades']
  }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
};

ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};

ws.onclose = (event) => {
  console.log('Connection closed:', event.code, event.reason);
};

Python

import websocket
import json

def on_message(ws, message):
    data = json.loads(message)
    print('Received:', data)

def on_error(ws, error):
    print('Error:', error)

def on_close(ws, close_status_code, close_msg):
    print('Connection closed')

def on_open(ws):
    print('Connected to Turnpike WebSocket')

    # Subscribe to trades
    ws.send(json.dumps({
        'method': 'subscribe',
        'keys': ['trades']
    }))

ws = websocket.WebSocketApp(
    'wss://turnpike.dev/api/data',
    on_open=on_open,
    on_message=on_message,
    on_error=on_error,
    on_close=on_close
)

ws.run_forever()

Authentication

For WebSocket connections, include your API key in the initial connection message:

ws.onopen = () => {
  // Authenticate
  ws.send(JSON.stringify({
    method: 'authenticate',
    apiKey: 'YOUR_API_KEY'
  }));
};

You'll receive a confirmation:

{
  "type": "authenticated",
  "userId": "user_123",
  "plan": "premium"
}

Subscription Methods

Subscribe to Channels

ws.send(JSON.stringify({
  method: 'subscribe',
  keys: ['trades', 'newTokens']
}));

Available Channels:

  • trades - All token trades across the platform

  • newTokens - Newly created tokens

  • priceUpdates - Real-time price updates

  • {MINT_ADDRESS} - Events for a specific token

Success Response:

{
  "type": "subscribed",
  "keys": ["trades", "newTokens"],
  "timestamp": 1697234567890
}

Subscribe to Specific Token

ws.send(JSON.stringify({
  method: 'subscribe',
  keys: ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v']
}));

Unsubscribe

ws.send(JSON.stringify({
  method: 'unsubscribe',
  keys: ['trades']
}));

Event Types

Trade Event

Emitted when a token trade occurs.

{
  "type": "trade",
  "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "signature": "5j7sK8K2YaFvS2hE3YgY4zRtV3pGq1Y7zxP8c9X3Qa6",
  "trader": "7BgBvyjrZX8YTqjkKrfbSx9X8QP4NDaP1hj4VKMjqA5s",
  "amount": 0.01,
  "tokensTraded": 1000000,
  "price": 0.00001,
  "marketCap": 1250000,
  "timestamp": 1697234567890,
  "side": "buy",
  "slippage": 2.3,
  "priorityFee": 0.0001
}

New Token Event

Emitted when a new token is created.

{
  "type": "newToken",
  "mint": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
  "symbol": "NEWCOIN",
  "name": "New Coin",
  "creator": "7BgBvyjrZX8YTqjkKrfbSx9X8QP4NDaP1hj4VKMjqA5s",
  "initialLiquidity": 5.0,
  "marketCap": 50000,
  "timestamp": 1697234567890,
  "metadata": {
    "description": "A revolutionary new token",
    "image": "https://...",
    "website": "https://...",
    "twitter": "@newcoin"
  }
}

Price Update Event

Emitted when token price changes significantly.

{
  "type": "priceUpdate",
  "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "price": 0.00001,
  "priceChange": 5.2,
  "priceChange24h": -2.1,
  "marketCap": 1250000,
  "volume24h": 50000,
  "liquidityUsd": 125000,
  "timestamp": 1697234567890
}

Error Event

{
  "type": "error",
  "code": "SUBSCRIPTION_FAILED",
  "message": "Invalid subscription key",
  "timestamp": 1697234567890
}

Advanced Usage

Reconnection Logic

class TurnpikeWebSocket {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.ws = null;
    this.reconnectDelay = 1000;
    this.maxReconnectDelay = 30000;
    this.subscriptions = new Set();
  }

  connect() {
    this.ws = new WebSocket('wss://turnpike.dev/api/data');

    this.ws.onopen = () => {
      console.log('Connected');
      this.reconnectDelay = 1000;

      // Authenticate
      this.send({
        method: 'authenticate',
        apiKey: this.apiKey
      });

      // Resubscribe to previous subscriptions
      if (this.subscriptions.size > 0) {
        this.send({
          method: 'subscribe',
          keys: Array.from(this.subscriptions)
        });
      }
    };

    this.ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      this.handleMessage(data);
    };

    this.ws.onerror = (error) => {
      console.error('WebSocket error:', error);
    };

    this.ws.onclose = () => {
      console.log('Connection closed, reconnecting...');
      setTimeout(() => {
        this.reconnectDelay = Math.min(
          this.reconnectDelay * 2,
          this.maxReconnectDelay
        );
        this.connect();
      }, this.reconnectDelay);
    };
  }

  subscribe(keys) {
    keys.forEach(key => this.subscriptions.add(key));

    if (this.ws?.readyState === WebSocket.OPEN) {
      this.send({
        method: 'subscribe',
        keys
      });
    }
  }

  unsubscribe(keys) {
    keys.forEach(key => this.subscriptions.delete(key));

    if (this.ws?.readyState === WebSocket.OPEN) {
      this.send({
        method: 'unsubscribe',
        keys
      });
    }
  }

  send(data) {
    if (this.ws?.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(data));
    }
  }

  handleMessage(data) {
    switch (data.type) {
      case 'trade':
        this.onTrade(data);
        break;
      case 'newToken':
        this.onNewToken(data);
        break;
      case 'priceUpdate':
        this.onPriceUpdate(data);
        break;
      case 'error':
        this.onError(data);
        break;
    }
  }

  onTrade(data) {
    // Override this method
    console.log('Trade:', data);
  }

  onNewToken(data) {
    // Override this method
    console.log('New token:', data);
  }

  onPriceUpdate(data) {
    // Override this method
    console.log('Price update:', data);
  }

  onError(data) {
    // Override this method
    console.error('Error:', data);
  }

  disconnect() {
    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
  }
}

// Usage
const ws = new TurnpikeWebSocket('YOUR_API_KEY');
ws.connect();
ws.subscribe(['trades', 'newTokens']);

ws.onTrade = (data) => {
  console.log('Trade detected:', data);
};

React Hook Example

import { useEffect, useRef, useState } from 'react';

interface Trade {
  type: 'trade';
  mint: string;
  signature: string;
  trader: string;
  amount: number;
  tokensTraded: number;
  price: number;
  marketCap: number;
  timestamp: number;
  side: 'buy' | 'sell';
}

export function useTurnpikeWebSocket(apiKey: string) {
  const ws = useRef<WebSocket | null>(null);
  const [trades, setTrades] = useState<Trade[]>([]);
  const [connected, setConnected] = useState(false);

  useEffect(() => {
    ws.current = new WebSocket('wss://turnpike.dev/api/data');

    ws.current.onopen = () => {
      setConnected(true);

      ws.current?.send(JSON.stringify({
        method: 'authenticate',
        apiKey
      }));

      ws.current?.send(JSON.stringify({
        method: 'subscribe',
        keys: ['trades']
      }));
    };

    ws.current.onmessage = (event) => {
      const data = JSON.parse(event.data);

      if (data.type === 'trade') {
        setTrades(prev => [data, ...prev].slice(0, 100));
      }
    };

    ws.current.onclose = () => {
      setConnected(false);
    };

    return () => {
      ws.current?.close();
    };
  }, [apiKey]);

  const subscribe = (keys: string[]) => {
    if (ws.current?.readyState === WebSocket.OPEN) {
      ws.current.send(JSON.stringify({
        method: 'subscribe',
        keys
      }));
    }
  };

  return { trades, connected, subscribe };
}

Best Practices

  1. Implement Reconnection: Handle connection drops gracefully

  2. Authenticate Early: Send authentication immediately after connecting

  3. Manage Subscriptions: Track subscriptions for reconnection

  4. Handle Errors: Monitor error events and log them

  5. Rate Limiting: Respect message rate limits

  6. Heartbeat: Implement ping/pong for connection health

  7. Clean Disconnection: Close connections properly when done

Heartbeat/Ping-Pong

Keep the connection alive with periodic pings:

let pingInterval;

ws.onopen = () => {
  // Send ping every 30 seconds
  pingInterval = setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify({ method: 'ping' }));
    }
  }, 30000);
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (data.type === 'pong') {
    console.log('Pong received');
  }
};

ws.onclose = () => {
  clearInterval(pingInterval);
};

Error Codes

Code
Description

AUTHENTICATION_FAILED

Invalid API key

SUBSCRIPTION_FAILED

Invalid subscription key

RATE_LIMIT_EXCEEDED

Too many messages

CONNECTION_LIMIT

Too many concurrent connections

Next Steps

Last updated