Skip to Content
StreamingVisão Geral

Visão Geral do Streaming

Atualizações de odds e oportunidades em tempo real via SSE ou WebSocket.

A SharpAPI oferece dois protocolos de streaming: SSE (Server-Sent Events) sobre HTTP e WebSocket para comunicação bidirecional. Ambos entregam os mesmos dados em tempo real — escolha conforme seu caso de uso.

Por que Streaming?

O polling REST introduz um atraso de 30 a 60 segundos entre as alterações nas odds e o momento em que sua aplicação as percebe. O streaming SSE entrega atualizações com latência abaixo de um segundo diretamente para sua aplicação assim que elas acontecem.

AbordagemLatênciaLargura de bandaCaso de uso
Polling REST30-60sAlta (payload completo a cada poll)Navegação casual, dashboards
Streaming SSE< 1sBaixa (apenas deltas)Apostas ao vivo, alertas, sistemas automatizados
WebSocket< 1sBaixa (apenas deltas)Comunicação bidirecional, atualizações dinâmicas de filtros

Principais Benefícios

  • Latência abaixo de um segundo — As atualizações de odds chegam assim que são detectadas
  • Menor largura de banda — Apenas dados alterados são enviados, não snapshots completos a cada poll
  • Dois protocolos — SSE para simplicidade, WebSocket para controle bidirecional
  • Reconexão automática — SSE reconecta nativamente; WebSocket com lógica simples de retry

Como o SSE Funciona

Server-Sent Events é um padrão W3C para streaming servidor-para-cliente sobre 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) | ... |

O SSE reconecta automaticamente em caso de desconexão. O servidor usa Last-Event-ID para reproduzir quaisquer eventos que você tenha perdido.

Requisitos

PlanoAcesso ao Streaming
FreeNão disponível
Hobby + Add-on ($99/mês)1 stream (substituição newer-wins)
Pro + Add-on ($99/mês)1 stream (substituição newer-wins)
Sharp + Add-on ($99/mês)1 stream (substituição newer-wins)
EnterpriseIncluído (limites personalizados)

Substituição newer-wins: abrir um segundo stream a partir da mesma API key encerra o primeiro. Uma conexão bem gerenciada é suficiente para a maioria dos casos de uso — veja Padrões de Conexão Única para técnicas. Implantações de fleet que precisem de múltiplos streams simultâneos podem solicitar um limite maior através do time de vendas.

Início Rápido

// Local odds map — snapshot fills it, deltas merge into it const oddsMap = new Map(); 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, reconnected } = JSON.parse(e.data); if (reconnected) oddsMap.clear(); console.log('Stream connected:', stream_id); }); eventSource.addEventListener('snapshot', (e) => { const { odds } = JSON.parse(e.data); for (const odd of odds) oddsMap.set(odd.id, odd); console.log('Snapshot chunk:', odds.length, 'odds'); }); eventSource.addEventListener('odds:update', (e) => { const { odds, book } = JSON.parse(e.data); // Delta only contains dynamic fields — merge into local state by ID for (const delta of odds) { const full = oddsMap.get(delta.id); if (full) Object.assign(full, delta); } console.log(`${book}: ${odds.length} odds updated`); }); eventSource.addEventListener('ev:detected', (e) => { const opps = JSON.parse(e.data); opps.forEach(opp => console.log(`+EV: ${opp.selection} at ${opp.ev_percentage}% EV`)); }); eventSource.addEventListener('heartbeat', () => { console.log('Connection alive'); }); eventSource.onerror = () => { console.log('Connection lost, auto-reconnecting...'); };

Node.js

import EventSource from 'eventsource'; const oddsMap = new Map(); 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); for (const odd of odds) oddsMap.set(odd.id, odd); console.log(`Received ${odds.length} initial odds`); }); es.addEventListener('odds:update', (e) => { const { odds, book } = JSON.parse(e.data); // Merge compact deltas into local state for (const delta of odds) { const full = oddsMap.get(delta.id); if (full) Object.assign(full, delta); } console.log(`${book}: ${odds.length} odds 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'} odds_map: dict[str, dict] = {} 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': if data.get('reconnected'): odds_map.clear() print(f"Stream {data['stream_id']} connected") elif event.event == 'snapshot': for odd in data.get('odds', []): odds_map[odd['id']] = odd print(f"Snapshot: {data['count']} odds") elif event.event == 'odds:update': # Delta only has dynamic fields — merge by ID for delta in data.get('odds', []): existing = odds_map.get(delta['id']) if existing: existing.update(delta) print(f"{data['book']}: {data['count']} odds updated") elif event.event == 'ev:detected': for opp in data: print(f"+EV: {opp['selection']} at {opp['ev_percentage']}%")

Tipos de Eventos

EventoDescrição
connectedStream estabelecido, retorna ID do stream, filtros ativos e canais
snapshot / opportunities_snapshotDump completo de dados de odds/oportunidades (todos os campos)
snapshot:completeTodos os dados iniciais foram enviados
odds:updateDelta compacto — apenas campos dinâmicos (id, odds_american, odds_decimal, odds_probability, line, is_live, odds_changed_at). Faça merge por id no estado do snapshot.
odds:removedOdds removidas por uma sportsbook
ev:detectedNova oportunidade +EV encontrada
ev:expiredOportunidade +EV não está mais disponível
arb:detectedNova oportunidade de arbitragem encontrada
arb:expiredOportunidade de arbitragem não está mais disponível
middles:detectedNova oportunidade de middle encontrada (veja Resumo de Middles para estatísticas agregadas)
middles:expiredOportunidade de middle não está mais disponível
low_hold:detectedNova oportunidade de low-hold encontrada
low_hold:expiredOportunidade de low-hold não está mais disponível
heartbeatKeep-alive enviado a cada 30 segundos
errorErro recuperável (a conexão permanece aberta)

SSE vs WebSocket

RecursoSSEWebSocket
ProtocoloHTTP (unidirecional)ws:// / wss:// (bidirecional)
EndpointGET /api/v1/streamwss://ws.sharpapi.io
Inscrições em canaisDefinidas uma vez via parâmetros de queryAtualizadas a qualquer momento via mensagem subscribe
Atualizações de filtrosReconectar com novos parâmetrosEnviar mensagem subscribe
ReconexãoAutomática (Last-Event-ID)Manual (com backoff)
Suporte do navegadorEventSource nativoWebSocket nativo
Melhor paraConsumidores simples, SSRFiltros dinâmicos, comunicação bidirecional

Ambos os protocolos entregam os mesmos tipos de eventos e payloads de dados.

Referência Completa da API

SDKs com Suporte a Streaming

  • TypeScript SDK — Cliente SSE integrado com handlers de eventos type-safe
  • Python SDK — Padrões de streaming baseados em handlers e iteradores

Projetos de Exemplo

Last updated on