RELAY POR WEBHOOK
Alertas de caída de Pinnacle en Discord o Slack.
Un relay es un proceso que mantiene abierto el stream de caídas de la API de cuotas de Pinnacle y publica cada alerta en un webhook de chat. Esta página da el bucle, la forma del mensaje, la regla de reintento del webhook y el cooldown que evita que un mercado agitado inunde un canal. Funciona con un plan con alertas SSE; la clave gratuita es solo REST.
Las tres partes de un relay
El lado del stream es un GET a /odds-drop para los mercados en vivo o a /odds-drop-prematch para los prepartido, con tu clave en la cabecera x-portal-apikey y min_drop fijado en la query string. La conexión permanece abierta y cada línea data: lleva una lista JSON de alertas. Un objeto suelto en lugar de una lista es un mensaje de control, como el saludo connected; sáltatelos.
El lado del chat es un POST a la URL de webhook que te dio tu espacio de trabajo. Discord lee un cuerpo JSON con un campo content; los incoming webhooks de Slack leen un campo text. Ambos responden en bastante menos de un segundo y ambos limitan la velocidad a la que un webhook puede publicar.
En medio hay un formateador y una comprobación de cooldown. El relay completo son unas cuarenta líneas en cualquier lenguaje con un cliente HTTP:
open GET /odds-drop?min_drop=5 (key in header)
for each line of the stream:
skip lines that do not start with "data:"
msg = parse JSON after "data:"
skip msg when it is an object (control message)
for alert in msg:
skip when alert.sport not in SPORTS
skip when cooldown(alert) is still running
enqueue post(webhook, text(alert))
Mantén el POST fuera del bucle de lectura. Si el relay espera cada respuesta del webhook antes de leer la siguiente línea, una respuesta lenta retrasa todas las alertas que vienen detrás. Basta con una pequeña cola en memoria con un worker que la vacíe, y si la cola se llena, descarta la entrada más antigua: una alerta sobre un precio de hace tres minutos ya no es noticia.
Qué poner en el mensaje
Cada alerta nombra el partido y la selección: home, away, league, sport, el mercado en sect, el lado en outcome y los dos precios, from_price y to_price. El stream envía precios, no un porcentaje, así que el relay calcula la caída por su cuenta: (from − to) ÷ from × 100. También lleva nvp, el precio justo con el margen eliminado, que es el número que un lector compara con el precio que sigue ofreciéndose en otro sitio.
Cairns Dolphins v Sunshine Coast Phoenix
Basketball · Moneyline · Away
2.86 → 2.70 (−5.59%)
fair 3.04 · Australia NBL1 Women
Cuatro líneas cortas se leen bien en un móvil y en una lista de canales. Imprime el precio justo como n/a cuando nvp sea nulo, en lugar de convertir un valor ausente en un cero. Deja la marca de tiempo al cliente de chat; cada mensaje ya lleva una.
Reintentos del lado del webhook
Los webhooks fallan de tres maneras y cada una pide una reacción distinta. Un 429 significa que se está publicando en el canal más rápido de lo que la plataforma permite; viene con una cabecera Retry-After, así que espera ese tiempo y envía el mismo mensaje otra vez. Un 5xx o un timeout es transitorio; reintenta con un retraso que se duplica, con un tope de 30 segundos y de tres intentos. Un 400 significa que el propio cuerpo fue rechazado, y ningún reintento lo arreglará: registra la forma del payload y sigue adelante.
Una ráfaga de alertas durante una cartelera grande es cuando llega el 429. Dos ajustes absorben la mayor parte: publica un mensaje por evento en lugar de uno por resultado, y mantén un cooldown por selección para que un precio que sigue cayendo no publique cada pocos segundos. Las reglas de deduplicación y cooldown cubren las claves que usar.
Cuando el stream termina
Las conexiones se caen. Cuando el stream se cierra, reconecta tras una pausa corta que crece con los fallos repetidos, y revisa el plan cuando el primer mensaje de control informe de un error. Las alertas que cayeron mientras estabas desconectado no se reenvían, así que un hueco sigue siendo un hueco; las selecciones que importan vuelven a alertar la próxima vez que crucen tu umbral. La página de configuración de SSE cubre el formato de los frames y el bucle de reconexión en detalle.
Las caídas en vivo y prepartido llegan por streams separados. Un solo proceso de relay puede mantener ambas conexiones y publicar en dos canales, lo que mantiene una deriva lenta del prepartido fuera del canal que vigila los movimientos en juego. Si el destino es un móvil y no un canal, el bot de Telegram en pnclDATA es el mismo bucle con un POST distinto al final.
Preguntas antes de construirlo
¿El relay necesita un plan de pago?
Sí. El stream de caídas viene con el plan de alertas SSE a 99 USD al mes y con los dos planes combinados de REST y SSE a 149 y 229 USD. La clave gratuita es solo REST y no puede abrir el stream.
¿Un relay puede servir a varios canales?
Sí. Filtra por sport o league después del parseo y dirige cada alerta al webhook de ese grupo. El stream no tiene un parámetro de deporte propio, así que el filtro vive en el relay.
¿Por qué el mismo partido se publicó dos veces?
Un precio que sigue cayendo puede cruzar el umbral más de una vez, y cada cruce es una alerta nueva. Omite las repeticiones por el id de la alerta y mantén un cooldown por evento y resultado.
Los campos del stream y los precios de los planes siguen la documentación publicada por el proveedor, revisada el 26 de septiembre de 2026. Publicado el .