RUNBOOK DE ERROS
Um runbook para erros da API da Pinnacle.
Cada status que a API de odds da Pinnacle devolve pede uma reação diferente de um poller. Este runbook os separa em parar, esperar e repetir, dá a regra de espera de cada um e diz quais devem acordar uma pessoa. As regras são as mesmas na chave gratuita e nos planos REST pagos.
Quatro classes de resposta
Um poller só precisa de quatro reações. A tabela mapeia cada status para uma delas; tudo o que vem depois explica o tempo.
| Resposta | O que significa | Reação |
|---|---|---|
| 401 | Sem chave, ou uma chave que a API não reconhece | Parar e alertar uma pessoa |
| 403 | A chave é conhecida, mas o plano não cobre esta chamada | Parar e verificar o plano |
| 429 | A cota por segundo ou diária acabou | Esperar o Retry-After e retomar |
| 5xx, timeout, reset | O serviço ou a rede falhou por enquanto | Repetir com backoff limitado |
| 200 com um corpo inesperado | Uma resposta que não é o envelope documentado | Tratar como falha; manter o último snapshot |
Erros de parada: 401 e 403
Nenhum dos dois melhora com o tempo, então repeti-los em loop só acrescenta ruído aos logs e, em uma conta compartilhada, ao lado do fornecedor. Um 401 significa que a requisição não trazia uma chave utilizável: o header está faltando, a variável de ambiente está vazia neste deploy, ou a chave foi rotacionada. Verifique se o poller envia a chave no header x-portal-apikey e se o valor bate com o painel da conta.
Um 403 é mais sutil: a autenticação funcionou, mas o plano não inclui o que foi pedido. Uma chave válida ainda pode não ter um transporte, um complemento ou um endpoint, e a correção está na conta, não no código. O checklist de acesso no pnclODDS separa autenticação de direito de uso passo a passo. Nos dois casos, registre o status e o código de erro, nunca a chave nem o corpo completo da resposta, e acione quem cuida da conta.
Erros de espera: 429
Um 429 diz que a programação cruzou o teto: 20 requisições por minuto ou 100 por dia na chave gratuita, 10 ou 30 por segundo nos planos REST pagos. O header Retry-After é a autoridade sobre quanto esperar. Respeite-o, adicione um pouco de jitter para que workers paralelos não retomem em sincronia, e compartilhe o estado do backoff entre os workers, já que dez processos educados ainda somam dez vezes as requisições. A página de limites de taxa tem o loop de backoff e a regra de folga que mantém os 429 raros.
HTTP/1.1 429 Too Many Requests
Retry-After: 2
Um 429 na cota diária da chave gratuita é de outra natureza: nenhum backoff traz o dia de volta. Detecte-o pelo tamanho do Retry-After e pare o poller até a janela reiniciar, em vez de queimar a próxima hora em chamadas rejeitadas.
Erros de repetição: 5xx, timeouts e resets
Estes são transitórios até prova em contrário. Repita com um atraso que começa em meio segundo, dobra a cada vez e para em 30 segundos, e desista depois de três tentativas em um ciclo de polling. Falhar o ciclo não é problema: o próximo polling agendado roda de qualquer forma, e um snapshot dez segundos atrasado é melhor do que um poller preso em um loop de retentativas. Continue servindo o último snapshot bom aos seus próprios consumidores, com a idade dele visível, para que um dashboard mostre preços desatualizados em vez de nenhum.
def poll_once():
delay = 0.5
for attempt in range(3):
try:
res = get(url, timeout=8)
except (Timeout, ConnectionError):
sleep(delay + random() * delay / 2)
delay = min(delay * 2, 30)
continue
if res.status in (401, 403):
raise Stop(res.status)
if res.status == 429:
sleep(float(res.headers.get("Retry-After", delay)))
continue
if res.status >= 500:
sleep(delay + random() * delay / 2)
delay = min(delay * 2, 30)
continue
return validate(res.json())
return None # this cycle failed; the next one runs
Valide o 200
Um status de sucesso é o começo da verificação, não o fim. A resposta de mercados é um objeto com um array events e um cursor last; exija os dois antes de tocar no payload. Um array vazio em uma hora tranquila é uma resposta válida e não deve ser registrado como erro, enquanto um corpo sem o cursor está malformado e não deve substituir o snapshot que você já tem. Nunca preencha um preço ausente com zero: uma money line nula significa que o mercado está fechado ou indisponível, e zero pareceria um preço para tudo o que vem depois.
O que deve acionar uma pessoa
Quatro condições justificam acordar alguém; o resto pertence a um dashboard. Um 401 ou 403 a qualquer momento, porque o poller não consegue se recuperar sozinho. Mais de um 429 a cada cem requisições durante uma hora, porque a programação está perto demais do teto. Uma sequência de 5xx ou timeouts por mais de cinco minutos, porque uma falha transitória deixou de ser transitória. E um snapshot mais velho que três intervalos de polling em qualquer quadro durante uma grade, que é o sintoma que os outros três causam. A página de monitoramento transforma isso em métricas com limiares.
Perguntas da escala de plantão
Um 429 deve ser repetido imediatamente alguma vez?
Não. Mesmo sem um header Retry-After, espere pelo menos o atraso base. Uma retentativa imediata cai dentro da mesma janela e prolonga o bloqueio.
Um 403 é sempre um problema de plano?
Nesta API quase sempre é: a chave foi aceita e a requisição foi recusada. Compare o endpoint e o transporte que você chamou com os direitos do plano antes de mudar qualquer código.
Quantas tentativas por ciclo é demais?
Mais de três. Cada tentativa extra gasta orçamento em uma chamada que provavelmente vai falhar de novo, e o próximo ciclo está a segundos de distância. Falhe rápido e deixe a programação se recuperar.
Os significados dos status e as cotas seguem a documentação publicada pelo fornecedor, conferida em 26 de setembro de 2026. Publicado em .