Notas de quickstart
Poste alertas de queda no Discord a partir do seu listener Python
O listener de quedas já interpreta cada alerta. Adicione um POST de webhook e um cooldown por partida, e seu canal mostra cada movimento.
O listener de quedas do quickstart de Python já faz a parte difícil: uma requisição aberta, uma linha de dados por lote, cada alerta interpretado com esporte, partida, resultado, preço antigo, preço novo e preço justo. Transformá-lo num canal de Discord leva só mais uma função: formatar o alerta, postá-lo num webhook e não deixar o POST atrasar o stream.
O que você precisa antes do código
Duas coisas além do listener. Primeiro, um plano que envia quedas: a página de preços mostra que as quedas começam no plano push de US$ 99 por mês e estão incluídas nos planos de US$ 149 e US$ 229, verificado em 2026-10-24. Sem um, o stream responde com uma mensagem de controle plan_lacks_sse em vez de alertas. Segundo, uma URL de webhook do Discord, que fica nas configurações do canal, em Integrações. Guarde-a numa variável de ambiente como a sua chave de API.
O publicador
A mudança no listener é pequena. Onde o quickstart imprime cada alerta, chame uma função de notificação:
import json, os, time, requests
BASE = os.environ["ODDS_BASE_URL"]
KEY = os.environ["ODDS_API_KEY"]
HOOK = os.environ["DISCORD_WEBHOOK_URL"]
s = requests.Session()
s.headers["x-portal-apikey"] = KEY
last_sent = {}
def notify(a):
key = (a["home"], a["outcome"])
if time.time() - last_sent.get(key, 0) < 300:
return # mesma partida e resultado em 5 minutos
last_sent[key] = time.time()
pct = (a["from_price"] - a["to_price"]) / a["from_price"] * 100
text = (f'{a["sport"]} | {a["home"]} | {a["outcome"]}: '
f'{a["from_price"]} -> {a["to_price"]} ({pct:.1f}%), '
f'justo {a["nvp"]}')
try:
requests.post(HOOK, json={"content": text}, timeout=10)
except requests.RequestException:
pass # o stream importa mais que uma mensagem
def listen():
r = s.get(BASE + "/odds-drop", params={"min_drop": 5},
stream=True, timeout=90)
r.raise_for_status()
for raw in r.iter_lines():
if not raw.startswith(b"data:"):
continue
msg = json.loads(raw[5:])
if isinstance(msg, dict):
continue # frame de controle, não alertas
for a in msg:
notify(a)
O percentual é a mesma aritmética que o feed mede: a queda dividida pelo preço antigo. O preço justo vem anexado ao alerta, então a mensagem carrega o que o mercado acha que o lado vale, não só para onde ele se moveu.
Mantenha o canal legível
Um webhook que dispara a cada alerta vira papel de parede em um dia. Duas proteções o mantêm digno de leitura. Deixe o stream fazer o filtro grosso: o min_drop na conexão define o piso, 5 no exemplo documentado, e qualquer coisa abaixo dele nunca chega ao seu código. Depois deixe o cooldown fazer o fino: cinco minutos por partida e resultado, como acima, para que um preço escorregando em degraus produza uma mensagem, não seis.
Resista a menções e embeds no começo. Linhas de texto puro leem mais rápido, e um canal que só apita quando você decide continua confiável.
Quando o Discord diz não
O Discord limita webhooks por taxa e responde a rajadas com seu próprio 429. O publicador acima trata um envio falho como mensagem perdida, o que é o padrão certo para um alerta sobre o qual você não agiria cinco minutos depois. Se precisar de cada alerta entregue, enfileire-os e esvazie a fila devagar; não tente de novo dentro do loop de leitura, onde um webhook lento trava o stream.
O listener já era a integração inteira. O webhook é o print, turbinado.