On the wire · 04:46:01 UTC Live 550 · Prematch 14,363 · Markets 56,922 Vol. I · No. 5 · Friday 13 November 2026 wss://pinnfeed.io/v1/stream
PinnFeed
Réponse · Python · WebSocket

WebSocket des cotes Pinnacle : exemple Python

Mis à jour le · PinnFeed · 2 min de lecture

Réponse : installez websockets, définissez PINNFEED_KEY, connectez-vous à wss://pinnfeed.io/v1/stream avec l'en-tête x-api-key, envoyez un message subscribe, appliquez chaque snapshot/delta, répondez à ping par {"type":"pong"} et reconnectez-vous avec un backoff exponentiel. Il faut le plan Builder (99 €/mois) : les clés Free et Hobby reçoivent 403 plan_lacks_ws.

Client minimal#

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 prêt")
                        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("déconnecté", e, "nouvel essai dans", delay, "s")
        await asyncio.sleep(delay + random.random())
        delay = min(delay * 2, 30)

asyncio.run(main())

Champs de chaque issue : decimal, american, fair (sans marge), fairProb. L'id de marché vaut eventId:key. Le filtre maxStake >= 100 écarte les marchés peu liquides. Liste complète des frames : docs WebSocket.

Codes de fermeture#

CodeSens
4002 no_subscriptionAucun subscribe dans les 30 s
4008 slow_consumerClient trop lent (tampon serveur au-delà de 16 Mo)
4001 key_revokedClé révoquée : ne reconnectez pas en boucle

Builder : essai de 3 jours depuis les tarifs ; une carte est requise et elle est débitée après le jour 3 sauf annulation. Ou commencez par une clé REST gratuite. Voir aussi push ou polling.

Contenu éducatif pour adultes (18+) : documentation technique, ni pronostics ni promesse de gain.

Questions fréquentes#

Pourquoi ma clé Free reçoit-elle 403 sur le WebSocket ?#

Free et Hobby sont en REST uniquement. Passez à Builder pour le push, ou interrogez /v1/odds sur Free (30 s de retard) ou Hobby (temps réel).

Dois-je répondre aux ping ?#

Oui. Le serveur envoie ping toutes les 20 secondes ; sans pong pendant 60 s, la connexion est coupée.

Combien de connexions ?#

Builder en autorise 3 simultanées, Pro 10. Au-delà : 429 connection_limit.

Le plan WebSocket : Builder, 99 €/mois.

Les cotes Pinnacle en temps réel sur un seul WebSocket : les 13 sports, tous les marchés, cotes justes sans marge et cotes de clôture. 3 jours gratuits, résiliable en 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.