Skip to Content
Referência da APIEstado do Jogo ao Vivo

Estado de Jogo ao Vivo

Estado agregado de jogos ao vivo — placares, períodos, cronômetros, posse de bola e dados situacionais específicos do esporte — mesclados entre sportsbooks em uma única visão autoritativa por evento. Uma linha por partida ao vivo, selecionada por consenso entre os books que a cobrem. Uma partida que acabou de terminar também permanece aqui por uma janela curta como linha terminal — veja Eventos finalizados.

GET /api/v1/gamestate GET /api/v1/gamestate/{sport}

AutenticaçãoPermalink for this section

Requer API key. Disponível no add-on Game State (US$ 79/mês) ou no tier Enterprise. Keys sem nenhum dos dois recebem 403 tier_restricted com addon: "game_state" no corpo do erro. Adicione o add-on pela página de billing  em qualquer plano pago (Hobby / Pro / Sharp); keys Enterprise já o incluem.

O estado de jogo ao vivo também é transmitido pelo canal gamestate via SSE e WebSocket — veja Streaming abaixo. (O acesso ao streaming requer o add-on WebSocket ou Enterprise, além do requisito de Game State acima.)

Parâmetros de PathPermalink for this section

ParâmetroTipoDescrição
sportstring(opcional) Esporte único a ser retornado. Corresponde a um esporte conhecido do Atlas (soccer, tennis, esports, basketball, table_tennis, baseball, hockey, cricket, volleyball, handball, football, olympics, darts, boxing, rugby_league, mma, aussie_rules, snooker, rugby_union, golf, floorball, water_polo, lacrosse, futsal, other). Não diferencia maiúsculas/minúsculas. Um esporte desconhecido retorna um objeto data vazio — e um esporte suportado sem nada ao vivo no momento também; veja a nota abaixo.

Um objeto data vazio não significa que o esporte não é suportado. O game state é mesclado por esporte em uma chave gamestate:{sport} com TTL de 60 segundos (GAMESTATE_TTL, deliberadamente o dobro da janela livestate de 30 segundos); sem nada ao vivo a chave expira e a resposta é {"data":{}}, idêntica à de um esporte não coberto. Vários dos esportes acima são sazonais.

Use GET /api/v1/sports para ver event_count e live_count por esporte. other é o bucket de reserva para esportes que o Atlas não mapeou.

Sem o parâmetro de path, retorna todos os esportes com eventos ao vivo.

Filtros de consultaPermalink for this section

Ambos valem para /api/v1/gamestate e /api/v1/gamestate/{sport}. Os valores não diferenciam maiúsculas e são aparados. Se você omitir os dois, recebe o conjunto padrão: tudo o que está ao vivo, mais as linhas finalizadas que ainda estão dentro da janela de retenção.

ParâmetroAceitoDescrição
statusfinalRetorna apenas as linhas finalizadas retidas — o espelho de /events?status=final. Qualquer outro valor é um 400 validation_error (veja abaixo). Não existe o valor live: linhas ao vivo são o conjunto padrão, e ?is_live=true pede só elas.
is_livetrue, falsetrue retorna apenas linhas ao vivo, o que exclui todas as linhas finalizadas. false retorna apenas linhas não ao vivo, que hoje são as linhas finalizadas retidas. Qualquer outro valor — incluindo 1 e 0 — é um 400 validation_error.

Um valor não reconhecido é rejeitado, não ignorado. Tanto ?status=zzz quanto ?is_live=1 retornam 400 com um corpo validation_error que nomeia o conjunto aceito, em vez de devolver silenciosamente as linhas sem filtro ou as do lado errado.

{ "error": { "code": "validation_error", "message": "is_live must be one of: true, false", "details": { "parameter": "is_live", "accepted": ["true", "false"] } } }

Antes ?is_live=1 era lido como false e devolvia exatamente as linhas que quem chamava queria excluir; agora é um 400. Se você envia 1 / 0, mude para true / false.

Envelope da RespostaPermalink for this section

{ "data": { "<sport>": { "<event_id>": { ...event state... } } }, "updated_at": "2026-04-23T23:55:01.234Z" }

Cada estado de evento é indexado pelo seu event_id canônico dentro do bucket do esporte. updated_at é o horário do servidor quando esta resposta foi construída — use-o para avaliar a atualidade se estiver fazendo polling.

Campos do Estado do EventoPermalink for this section

Todos os campos são opcionais, exceto onde indicado. A presença varia por esporte — eventos de tênis carregam sets_home / server; eventos de hóquei carregam power_play; eventos de futebol carregam corners_* / yellow_cards_*; etc.

Sempre presentesPermalink for this section

CampoTipoNotas
home_teamstringNome normalizado do time da casa
away_teamstringNome normalizado do time visitante
sportstringBucket de esporte (baseball, soccer, …)
leaguestringID da liga no Atlas (ex. mlb, england_-_premier_league)
home_scoreintegerPlacar atual da casa na unidade natural do esporte (corridas, pontos, gols, sets — tênis usa pontos somados de sets)
away_scoreintegerPlacar atual do visitante
is_livebooleantrue em um evento ao vivo. false em uma linha finalizada retida — veja Eventos finalizados
primary_bookstringO book de onde os placares mesclados foram selecionados. Respeita o consenso — books de maior qualidade vencem empates
book_countintegerNúmero de sportsbooks que contribuíram com estado ao vivo para este evento no momento da mesclagem

“Sempre presentes” significa sempre presentes em uma linha ao vivo. Uma linha finalizada retida é montada a partir do registro de conclusão, não de uma mesclagem ao vivo, então não carrega primary_book nem book_count, e nenhum game_period / game_clock. Os campos de placar também dependem do esporte: esportes por sets carregam sets_home / sets_away em vez de home_score / away_score. Verifique status === "final" antes de ler qualquer um desses campos. A forma terminal completa está em Eventos finalizados.

Temporais (maioria dos esportes em equipe)Permalink for this section

CampoTipoExemplo
game_periodstring"T5" (MLB topo do 5º), "Q3" (NBA Q3), "2H" (futebol 2º tempo), "P2" (NHL), "S2" (tênis 2º set), "FT" (tempo final)
game_clockstring"49:06" para esportes com contagem progressiva (futebol), "5:42" para esportes com contagem regressiva (basquete, hóquei)

SituacionaisPermalink for this section

CampoTipoNotas
possession"home" | "away"Qual time tem a posse (esportes em equipe) ou está sacando (tênis)
server"home" | "away"Apenas tênis — sacador atual
last_playstringDescrição da última jogada específica do esporte, quando disponível
is_timeoutbooleantrue durante um timeout

Específicos do esportePermalink for this section

CampoEsporteTipo
fouls_home, fouls_awaybasketball, soccerinteger
corners_home, corners_awaysoccerinteger
yellow_cards_home, yellow_cards_awaysoccerinteger
red_cards_home, red_cards_awaysoccerinteger
power_playhockey"home" | "away"
sets_home, sets_awaytennisinteger (sets vencidos)
hits_home, hits_awaybaseballinteger
home_pitcher, away_pitcherbaseballstring — nome de exibição do arremessador titular
wickets_home, wickets_awaycricketinteger
overscricketfloat
batting_teamcricket"home" | "away"

AtualidadePermalink for this section

CampoTipoSignificado
staletrue (omitido caso contrário)O TTL da chave de livestate do primary_book caiu abaixo do limite de atualidade do agregador (~10s) no momento da mesclagem. Os placares são os últimos valores conhecidos; o book ficou em silêncio. Trate os placares e o período do evento como potencialmente atrasados em relação ao estado real do jogo.
aggregator_staletrue (omitido caso contrário)O próprio agregador SharpAPI não escreveu um novo shard gamestate:{sport} para este esporte em mais de ~30s. Sinal mais amplo do que stale — indica um soluço no pipeline, não um problema isolado de um book. Se você ver isso de forma persistente, entre em contato com o suporte.

Ausência = atualizado. Tanto stale quanto aggregator_stale só são escritos quando verdadeiros, mantendo o payload compacto. Se você não os vê em um evento, os dados são considerados atualizados.

Eventos finalizadosPermalink for this section

Antes, uma partida sumia de /gamestate no instante em que terminava — o placar final só era visível para o cliente que por acaso fizesse polling durante o último ciclo ao vivo. Agora os eventos finalizados permanecem neste endpoint por 15 minutos após a conclusão como linha terminal, de modo que qualquer cliente com um intervalo razoável veja o resultado final pelo menos uma vez.

A janela é do lado do servidor e hoje é de 15 minutos (GAMESTATE_TERMINAL_CARRY_SECONDS, padrão 900). Depois disso a linha some de vez; o resultado encerrado continua disponível em /api/v1/events?status=final, que é a origem da linha terminal.

Como é uma linha terminalPermalink for this section

{ "home_team": "Skelleftea AIK", "away_team": "Geneva Servette HC", "sport": "hockey", "league": "champions_hockey_league", "home_score": 2, "away_score": 1, "score_type": "points", "winner": "home", "status": "final", "completed_at": "2026-09-10T18:54:03Z", "is_live": false, "stale": false }
CampoTipoNotas
status"final"Presente apenas em uma linha terminal. Linhas ao vivo não carregam nenhuma chave status, então status === "final" é o teste confiável — não deduza a partir de is_live.
completed_atstringISO 8601 — quando a SharpAPI detectou a conclusão, não o apito final oficial da liga. A janela de retenção é medida a partir deste timestamp.
score_type"points" | "sets"Quais campos carregam o resultado. "sets" para os esportes por sets (tennis, table_tennis, volleyball, badminton); "points" em todo o resto.
winner"home" | "away" | "draw"Opcional — omitido quando o resultado não pode ser determinado; veja abaixo. "draw" só é produzido em esportes nos quais um placar igual é um resultado real (soccer, hockey, football, rugby_union, rugby_league).
is_livefalseSempre false de forma explícita, para que qualquer renderização condicionada a is_live trate a linha como não ao vivo.
stalefalseSempre false de forma explícita. É o único lugar em que stale aparece sem ser verdadeiro — a regra “ausência = atualizado” acima vale só para linhas ao vivo.

Os placares finais usam os nomes de campo ao vivo, conforme o esporte. Um esporte por pontos coloca sua contagem em home_score / away_score. Um esporte por sets coloca sua contagem de sets em sets_home / sets_away e não carrega home_score / away_score — um final de tênis é 2-1 em sets, e colocar isso em home_score colidiria com os pontos de game da linha ao vivo:

{ "home_team": "Mikhail Biserov", "away_team": "Vasily Yugov", "sport": "table_tennis", "league": "pro_league", "sets_home": 2, "sets_away": 1, "score_type": "sets", "winner": "home", "status": "final", "completed_at": "2026-09-10T18:55:25Z", "is_live": false, "stale": false }

winner pode faltar, e isso significa algo. O campo é omitido quando o resultado registrado não encerra a partida:

  • um placar igual em um esporte que não admite empate (basquete, handebol, esports, beisebol…) — o jogo foi para a prorrogação, foi abandonado, ou o feed parou antes da decisão;
  • uma contagem de sets sub-terminal em um esporte por sets (quem lidera com menos de dois sets não pode ter vencido nenhum formato);
  • um snapshot cujos placares nunca chegaram, registrado como 0-0. Por isso um 0-0 sem winner não é o mesmo que um empate sem gols real — o real carrega "winner": "draw".

Trate um winner ausente como “não decidido”, não como empate. Se você está gradando ou liquidando algo, pule essas linhas.

Quais campos uma linha terminal não carregaPermalink for this section

Uma linha terminal é projetada a partir do registro de conclusão, não de uma mesclagem ao vivo entre books, então estes campos ao vivo simplesmente não existem: primary_book, book_count, game_period, game_clock e todos os campos situacionais (possession, corners_*, power_play, in_play, a família de probabilidade de vitória do tênis, e assim por diante). Leia-os somente depois de conferir que a linha não é status: "final".

Filtrando eventos finalizadosPermalink for this section

O que você querRequisição
Só linhas ao vivo (comportamento anterior à retenção)?is_live=true
Só linhas finalizadas?status=final
Ambas (padrão)nenhum parâmetro
# Só os finais dos últimos 15 minutos, um esporte curl "https://api.sharpapi.io/api/v1/gamestate/soccer?status=final" \ -H "X-API-Key: YOUR_API_KEY" # Exatamente o que você recebia antes da retenção existir curl "https://api.sharpapi.io/api/v1/gamestate?is_live=true" \ -H "X-API-Key: YOUR_API_KEY"

Se um evento finalizado ainda estiver ao vivo em algum lugar, a linha ao vivo vence. Um event_id que aparece tanto no conjunto ao vivo quanto no retido é retornado uma única vez, como linha ao vivo. Um book que ainda precifica o jogo o mantém ao vivo até que todos o tenham largado.

Exemplos de RequisiçãoPermalink for this section

# Todos os eventos ao vivo de todos os esportes curl "https://api.sharpapi.io/api/v1/gamestate" \ -H "X-API-Key: YOUR_API_KEY" # Um esporte curl "https://api.sharpapi.io/api/v1/gamestate/soccer" \ -H "X-API-Key: YOUR_API_KEY"

Exemplo de RespostaPermalink for this section

{ "data": { "soccer": { "argentina_-_primera_division_bocajuniors_defensayjusticia_2026-04-23": { "home_team": "Defensa y Justicia", "away_team": "Boca Juniors", "sport": "soccer", "league": "argentina_-_primera_division", "home_score": 0, "away_score": 1, "game_period": "2H", "game_clock": "49:06", "is_live": true, "possession": "away", "corners_home": 1, "corners_away": 0, "fouls_home": 0, "fouls_away": 0, "yellow_cards_home": 0, "yellow_cards_away": 0, "red_cards_home": 0, "red_cards_away": 0, "primary_book": "draftkings", "book_count": 6 }, "chile_-_primera_division_concepcion_palestino_2026-04-24": { "home_team": "Palestino", "away_team": "Concepción", "sport": "soccer", "league": "chile_-_primera_division", "home_score": 0, "away_score": 0, "is_live": true, "primary_book": "unibet", "book_count": 1, "stale": true }, "montenegro_-_prva_liga_bokelj_otrantolympiculcinj_2026-04-23": { "home_team": "Bokelj", "away_team": "FK Otrant-Olympic Ulcinj", "sport": "soccer", "league": "montenegro_-_prva_liga", "home_score": 2, "away_score": 1, "score_type": "points", "winner": "home", "status": "final", "completed_at": "2026-04-23T23:48:55Z", "is_live": false, "stale": false } } }, "updated_at": "2026-04-23T23:55:01.234Z" }

A terceira linha é uma linha terminal: a partida terminou cerca de seis minutos antes de esta resposta ser montada, então ela é retida com status: "final" e seu placar final, e não carrega primary_book, book_count, game_period nem game_clock.

Modelo de Mesclagem Cross-BookPermalink for this section

Os campos de cada evento são mesclados a partir do snapshot de livestate de cada sportsbook por meio de um algoritmo de três classes:

  • Classe A — Placares são escolhidos por consenso: entre os books no rank de período mais avançado, vence o placar de maior total com ≥2 apoiadores. Um único book relatando um placar discrepante (comum nos primeiros segundos de uma mudança de placar, ou de um adapter com mau funcionamento) é rejeitado.
  • Classe B — Campos temporais (game_period, game_clock) são selecionados pela direção do cronômetro de acordo com o esporte — regressivo vs progressivo — e rank de período.
  • Classe C — Campos situacionais (possession, corners_*, etc.) são preenchidos por prioridade a partir de um ranking fixo de books.

primary_book informa de qual book vieram os placares vencedores. book_count é o número total de books que contribuíram com qualquer estado para o evento no momento da mesclagem.

StreamingPermalink for this section

Toda atualização ao vivo que o endpoint REST exibiria no próximo poll também dispara um evento gamestate:update nos canais de streaming:

Clientes de streaming recebem um gamestate:snapshot inicial com o estado atual completo (uma lista plana de linhas de eventos), depois eventos gamestate:update carregando linhas alteradas conforme são mescladas, e eventos gamestate:removed quando eventos saem do conjunto ao vivo.

Um evento finalizado continua no slate transmitido como sua linha status: "final" durante a janela descrita em Eventos finalizados, e é anunciado uma vez com um frame gamestate:final.

Avisos de evento finalizadoPermalink for this section

Quando um evento termina, cada transporte envia um único frame gamestate:final para ele. Ele carrega a linha terminal do evento — o mesmo formato da linha REST, mais o event_id.

WebSocket:

{"type":"gamestate:final","seq":48213,"global_seq":"48213","data":[{"event_id":"atp_jdoe_rroe_2026-07-03","home_team":"J. Doe","away_team":"R. Roe","sport":"tennis","league":"atp","sets_home":1,"sets_away":2,"score_type":"sets","winner":"away","status":"final","completed_at":"2026-07-03T19:42:10Z","is_live":false,"stale":false}]}

SSE (o mesmo envelope {"data": [...]} do gamestate:update):

event: gamestate:final data: {"data":[{"event_id":"atp_jdoe_rroe_2026-07-03","home_team":"J. Doe","away_team":"R. Roe","sport":"tennis","league":"atp","sets_home":1,"sets_away":2,"score_type":"sets","winner":"away","status":"final","completed_at":"2026-07-03T19:42:10Z","is_live":false,"stale":false}]}
  • Mesmo acesso e mesmos filtros do gamestate:update. Quem recebe gamestate:update recebe gamestate:final, e seus filtros sport/league se aplicam. Sem acesso a game state, você não recebe nenhum dos dois.
  • O WebSocket faz replay. Como gamestate:update e gamestate:removed, ele fica no buffer de replay e é reenviado numa reconexão com from_seq. Frames de gamestate no SSE não são retomáveis.
  • É um aviso, não a única entrega. A mesma linha também está no slate (gamestate:snapshot e gamestate:update) durante toda a janela.

“Uma vez por evento” pode se repetir ocasionalmente — deduplique por (event_id, completed_at). Você pode receber gamestate:final mais de uma vez para o mesmo evento. event_id e completed_at são idênticos em toda repetição: descarte um frame cujo par você já processou. Isso é sempre seguro, porque a linha continua no slate.

Rate Limits e QuotasPermalink for this section

Os rate limits seguem o seu tier base, não o add-on — keys Hobby mantêm seus 120 req/min, Pro mantêm 300, Sharp mantêm 1.000, Enterprise customizado. Veja Pricing . /gamestate conta da mesma forma que outras chamadas REST para a quota por minuto.

Solução de ProblemasPermalink for this section

  • 403 tier_restricted com addon: "game_state" — sua key não tem o add-on Game State. Adicione-o pela Billing  por US$ 79/mês, ou faça upgrade para Enterprise.
  • 400 validation_error com parameter: "status" — o único valor aceito de ?status= é final. Não existe o valor live; linhas ao vivo são o conjunto padrão, ou peça só elas com ?is_live=true.
  • 400 validation_error com parameter: "is_live" — ?is_live= aceita apenas true / false. 1 e 0 são rejeitados; antes eram lidos como false e devolviam o oposto do que se pedia.
  • Uma linha com status: "final" e is_live: false — não é bug. É um evento finalizado dentro da janela de 15 minutos. Filtre com ?is_live=true para o comportamento anterior.
  • primary_book / book_count ausentes — você está lendo uma linha terminal. Verifique status antes de ler campos que só existem ao vivo.
  • Objeto data vazio — não há eventos ao vivo no escopo. Isso é comum entre eventos em calendários de esportes menores. Faça polling novamente.
  • Eventos com stale: true — o book primário ficou em silêncio. Os placares podem estar atrasados; considere filtrá-los ou exibir um indicador de UI.
  • Eventos com aggregator_stale: true — o agregador SharpAPI não atualizou esse esporte em >30s. Se persistente, entre em contato com o suporte; um pico breve pode acontecer durante redeploys.
  • Mesma partida aparece duas vezes sob diferentes event_ids — limitação conhecida para algumas ligas regionais onde os sportsbooks usam nomenclatura de liga inconsistente. Use (home_team, away_team) como uma chave secundária de deduplicação no cliente até que as lacunas restantes de aliases sejam fechadas.
Last updated on