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.
| Approach | Latency | Bandwidth | Use Case |
|---|---|---|---|
| REST polling | 30-60s | High (full payload each poll) | Casual browsing, dashboards |
| SSE streaming | < 1s | Low (only deltas) | Live betting, alerts, automated systems |
| WebSocket | < 1s | Low (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
| Tier | Streaming Access |
|---|---|
| Free | Not 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 |
| Enterprise | Included (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
| Event | Description |
|---|---|
connected | Stream established, returns stream ID, active filters, and channels |
snapshot / opportunities_snapshot | Data dump of current odds and/or opportunities |
snapshot:complete | All initial data has been sent |
odds:update | Odds changed for a sportsbook |
odds:removed | Odds removed by a sportsbook (WebSocket only) |
ev:detected | New +EV opportunity found |
ev:expired | +EV opportunity no longer available |
arb:detected | New arbitrage opportunity found |
arb:expired | Arbitrage opportunity no longer available |
middles:detected | New middle opportunity found |
middles:expired | Middle opportunity no longer available |
low_hold:detected | New low-hold opportunity found |
low_hold:expired | Low-hold opportunity no longer available |
heartbeat | Keep-alive sent every 30 seconds |
error | Recoverable error (connection stays open) |
SSE vs WebSocket
| Feature | SSE | WebSocket |
|---|---|---|
| Protocol | HTTP (one-way) | ws:// / wss:// (bidirectional) |
| Endpoint | GET /api/v1/stream | wss://ws.sharpapi.io |
| Channel subscriptions | Set once via query params | Update anytime via subscribe message |
| Filter updates | Reconnect with new params | Send subscribe message |
| Reconnection | Automatic (Last-Event-ID) | Manual (with backoff) |
| Browser support | Native EventSource | Native WebSocket |
| Best for | Simple consumers, SSR | Dynamic filters, two-way comms |
Both protocols deliver the same event types and data payloads.
Full API Reference
- SSE Stream API Reference — Query parameters, event payloads, reconnection
- WebSocket API Reference — Connection lifecycle, message protocol, close codes
- WebSocket Streaming Guide — Quick start, reconnection patterns, best practices
Last updated on