Skip to Content
StreamingOverview

Streaming Overview

Real-time odds and opportunity updates via SSE or WebSocket.

SharpAPI offers two streaming protocols: SSE (Server-Sent Events) over HTTP and WebSocket for bidirectional communication. Both deliver the same real-time data — choose based on your use case.

Why Streaming?

REST polling introduces a 30-60 second delay between odds changes and your application seeing them. SSE streaming delivers updates in sub-second latency directly to your application as they happen.

ApproachLatencyBandwidthUse Case
REST polling30-60sHigh (full payload each poll)Casual browsing, dashboards
SSE streaming< 1sLow (only deltas)Live betting, alerts, automated systems
WebSocket< 1sLow (only deltas)Bidirectional comms, dynamic filter updates

Key Benefits

  • Sub-second latency — Odds updates arrive as soon as they are detected
  • Lower bandwidth — Only changed data is sent, not full snapshots on every poll
  • Two protocols — SSE for simplicity, WebSocket for bidirectional control
  • Automatic reconnection — SSE reconnects natively; WebSocket with simple retry logic

How SSE Works

Server-Sent Events is a W3C standard for server-to-client streaming over HTTP:

Client Server | | |--- GET /api/v1/stream ------->| | | |<-- event: connected ----------| Stream established |<-- event: snapshot -----------| Full current state |<-- event: odds:update --------| Delta update |<-- event: odds:update --------| Delta update |<-- event: ev:detected --------| Opportunity found |<-- event: heartbeat ----------| Keep-alive (every 30s) | ... |

SSE automatically reconnects on disconnect. The server uses Last-Event-ID to replay any events you missed.

Requirements

TierStreaming Access
FreeNot available
Hobby + Add-on ($99/mo)10 concurrent streams
Pro + Add-on ($99/mo)10 concurrent streams
Sharp + Add-on ($99/mo)10 concurrent streams
EnterpriseIncluded (custom limits)

Quick Start

Browser

const eventSource = new EventSource( 'https://api.sharpapi.io/api/v1/stream?channel=all&league=nba&api_key=YOUR_KEY' ); eventSource.addEventListener('connected', (e) => { const { stream_id } = JSON.parse(e.data); console.log('Stream connected:', stream_id); }); eventSource.addEventListener('snapshot', (e) => { const { odds } = JSON.parse(e.data); console.log('Initial snapshot:', odds.length, 'odds'); }); eventSource.addEventListener('odds:update', (e) => { const update = JSON.parse(e.data); console.log('Update from:', update.sportsbook); }); eventSource.addEventListener('ev:detected', (e) => { const opp = JSON.parse(e.data); console.log(`+EV: ${opp.selection} at ${opp.ev_percent}% EV`); }); eventSource.addEventListener('heartbeat', () => { console.log('Connection alive'); }); eventSource.onerror = () => { console.log('Connection lost, auto-reconnecting...'); };

Node.js

import EventSource from 'eventsource'; const es = new EventSource( 'https://api.sharpapi.io/api/v1/stream?channel=odds&league=nba', { headers: { 'X-API-Key': 'YOUR_KEY' } } ); es.addEventListener('snapshot', (e) => { const { odds } = JSON.parse(e.data); console.log(`Received ${odds.length} initial odds`); }); es.addEventListener('odds:update', (e) => { const update = JSON.parse(e.data); console.log(`${update.sportsbook}: ${update.markets.length} markets updated`); });

Python

import sseclient import requests import json url = 'https://api.sharpapi.io/api/v1/stream' params = {'channel': 'all', 'league': 'nba'} headers = {'X-API-Key': 'YOUR_KEY'} response = requests.get(url, params=params, headers=headers, stream=True) client = sseclient.SSEClient(response) for event in client.events(): data = json.loads(event.data) if event.data else {} if event.event == 'connected': print(f"Stream {data['stream_id']} connected") elif event.event == 'snapshot': print(f"Snapshot: {len(data.get('odds', []))} odds") elif event.event == 'odds:update': print(f"{data['sportsbook']}: odds updated") elif event.event == 'ev:detected': print(f"+EV: {data['selection']} at {data['ev_percent']}%")

Event Types

EventDescription
connectedStream established, returns stream ID, active filters, and channels
snapshot / opportunities_snapshotData dump of current odds and/or opportunities
snapshot:completeAll initial data has been sent
odds:updateOdds changed for a sportsbook
odds:removedOdds removed by a sportsbook (WebSocket only)
ev:detectedNew +EV opportunity found
ev:expired+EV opportunity no longer available
arb:detectedNew arbitrage opportunity found
arb:expiredArbitrage opportunity no longer available
middles:detectedNew middle opportunity found
middles:expiredMiddle opportunity no longer available
low_hold:detectedNew low-hold opportunity found
low_hold:expiredLow-hold opportunity no longer available
heartbeatKeep-alive sent every 30 seconds
errorRecoverable error (connection stays open)

SSE vs WebSocket

FeatureSSEWebSocket
ProtocolHTTP (one-way)ws:// / wss:// (bidirectional)
EndpointGET /api/v1/streamwss://ws.sharpapi.io
Channel subscriptionsSet once via query paramsUpdate anytime via subscribe message
Filter updatesReconnect with new paramsSend subscribe message
ReconnectionAutomatic (Last-Event-ID)Manual (with backoff)
Browser supportNative EventSourceNative WebSocket
Best forSimple consumers, SSRDynamic filters, two-way comms

Both protocols deliver the same event types and data payloads.

Full API Reference

Last updated on