O que é a API de odds da Pinnacle

A API de odds da Pinnacle que este guia documenta é um feed de terceiros que serve os preços ao vivo e pré-jogo da Pinnacle como JSON por REST, envia quedas de preço por server-sent events e, como complemento pago, retransmite frames brutos de WebSocket. É um produto de dados: lê preços, não faz apostas nem toca em uma conta da Pinnacle.

Não é a API da própria Pinnacle. A Pinnacle encerrou o cadastro público na sua API em 23 de julho de 2025 e agora concede acesso caso a caso a parceiros comerciais e a alguns usos individuais e de pesquisa. A página alternativa à API da Pinnacle no pnclFEED explica o que mudou e qual caminho serve a cada uso; este guia cobre o feed.

Tudo abaixo vem da documentação publicada do feed, conferida em 26 de setembro de 2026. Onde a documentação diverge de si mesma, o guia diz isso. Nada aqui é um resultado medido, a menos que a seção diga como foi medido.

Autenticação e a primeira requisição

Toda requisição leva sua chave no cabeçalho x-portal-apikey. Os endpoints de streaming também a aceitam como parâmetro de consulta ?key= para clientes que não conseguem definir cabeçalhos, mas uma chave na URL acaba em logs, então mantenha a forma de cabeçalho nos servidores. A URL base vem da sua conta e da documentação; os exemplos desta página a leem de uma variável de ambiente.

Uma chave gratuita é emitida no cadastro, sem cartão e sem validade, e serve também como login da conta. Ela permite 20 requisições por minuto e 100 por dia em REST, o que basta para validar um parser, rodar todos os exemplos desta página e consultar um quadro a cada quinze minutos o dia inteiro. Uma demonstração completa de três dias, com SSE, WebSocket bruto e 10 requisições por segundo, está disponível mediante pedido (conferido em 26 de setembro de 2026).

export ODDS_API_KEY="your key"
export ODDS_BASE_URL="https://..."   # from your account

curl -s -H "x-portal-apikey: $ODDS_API_KEY" \
  "$ODDS_BASE_URL/kit/v1/markets?sport_id=1" \
  | jq '{last, events: (.events | length)}'

Um 200 com um cursor last e uma contagem de eventos diferente de zero significa que a chave funciona e o quadro de futebol está ativo. O quickstart de curl e jq no pnclFEED estende isso para uma listagem de uma linha por partida, e a página chave da API da Pinnacle no pnclODDS cobre o cadastro e a primeira requisição passo a passo.

Endpoints

O feed tem uma superfície pequena. Quatro rotas REST, dois streams, uma verificação de saúde e um WebSocket bruto opcional cobrem tudo o que a documentação descreve.

RotaFinalidadeObservações
GET /kit/v1/markets?sport_id=NO quadro ao vivo de um esporteDevolve um objeto com events e um cursor last. Envie last de volta como since para receber apenas o que mudou.
GET /kit/v1/prematch/fixtures?sport_id=NO quadro pré-jogo de um esporteFixtures com seus mercados. Uma rota de nome parecido, abaixo, recebe um evento em vez de um esporte.
GET /kit/v1/prematch/markets?event_id=NOs mercados de um evento pré-jogoConfundi-la com a rota de fixtures faz um feed válido parecer vazio ou devolve um erro de parâmetro.
GET /api/drops?mode=live|prematchQuedas recentes, sob demandamin_drop_pct define o tamanho do movimento e max_age_sec a janela. Guarda aproximadamente as últimas três horas.
GET /odds-drop?min_drop=NAlertas de queda ao vivo, em streamServer-sent events. Uma conexão por chave por stream; uma segunda conexão ao vivo fecha a primeira.
GET /odds-drop-prematch?min_drop=NAlertas de queda pré-jogo, em streamAdicione recheck=N para segurar cada queda por N segundos e enviá-la só se o preço não tiver voltado.
Endpoint de saúdeHá quanto tempo o feed ao vivo escreveu pela última vezIndicado na documentação; consulte-o ao lado de um stream silencioso para distinguir um mercado parado de um feed quebrado.
WebSocket brutoCada frame, sem processamentoUm complemento pago nos três planos REST. Você mesmo reconstrói o estado do mercado.

Os ids de esporte são do próprio feed, de 1 a 13, e cada resposta publica ao lado deles o id interno da Pinnacle. Futebol é 1, tênis 2, basquete 3, hóquei 4, futebol americano 5, beisebol 6, rúgbi 7, MMA 8, boxe 9, vôlei e handebol 10, esports 11, golfe 12 e críquete 13. Mapeie-os uma vez na borda do seu código e nunca misture os dois espaços de nomes.

O formato da resposta

A resposta de um quadro é um objeto, não uma lista. events guarda um registro por partida e last é o cursor da próxima chamada. Cada evento traz as equipes, o horário de início, o id de esporte do feed e o da Pinnacle, e seus mercados agrupados em periods. periods.num_0 é a partida completa; as outras chaves são tempos, quartos, sets ou mapas, conforme o esporte.

{
  "last": 141,
  "events": [
    {
      "home": "Home FC",
      "away": "Away FC",
      "periods": {
        "num_0": {
          "money_line": { "home": 2.10, "draw": 3.40, "away": 3.60 },
          "spreads": { "-0.5": { "home": 2.05, "away": 1.85 } },
          "totals":  { "2.5":  { "over": 1.95, "under": 1.90 } },
          "team_total": { "home": { "points": 1.5, "over": 2.00, "under": 1.85 } }
        }
      }
    }
  ]
}

Os preços são odds decimais. Money line, spreads, totais e totais por equipe têm formatos diferentes, e um total da partida completa e um total do primeiro tempo são mercados diferentes mesmo quando compartilham uma linha. A presença varia por evento e período: um mercado pode estar ausente, vazio ou suspenso, e seu modelo deve manter esses três estados separados. Nunca substitua um preço ausente por zero.

Os mercados especiais são uma expansão opcional por meio de include_specials. Eles chegam como linhas extras ligadas por parent_id e estruturas special_markets separadas, aumentam o payload, e nem todas as suas mudanças de preço seguem o mesmo comportamento de alerta dos mercados principais. Mantenha o parser de mercado completo e o parser de alertas de queda separados. O guia de normalização mostra as chaves de evento, período, mercado, linha, seleção e timestamp que tornam os registros deste feed comparáveis a qualquer outro.

Polling com o cursor since

O cursor é todo o truque para consultar este feed com baixo custo. A primeira chamada de um esporte devolve o quadro completo e um valor last; cada chamada seguinte envia esse valor como since e recebe apenas os eventos que mudaram. Guarde o cursor junto com o snapshot para que um reinício retome em vez de buscar tudo de novo, e trate o quadro completo como o meio de ressincronizar, não como o meio de fazer polling.

import os, time, requests

BASE = os.environ["ODDS_BASE_URL"]
HEADERS = {"x-portal-apikey": os.environ["ODDS_API_KEY"]}

def poll(sport_id=1, interval=900):
    since = None
    while True:
        params = {"sport_id": sport_id}
        if since is not None:
            params["since"] = since
        r = requests.get(f"{BASE}/kit/v1/markets", headers=HEADERS, params=params, timeout=30)
        if r.status_code == 429:
            time.sleep(int(r.headers.get("Retry-After", "5")))
            continue
        r.raise_for_status()
        body = r.json()
        since = body["last"]
        for event in body["events"]:
            line = event["periods"].get("num_0", {}).get("money_line")
            if line:
                print(event["home"], event["away"], line)
        time.sleep(interval)

poll()

Quinze minutos entre chamadas mantêm um quadro dentro das 100 requisições por dia da chave gratuita. Em um nível pago, o intervalo é uma decisão de orçamento: a página de planejamento de capacidade no pnclENGINE transforma esportes, fases e um intervalo em requisições por segundo e por dia, e a calculadora de custo da API aqui transforma a mesma programação em um valor mensal. O quickstart de Python e o quickstart de Node.js no pnclFEED trazem versões mais longas deste loop.

Alertas de queda por SSE

Os streams enviam quedas de preço no instante em que o feed as detecta. Um GET para /odds-drop nos mercados ao vivo ou /odds-drop-prematch nos pré-jogo, com a chave e Accept: text/event-stream, devolve um 200 que nunca termina. Defina min_drop você mesmo: o exemplo documentado usa 5 e o mínimo é 1, e o valor padrão está documentado de forma inconsistente, então confiar nele é um erro.

Cada mensagem é uma linha data: contendo JSON. A primeira é um objeto de controle, {"type": "connected"}; depois dela, cada lote de alertas é um array. Um objeto mais adiante no stream é outra mensagem de controle, como plan_lacks_sse quando o plano da chave não tem stream ou rate_limited quando um cliente reconecta em loop apertado, que também traz um cabeçalho Retry-After: 60.

data: {"type": "connected", "id": "d648beb8-..."}
data: [{"home": "Sunshine Coast Phoenix", "away": "Cairns Dolphins",
        "league": "Australia - NBL1 Women", "sport": "Basketball",
        "sect": "Moneyline", "outcome": "Home", "period": 4,
        "from_price": 2.86, "to_price": 2.7, "nvp": 3.04,
        "id": 1629729400, "alerted": 1777625196}]

Cada alerta identifica a linha com sport, league, sect, outcome e period, traz o preço antes e depois como from_price e to_price, acrescenta nvp, o preço justo sem margem após o movimento, e marca o alerta em segundos Unix como alerted. A porcentagem é você quem calcula. Alertas perdidos não são reenviados: preencha uma lacuna a partir de /api/drops, cujos registros usam nomes de campo diferentes (from, to, drop_pct, market, side), então confira qual deles um exemplo lê.

// Node.js 18+: read the live drop stream and reconnect with backoff.
const BASE = process.env.ODDS_BASE_URL;
const KEY = process.env.ODDS_API_KEY;

async function listen(minDrop = 5) {
  let delay = 1000;
  for (;;) {
    try {
      const res = await fetch(`${BASE}/odds-drop?min_drop=${minDrop}`, {
        headers: { "x-portal-apikey": KEY, accept: "text/event-stream" },
      });
      if (res.status === 429) {
        await new Promise((r) => setTimeout(r, Number(res.headers.get("retry-after") || 60) * 1000));
        continue;
      }
      delay = 1000;
      let buffer = "";
      for await (const chunk of res.body) {
        buffer += Buffer.from(chunk).toString("utf8");
        let end;
        while ((end = buffer.indexOf("\n\n")) >= 0) {
          const frame = buffer.slice(0, end);
          buffer = buffer.slice(end + 2);
          const line = frame.split("\n").find((l) => l.startsWith("data:"));
          if (!line) continue;
          const payload = JSON.parse(line.slice(5));
          if (Array.isArray(payload)) payload.forEach(handle);
          else if (payload.type !== "connected") console.warn("control", payload);
        }
      }
    } catch (err) {
      console.error("stream closed", err.message);
    }
    await new Promise((r) => setTimeout(r, delay + Math.random() * delay));
    delay = Math.min(delay * 2, 60000);
  }
}

function handle(alert) {
  const pct = ((alert.from_price - alert.to_price) / alert.from_price) * 100;
  console.log(alert.sport, alert.home, alert.away, alert.sect, alert.outcome, pct.toFixed(1) + "%");
}

listen();

Limites, conjuntos de alertas vistos e janelas de deduplicação ficam ao lado do processo leitor, não em uma aba do navegador. As páginas de configuração SSE e de deduplicação e cooldowns no pnclPULSE cobrem o lado das regras, e a página de alertas no Telegram no pnclDATA mostra o mesmo stream entregue em um celular.

Limites de taxa, erros e backoff

Todo plano tem um teto por segundo em REST, e a chave gratuita tem também tetos por minuto e por dia. Ultrapassar um limite devolve 429 Too Many Requests, normalmente com um cabeçalho Retry-After em segundos. Esse cabeçalho manda: espere exatamente esse tempo e continue. Uma contagem crescente de 429 é o aviso antecipado de que a carga em regime está se aproximando do teto.

StatusSignificadoO que fazer
401O cabeçalho está faltando ou a chave está erradaCorrija a chave; não tente de novo
403A chave é válida, mas o plano não inclui o que você pediuConfira o plano, ou o direito ao stream
429Acima da cota por segundo, por minuto ou por diaEspere o Retry-After, depois tente de novo com jitter
5xxO feed teve um problemaTente algumas vezes com esperas crescentes, depois falhe o ciclo

Mantenha o uso em regime abaixo de cerca de 70 por cento da cota por segundo, para que tentativas, ferramentas administrativas e um segundo ambiente caibam no restante. Compartilhe o estado de backoff entre os workers; dez processos recuando educadamente ainda somam dez vezes as requisições. A página de limites de taxa e o runbook de erros no pnclENGINE vão status por status.

Planos e preços

Preços publicados em dólares, cobrança mensal, conferidos em 26 de setembro de 2026. O checkout mostra os valores que valem no dia da compra, e impostos, taxas e rateio não são publicados.

PlanoMensalCota RESTAlertas SSEWebSocket bruto
Chave gratuita$020 por minuto, 100 por diaNãoNão
Alertas de queda SSE$9920 por minuto, 100 por hora, 100 por diaIncluídoNão elegível
Snapshots REST$9910 requisições por segundoNão+US$ 99 a cada 30 dias
REST + SSE$14910 requisições por segundoIncluído+US$ 99 a cada 30 dias
REST de alto volume$22930 requisições por segundoIncluído+US$ 99 a cada 30 dias

Existem períodos pré-pagos: três meses por US$ 249 nos dois planos de US$ 99, US$ 379 no REST + SSE e US$ 599 no REST de alto volume, e seis meses por US$ 449 e US$ 679 apenas nos dois planos REST. O complemento WebSocket bruto é cotado em blocos de 30, 90 e 180 dias por US$ 99, US$ 297 e US$ 594. Um equivalente mensal é um número de comparação, não uma fatura mensal. A página preços da API da Pinnacle no pnclODDS tem o estimador e as decisões de adequação de plano, e o quickstart de preços no pnclFEED lê os mesmos números do lado do desenvolvedor.

Cobertura

A documentação lista futebol, tênis, basquete, hóquei, futebol americano, beisebol, rúgbi, MMA, boxe, vôlei e handebol, esports, golfe e críquete. Ao vivo e pré-jogo estão ambos documentados, e a disponibilidade de eventos varia por esporte e por dia. Os mercados REST são money line, spreads, totais e totais por equipe sob períodos. Um esporte listado não garante todas as competições ou mercados, então rode uma amostra representativa com a chave gratuita enquanto os eventos que importam para você estiverem no quadro.

A cadência de atualização é informada de forma inconsistente: a página inicial fala em cinco segundos para o pré-jogo e a referência descreve trinta. Nenhum dos dois é uma latência medida de ponta a ponta. Não há arquivo histórico; o feed é um serviço de dados atuais, e registrar o histórico é uma tarefa operacional sua, com seus próprios direitos de armazenamento. A página de cobertura no pnclODDS mantém a tabela de evidências, e a página API de odds de esports no pnclHUB mostra um esporte documentado na prática.

Medir latência e atualidade por conta própria

Este guia não publica nenhum número de latência porque nenhum foi medido sob um protocolo declarado. O jeito honesto de obter um é medir: registre o timestamp do próprio feed ao lado do seu horário de recebimento para cada alerta ou atualização durante pelo menos uma semana, alinhe os relógios antes, compare mercados em vez de eventos e informe a distribuição, não uma média.

O protocolo de benchmark define as cargas de trabalho, o alinhamento de relógios e o formato do relatório, e a página de pesquisa lista os relógios de que cada resultado precisa. Quando uma medição for publicada nesta rede, ela aparecerá com esse método e sua data.

Referência de campos

Os campos que um parser mais encontra, por endpoint, com os nomes que a documentação usa. Os tipos são os que os exemplos documentados mostram; valide-os em vez de presumir.

CampoOndeSignificado
eventsRespostas de quadroArray de registros de eventos do esporte solicitado.
lastRespostas de quadroCursor a devolver como since na próxima chamada.
home, awayEvento, alerta, quedaNomes de equipes ou jogadores como o feed os imprime.
periodsEventoObjeto com chaves num_0, num_1 e assim por diante; cada período guarda seus próprios mercados.
money_linePeríodohome, draw (quando o esporte tem empate) e away como odds decimais.
spreadsPeríodoIndexado pela linha de handicap; cada linha guarda os preços home e away.
totalsPeríodoIndexado pela linha de total; cada linha guarda over e under.
team_totalPeríodoTotais por equipe com uma linha points e preços over e under.
parent_id, special_marketsEvento, com include_specialsLiga uma linha de mercado especial ao evento a que pertence.
typeMensagem de controle SSEconnected na abertura; depois, nomes de erro como plan_lacks_sse ou rate_limited.
sport, league, sect, outcome, periodAlerta SSEA linha que se moveu: esporte, competição, seção de mercado, lado e número do período.
from_price, to_price, nvpAlerta SSEPreço antes, preço depois e o preço justo sem margem após o movimento.
id, alertedAlerta SSEId do evento e hora do alerta em segundos Unix; junto com os campos da linha, formam uma chave de deduplicação.
market, side, from, to, drop_pct, nvpREST /api/dropsO mesmo movimento como registro REST, com a porcentagem já calculada.
Retry-AfterRespostas 429, frames rate_limitedSegundos a esperar antes da próxima requisição ou reconexão.

Ler uma queda por REST e por SSE

A mesma detecção alimenta o stream e o endpoint de quedas, mas os dois registros têm formatos diferentes. Um parser escrito para um lerá o outro errado em silêncio, então mapeie os campos explicitamente.

O que você querAlerta SSEQueda REST
A linhasport, league, sect, outcome, periodsport_name, market, side
Preço antes e depoisfrom_price, to_pricefrom, to
Tamanho do movimentoCalcule: (from_price menos to_price) dividido por from_pricedrop_pct
Preço justo após o movimentonvpnvp
Quandoalerted, segundos UnixUm timestamp em cada registro
Filtragemmin_drop na conexão, recheck no pré-jogomode, min_drop_pct, max_age_sec na requisição
ReenvioNenhum; alertas perdidos se perdemAproximadamente as últimas três horas

Glossário

Quadro
Todos os eventos que o feed lista no momento para um esporte em uma fase, ao vivo ou pré-jogo, com seus mercados.
Cursor
O valor last que uma resposta de quadro traz; devolvido como since, limita a próxima resposta ao que mudou.
Queda
Um preço que cai pelo menos o limite que você definiu, medido do preço anterior que o feed viu até o atual.
Preço sem margem (nvp)
O preço justo implícito em um mercado depois de removida a margem da casa, de modo que as probabilidades de todos os resultados somem um.
Período
A parte da partida sobre a qual um mercado se liquida: num_0 para a partida completa, depois tempos, quartos, sets ou mapas conforme o esporte.
Fase
Pré-jogo, antes de o evento começar, ou ao vivo, enquanto acontece. O feed serve ambos por rotas e streams diferentes.
Snapshot
Uma resposta de quadro guardada no seu próprio armazenamento, o estado contra o qual você reconcilia e que atualiza a partir do stream.

Escolher um transporte

Polling REST é o padrão certo para snapshots e reconciliação: é barato com o cursor, se recupera sozinho e não precisa de conexão de longa duração. Os streams SSE são a escolha certa quando sua aplicação reage a quedas e a nada mais, porque o feed já fez a detecção. Frames brutos de WebSocket só são a escolha certa quando você precisa de cada movimento de preço, inclusive os pequenos demais para gerar alerta, e está preparado para reconstruir o estado do mercado e recuperar lacunas por conta própria.

A maioria das configurações em produção usa dois: REST para a carga inicial e a reconciliação periódica, um stream para o caminho quente. O guia de transportes pesa recuperação, atualidade, estado e custo operacional, e a página stream SSE versus endpoint REST no pnclPULSE compara as duas formas de ler quedas.

Perguntas frequentes

Esta é a API oficial da Pinnacle?
Não. A Pinnacle encerrou o cadastro público na sua própria API em 23 de julho de 2025 e concede acesso mediante solicitação. O feed documentado aqui serve os preços da Pinnacle a qualquer pessoa com uma chave, e apenas lê preços.
Existe uma API de odds da Pinnacle gratuita?
Sim. A chave gratuita permite 20 requisições por minuto e 100 por dia em REST, sem cartão e sem validade. Streams e taxas maiores exigem um plano pago ou a demonstração de três dias.
A API tem odds históricas?
Não. A documentação descreve um serviço de dados atuais, sem arquivo histórico. Registre o que precisar a partir do dia em que começar e verifique os direitos de armazenamento que se aplicam ao seu uso.
Com que frequência os preços são atualizados?
As páginas do fornecedor divergem: cinco segundos na página inicial, trinta segundos na referência, para o pré-jogo. Trate ambos como cadência documentada, não latência medida, e meça seu próprio caminho se isso importar.
Posso fazer apostas por ele?
Não. É um feed de dados. Fazer apostas por API significa a API de apostas da própria Pinnacle, disponível apenas para usuários aprovados.
De qual plano preciso para alertas de queda?
O plano de alertas de queda SSE de US$ 99, ou REST + SSE por US$ 149 e REST de alto volume por US$ 229, que incluem os streams. O plano de snapshots REST de US$ 99 não tem stream.
O que acontece se eu ultrapassar o limite de taxa?
A API responde 429 com um cabeçalho Retry-After. Espere esse número de segundos e continue; um loop de tentativas apertado transforma um limite curto em uma restrição mais longa, e nos streams produz uma mensagem de controle rate_limited.

Onde cada assunto se aprofunda

Este guia é a referência; sete sites do mesmo editor levam adiante, cada um, uma parte do feed.

  • pnclFEED: quickstarts em curl, Python, Node.js, Google Sheets e WebSocket bruto, todos executáveis com a chave gratuita.
  • pnclENGINE: planejamento de capacidade REST, o cursor since, limites de taxa, tratamento de erros, armazenamento de histórico e monitoramento de pipeline.
  • pnclPULSE: alertas de queda por SSE, de limites e janelas a deduplicação, entrega e reconexões.
  • pnclODDS: planos, preços, acesso, cobertura e o complemento WebSocket, comparados por completo.
  • pnclDATA: alertas de odds em queda com preços justos, e calculadoras de EV, odds em queda, CLV e Kelly.
  • pnclHUB: uma mesa de partidas de esports ao vivo para CS2, League of Legends e Dota 2, com guias de mercado.
  • Ferramentas do pnclAPI: o conversor de odds, a calculadora de no-vig e a calculadora de custo da API, aqui neste site.

Correções de qualquer fato desta página seguem a política editorial: a página muda, e a data de atualização também.