On the wire · 04:45:57 UTC Live 550 · Prematch 14,363 · Markets 56,936 Vol. I · No. 5 · Friday 13 November 2026 wss://pinnfeed.io/v1/stream
PinnFeed
Respuesta · Python · WebSocket

WebSocket de cuotas Pinnacle: ejemplo en Python

Actualizado el · PinnFeed · 2 min de lectura

Respuesta: instala websockets, define PINNFEED_KEY, conéctate a wss://pinnfeed.io/v1/stream con la cabecera x-api-key, envía un mensaje subscribe, aplica cada snapshot/delta, responde a ping con {"type":"pong"} y reconecta con backoff exponencial. Necesitas el plan Builder (€99/mes): las claves Free y Hobby reciben 403 plan_lacks_ws.

Cliente mínimo#

pip install websockets
export PINNFEED_KEY="ps_live_..."
import asyncio, json, os, random
import websockets

WS = "wss://pinnfeed.io/v1/stream"
KEY = os.environ["PINNFEED_KEY"]

async def main():
    delay = 1
    while True:
        try:
            async with websockets.connect(WS, additional_headers={"x-api-key": KEY}, max_size=None) as ws:
                await ws.send(json.dumps({
                    "type": "subscribe",
                    "sports": ["soccer", "tennis"],
                    "markets": ["moneyline"],
                    "main": True,
                    "specials": False,
                }))
                async for raw in ws:
                    msg = json.loads(raw)
                    if msg["type"] == "ping":
                        await ws.send('{"type":"pong"}')
                    elif msg["type"] == "snapshot" and msg.get("final"):
                        print("snapshot listo")
                        delay = 1
                    elif msg["type"] == "delta":
                        for c in msg["changes"]:
                            if c["kind"] == "market" and c["op"] == "upsert":
                                m = c["market"]
                                if (m["maxStake"] or 0) >= 100:
                                    print(m["id"], [(o["name"], o["decimal"], o["fair"]) for o in m["outcomes"]])
        except (OSError, websockets.ConnectionClosed) as e:
            print("desconectado", e, "reintento en", delay, "s")
        await asyncio.sleep(delay + random.random())
        delay = min(delay * 2, 30)

asyncio.run(main())

Campos de cada resultado: decimal, american, fair (sin margen), fairProb. El id de mercado es eventId:key. El filtro maxStake >= 100 descarta mercados con poca liquidez. Lista completa de frames: docs del WebSocket.

Códigos de cierre#

CódigoSignificado
4002 no_subscriptionNingún subscribe en 30 s
4008 slow_consumerCliente demasiado lento (búfer del servidor por encima de 16 MB)
4001 key_revokedClave revocada: no reconectes en bucle

Builder: prueba de 3 días desde precios; se requiere tarjeta y se cobra después del día 3 salvo que canceles. O empieza con una clave REST gratuita. Ver también push o polling y arranque de cuenta en Python.

Contenido educativo para mayores de 18 años: documentación técnica, no pronósticos ni promesas de ganancia.

Preguntas frecuentes#

¿Por qué mi clave Free recibe 403 en el WebSocket?#

Free y Hobby son solo REST. Pasa a Builder para el push, o consulta /v1/odds en Free (30 s de retraso) u Hobby (tiempo real).

¿Tengo que responder a los ping?#

Sí. El servidor envía ping cada 20 segundos; sin pong durante 60 s, corta la conexión.

¿Cuántas conexiones?#

Builder permite 3 simultáneas y Pro 10. Por encima: 429 connection_limit.

El plan WebSocket: Builder, 99 €/mes.

Cuotas de Pinnacle en tiempo real por un único WebSocket: los 13 deportes, todos los mercados, cuotas justas sin margen y cuotas de cierre. 3 días gratis y cancelas con un clic.

Form K-1 · Free API key

Get your free API key.

One field. No password, no card: enter your email, click the link we send, and your key is on screen.

By continuing you agree to the Terms and Privacy Policy.

One free key per email. Link valid for 20 minutes.