Pular para o conteúdo principal

Streaming API

Real-time streaming endpoints for live updates.

Overview

Data Stream provides three streaming protocols:

ProtocolEndpoint PatternUse Case
gRPCgrpc-datastream.hypetech.games:50051Type-safe, built-in filters
WebSocketwss://host/ws/:gameBidirectional, low latency
SSEGET /sse/:gameServer push, auto-reconnect

Authentication

All streaming endpoints require authentication. See the Authentication Guide for details.

ProtocolAuth Method
gRPCAPI key via x-api-key metadata
WebSocketToken via Sec-WebSocket-Protocol header
SSEAPI key via X-API-Key header or ?api_key= query parameter

WebSocket

Endpoints

ws://localhost:3000/ws/:game
ws://localhost:3000/ws/type/:type
wss://datastream.hypetech.games/ws/:game
wss://datastream.hypetech.games/ws/type/:type

Connection

WebSocket requires a short-lived token obtained via REST API:

// Step 1: Get token using API key
const tokenResponse = await fetch('/api/auth/token', {
method: 'POST',
headers: { 'X-API-Key': 'sk_live_xxxxx' }
});
const { token } = await tokenResponse.json();

// Step 2: Connect with token via Sec-WebSocket-Protocol
const ws = new WebSocket('wss://datastream.hypetech.games/ws/crash', [token]);

// By type
const wsType = new WebSocket('wss://datastream.hypetech.games/ws/type/multiplier', [token]);

Message Format

Messages are JSON-encoded round objects:

{
"round_id": 512,
"game_id": 1,
"game_slug": "crash",
"game_type": "multiplier",
"finished_at": "2026-01-17T00:45:42Z",
"extras": "{\"point\": \"11.72\"}",
"timestamp": 1768621542123
}

Events

EventDescription
onopenConnection established
onmessageNew round received
oncloseConnection closed
onerrorError occurred

Example

// Get token first
async function connectWithAuth() {
const tokenRes = await fetch('/api/auth/token', {
method: 'POST',
headers: { 'X-API-Key': 'sk_live_xxxxx' }
});
const { token } = await tokenRes.json();

const ws = new WebSocket('wss://datastream.hypetech.games/ws/crash', [token]);

ws.onopen = () => {
console.log('Connected');
};

ws.onmessage = (event) => {
const round = JSON.parse(event.data);
console.log(`Round ${round.round_id}: ${round.extras}`);
};

ws.onclose = (event) => {
console.log(`Closed: ${event.code}`);
// Implement reconnection with new token
};

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

Server-Sent Events (SSE)

Endpoints

GET /sse/:game
GET /sse/type/:type

Headers

Request:

Accept: text/event-stream

Response:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

Event Types

EventDescription
initialFirst message with latest result
messageNew round result
(comment)Heartbeat (: prefix)

Event Format

event: initial
data: {"round_id":512,"game_slug":"crash",...}

: heartbeat 1705432800

event: message
data: {"round_id":513,"game_slug":"crash",...}

Example

SSE supports both header and query parameter for authentication. Use query parameter for browser's native EventSource (which doesn't support headers):

// Browser: Use query parameter (EventSource doesn't support headers)
const apiKey = 'sk_live_xxxxx';
const sse = new EventSource(`/sse/crash?api_key=${encodeURIComponent(apiKey)}`);

// Initial data
sse.addEventListener('initial', (e) => {
const round = JSON.parse(e.data);
console.log('Initial:', round);
});

// New messages
sse.addEventListener('message', (e) => {
const round = JSON.parse(e.data);
console.log('New round:', round);
});

// Connection events
sse.onopen = () => console.log('Connected');
sse.onerror = () => console.log('Reconnecting...');

curl Testing

# With header (recommended)
curl -N -H "X-API-Key: sk_live_xxxxx" "https://datastream.hypetech.games/sse/crash"

# Or with query parameter
curl -N "https://datastream.hypetech.games/sse/crash?api_key=sk_live_xxxxx"

Message Schema

All streaming protocols use the same message format:

interface Round {
round_id: number; // Unique identifier
game_id: number; // Database ID
game_slug: string; // URL-friendly name
game_type: string; // Category
finished_at: string; // ISO 8601 timestamp
extras: string; // JSON-encoded game data
timestamp: number; // Unix milliseconds
}

Extras Schema

Crash

{"point": "11.72"}

Double

{"color": "red", "number": 5}

Slot

{"reels": ["cherry", "lemon", "orange"], "multiplier": "2.00"}

Wall Street

{"trending": "up"}

Subscription Patterns

By Game

Subscribe to a specific game:

/ws/crash        → Only crash results
/sse/double → Only double results

By Type

Subscribe to all games of a type:

/ws/type/multiplier   → crash + slot results
/sse/type/color → double results

Latency Characteristics

ProtocolTypical LatencyNotes
gRPC~2msHTTP/2 streaming
WebSocket~5msTCP overhead
SSE~50msHTTP chunked

Latency Measurement

Each message includes a timestamp field (Unix ms). Calculate latency:

ws.onmessage = (event) => {
const round = JSON.parse(event.data);
const latency = Date.now() - round.timestamp;
console.log(`Latency: ${latency}ms`);
};

Connection Management

WebSocket Reconnection

class ReconnectingWebSocket {
constructor(url) {
this.url = url;
this.ws = null;
this.reconnectDelay = 1000;
this.maxDelay = 30000;
}

connect() {
this.ws = new WebSocket(this.url);

this.ws.onopen = () => {
this.reconnectDelay = 1000;
};

this.ws.onclose = () => {
this.scheduleReconnect();
};
}

scheduleReconnect() {
setTimeout(() => {
this.connect();
}, this.reconnectDelay);

// Exponential backoff
this.reconnectDelay = Math.min(
this.reconnectDelay * 2,
this.maxDelay
);
}
}

SSE (Auto-Reconnect)

SSE reconnects automatically. Just handle the error event:

sse.onerror = () => {
console.log('Connection lost, auto-reconnecting...');
// Browser handles reconnection
};

Error Handling

WebSocket Errors

CodeMeaningAction
1000Normal closeClean shutdown
1001Going awayServer restart
1006AbnormalNetwork issue
1011Server errorRetry with backoff

SSE Errors

SSE auto-reconnects on network errors. Handle via:

sse.onerror = (event) => {
if (event.target.readyState === EventSource.CLOSED) {
console.log('Connection closed');
} else {
console.log('Reconnecting...');
}
};

Best Practices

1. Choose the Right Protocol

// gRPC for backend services with type safety
if (needsTypeSafety && !isBrowser) {
return new GrpcClient('grpc-datastream.hypetech.games:50051');
}

// WebSocket for bidirectional
if (needsBidirectional) {
return new WebSocket('wss://host/ws/crash');
}

// SSE for simple server push
if (needsOnlyServerPush) {
return new EventSource('/sse/crash?api_key=...');
}

2. Handle Reconnection

Always implement reconnection for WebSocket:

ws.onclose = () => {
setTimeout(() => connect(), 3000);
};

3. Parse Extras Safely

function parseExtras(extras) {
try {
return JSON.parse(extras);
} catch (e) {
console.error('Invalid extras:', extras);
return {};
}
}

4. Monitor Latency

function handleMessage(round) {
const latency = Date.now() - round.timestamp;
if (latency > 100) {
console.warn(`High latency: ${latency}ms`);
}
}

5. Graceful Degradation

async function connect() {
// Try WebSocket first for lower latency
try {
return await connectWebSocket();
} catch (e) {}

// Fallback to SSE (works everywhere)
return connectSSE();
}