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 platformnewTokens- Newly created tokenspriceUpdates- 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
Implement Reconnection: Handle connection drops gracefully
Authenticate Early: Send authentication immediately after connecting
Manage Subscriptions: Track subscriptions for reconnection
Handle Errors: Monitor error events and log them
Rate Limiting: Respect message rate limits
Heartbeat: Implement ping/pong for connection health
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
AUTHENTICATION_FAILED
Invalid API key
SUBSCRIPTION_FAILED
Invalid subscription key
RATE_LIMIT_EXCEEDED
Too many messages
CONNECTION_LIMIT
Too many concurrent connections
Next Steps
View Lightning API for trading endpoints
Check Examples for complete implementations
Learn about Error Handling
Last updated