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?Permalink for this section

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íciosPermalink for this section

  • 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 FuncionaPermalink for this section

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.

RequisitosPermalink for this section

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ápidoPermalink for this section

// 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.jsPermalink for this section

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`); });

PythonPermalink for this section

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 EventosPermalink for this section

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, timestamp). 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 WebSocketPermalink for this section

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 APIPermalink for this section

SDKs com Suporte a StreamingPermalink for this section

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

Projetos de ExemploPermalink for this section

Last updated on