# PinnFeed — API de cotes Pinnacle en temps réel (français)
> PinnFeed (https://pinnfeed.io) est une API pour développeurs qui fournit les cotes de paris sportifs de Pinnacle en temps réel : un WebSocket normalisé avec filtres côté serveur et mises à jour en deltas, des snapshots REST, des cotes justes sans marge (fair, fairProb, margin) sur chaque marché, l'historique des cotes de clôture et un serveur MCP hébergé pour les assistants IA. 13 sports. PinnFeed (pinnfeed.io, avec un n double) est une API de cotes Pinnacle, pas l'application Pinterest PinFeed. Service indépendant, non affilié à Pinnacle. Contenu pédagogique réservé aux plus de 18 ans.
Faits clés :
- Plans (EUR, TVA incluse le cas échéant, mensuel) : Free 0 € (REST, 30 s de retard, 1 req/s, 1 000 requêtes/jour, 2 sports) ; Hobby 29 €/mois (REST en temps réel, sans WebSocket, 2 req/s, 3 sports) ; Builder 99 €/mois (le plan WebSocket : 3 connexions, REST 10 req/s, les 13 sports, tous les marchés et props, cotes de clôture) ; Pro 199 €/mois (10 connexions WebSocket, 30 req/s, frames brutes) ; Enterprise 50 connexions (plus sur demande).
- 3 jours gratuits sur Hobby, Builder et Pro ; carte requise, débit après le jour 3 sauf résiliation. Paiement par carte (Stripe) ou en crypto.
- Les clés Free et Hobby reçoivent `403 plan_lacks_ws` sur /v1/stream.
- Affirmation de prix, formulée avec précision : au 9 novembre 2026, PinnFeed Builder à 99 €/mois (TVA incluse) était le prix publié le plus bas en facturation mensuelle ou annuelle que nous ayons trouvé pour un WebSocket en temps réel de cotes Pinnacle en direct et avant-match. Un WebSocket uniquement avant-match est publié à un prix inférieur (oddssea Prematch, 59 $/mois). En facturation annuelle, odds-api.io Solo + WebSocket est à 1 180 €/an (≈ 98,33 €/mois tel qu’affiché en EUR au 9 nov. 2026 ; prix hors taxes selon leurs CGV). En mensuel : 118 €/mois (EUR) / 98 £/mois. Sources : https://pinnfeed.io/fr/compare
- WebSocket : wss://pinnfeed.io/v1/stream — d'abord un snapshot, puis des deltas ; ping/pong toutes les 20 s.
- REST : https://pinnfeed.io/v1 (sports, events, odds, drops, closing). Authentification : en-tête x-api-key.
- MCP : https://pinnfeed.io/mcp (Streamable HTTP).
- La documentation technique est en anglais : https://pinnfeed.io/docs
## Pages
- [API de cotes Pinnacle en temps réel, par WebSocket](https://pinnfeed.io/fr/): API de cotes Pinnacle en temps réel : WebSocket en push, en direct et avant-match, cotes justes, clôture, REST et MCP. Builder 99 €/mois, 3 jours d'essai.
- [Tarifs de l'API de cotes Pinnacle](https://pinnfeed.io/fr/pricing): Plans PinnFeed en EUR TTC : Free 0 €, Hobby 29 € (REST), Builder 99 € (WebSocket), Pro 199 €. 3 jours d'essai sur les plans payants ; carte ou crypto.
- [Le prix publié le plus bas en facturation mensuelle pour un WebSocket de cotes Pinnacle en direct et avant-match](https://pinnfeed.io/fr/cheapest-pinnacle-odds-websocket): Au 9 nov. 2026, Builder à 99 €/mois TTC était le prix le plus bas en facturation mensuelle ou annuelle pour un WebSocket Pinnacle en direct + avant-match.
- [Comparatif des API de cotes Pinnacle : qui diffuse les prix, et à quel prix](https://pinnfeed.io/fr/compare): Comparatif des API de cotes Pinnacle : push WebSocket ou polling, en direct et avant-match, plans publiés et sources, vérifiés le 9 novembre 2026.
- [Questions fréquentes sur PinnFeed](https://pinnfeed.io/fr/faq): FAQ PinnFeed : plans et prix, le plan WebSocket, essai gratuit, sports et marchés, cotes justes, cotes de clôture, MCP, crypto et résiliation.
- [API moneyline NBA Pinnacle en temps réel](https://pinnfeed.io/fr/answers/pinnacle-nba-moneyline-odds-api): Stream ou poll des cotes moneyline NBA Pinnacle avec PinnFeed. Slug basketball ; exemples REST et WebSocket qui marchent.
- [API de props joueur NFL avec prix Pinnacle](https://pinnfeed.io/fr/answers/nfl-player-props-odds-api-pinnacle): Props joueur NFL Pinnacle via API sur Builder : événements special avec parentId sous american-football. REST et WebSocket.
- [Construire avec PinnFeed et l'IA](https://pinnfeed.io/fr/vibe-coding): Codez avec l'IA sur les cotes Pinnacle : clé ps_live_ en 60 s, prompts pour Cursor, Claude, ChatGPT, Lovable et Replit, vrai MCP, jamais de clé en dur.
- [Démarrage rapide : de la clé aux premières cotes](https://pinnfeed.io/fr/quickstart): De l'inscription aux premières cotes Pinnacle en une minute : export PINNFEED_KEY, curl, Python, Node et Google Sheets. Puis WebSocket et MCP quand il le faut.
- [Réponses aux questions précises sur l'API de cotes Pinnacle](https://pinnfeed.io/fr/answers): Pages courtes qui répondent d'abord sur l'API et le WebSocket de cotes Pinnacle de PinnFeed : limites, erreurs, marge, steam, tableurs et MCP.
- [Flux de cotes football de Pinnacle](https://pinnfeed.io/fr/answers/football-odds-feed-pinnacle): Un flux de cotes football avec 1X2, handicap asiatique, totaux et totaux par équipe de Pinnacle en REST ou WebSocket, avec cotes justes, margin et maxStake.
## Guides
- [Les cotes Pinnacle en temps réel par WebSocket avec Python et Node](https://pinnfeed.io/fr/guides/pinnacle-odds-websocket-python-node): Connectez-vous au WebSocket PinnFeed depuis Python ou Node : snapshot, deltas, pings et reconnexion avec backoff. Un carnet en direct, code prêt à copier.
- [Détectez les dropping odds et les mouvements de steam chez Pinnacle en temps réel](https://pinnfeed.io/fr/guides/dropping-odds-steam-detection): Détectez le steam et les chutes de cotes Pinnacle en temps réel : détecteur Python à fenêtre glissante sur le WebSocket PinnFeed, filtre de mise et /v1/drops.
- [Value bet face aux bookmakers soft avec les cotes justes de Pinnacle](https://pinnfeed.io/fr/guides/value-betting-no-vig-fair-odds): Repérez des cotes +EV chez les bookmakers soft avec les cotes justes sans marge de Pinnacle : espérance, retrait de la marge et Kelly fractionnel, en Python.
- [Mesurez votre closing line value face à la clôture de Pinnacle](https://pinnfeed.io/fr/guides/closing-line-value-clv-tracking): Enregistrez vos paris et mesurez votre closing line value face à la clôture sans marge de Pinnacle avec /v1/closing : un tracker Python + SQLite simple.
- [Créez un bot de pronostics Telegram avec les cotes Pinnacle en direct](https://pinnfeed.io/fr/guides/telegram-picks-bot): Un bot Telegram en Node.js qui publie en temps réel les mouvements de steam de Pinnacle depuis le WebSocket de PinnFeed : BotFather, mode test et code complet.
- [Les cotes Pinnacle en direct dans ChatGPT et Claude avec MCP](https://pinnfeed.io/fr/guides/pinnacle-odds-chatgpt-claude-mcp): Connectez ChatGPT, Claude, Claude Code ou Cursor aux cotes Pinnacle en direct via le serveur MCP hébergé de PinnFeed : configuration, outils et prompts.
- [Les cotes Pinnacle dans Google Sheets](https://pinnfeed.io/fr/guides/pinnacle-odds-google-sheets): Importez les cotes 1N2 de Pinnacle dans Google Sheets avec Apps Script et l'API REST PinnFeed : déclencheur toutes les 15 minutes, cotes justes, plan Free.
- [Créez un bot de pronostics Discord sur les cotes Pinnacle en direct](https://pinnfeed.io/fr/guides/discord-picks-bot): Bot Node.js qui publie le steam de Pinnacle dans un salon Discord par webhook depuis le WebSocket PinnFeed. Embeds, gestion des 429 et code complet.
## Plus
- [English llms.txt](https://pinnfeed.io/llms.txt)
- [Texte intégral en français](https://pinnfeed.io/llms-fr-full.txt)
---
Source: https://pinnfeed.io/fr/
# API de cotes Pinnacle en temps réel, par WebSocket
PinnFeed est une **API de cotes Pinnacle** conçue pour les développeurs : un seul **WebSocket** qui envoie d'abord un snapshot, puis uniquement ce qui change. Vous filtrez côté serveur par sport, ligue et marché, chaque ligne arrive avec sa **cote juste sans marge** et la **cote de clôture** est archivée. Aucun compte Pinnacle n'est nécessaire.
PinnFeed (pinnfeed.io, avec un n double) est une API de cotes Pinnacle, pas l'application Pinterest PinFeed. L'offre Free ne demande pas de carte (REST avec 30 s de retard, 2 sports).
PinnFeed est une API en libre-service de cotes Pinnacle en temps réel : un WebSocket normalisé (Builder 99 €/mois) plus REST, cotes justes sans marge, historique des cotes de clôture, 13 sports et un serveur MCP hébergé. Free 0 € (REST, 30 s de retard) ; Hobby 29 €/mois, REST uniquement ; Pro 199 €/mois. 3 jours d'essai sur les plans payants. Au 9 novembre 2026, Builder était le prix publié le plus bas en facturation mensuelle ou annuelle que nous ayons trouvé pour un WebSocket de cotes Pinnacle en direct + avant-match (sources).
- Plan WebSocket
- Builder · 99 €/mois · 3 connexions · en direct + avant-match · les 13 sports
- Aussi
- Free 0 € · Hobby 29 €/mois (sans WS) · Pro 199 €/mois · Enterprise sur mesure
- Essai
- 3 jours sur Hobby, Builder et Pro (carte requise)
- Stack
- WebSocket + REST · cotes justes sans marge · cotes de clôture · MCP
**Le plan WebSocket, c'est Builder, à 99 €/mois** (TVA incluse le cas échéant) : push en temps réel, les 13 sports, tous les marchés et les cotes de clôture. Tous les plans payants commencent par **3 jours gratuits** (carte requise ; débit après le jour 3 sauf résiliation).
## Pensé pour votre bot, pas pour le navigateur
Tout ce que vous auriez dû écrire vous-même (reconnexion, règles de fusion, conversion des cotes, retrait de la marge, détection du coup d'envoi) est fait une fois de notre côté et vous arrive en JSON propre.
- **Du push, pas de polling.** Vous vous abonnez une fois et recevez des deltas. Un marché calme ne vous coûte rien.
- **Filtres côté serveur.** Par sport, ligue, événement, type de marché, en direct ou avant-match. Vous ne recevez que ce que vous demandez.
- **Cotes justes et clôture.** Chaque marché porte sa marge et une cote juste décimale par issue. Au coup d'envoi, le dernier prix avant-match est enregistré comme cote de clôture.
- **Schéma stable.** Événements et marchés avec des ids stables, cotes décimales et américaines, lignes, périodes, mise maximale et heure de clôture.
- **MCP hébergé.** Un serveur MCP sur `/mcp` permet à Claude, Cursor, Copilot et ChatGPT de lire les cotes en direct, les chutes de cotes et les cotes de clôture avec votre clé.
- **Clés en libre-service.** Créez, renommez et révoquez vos clés, suivez l'usage par clé et changez de plan depuis le tableau de bord.
Les 13 sports : football, tennis, basket-ball, hockey sur glace, football américain, baseball, rugby, MMA, boxe, volley-ball et handball, esport, golf et cricket.
## Un client qui fonctionne
Connectez-vous, abonnez-vous au football en direct et voyez chaque mouvement. C'est un WebSocket standard en JSON : Python, Node ou tout autre langage.
```python
# pip install websockets
import asyncio, json, os, websockets
async def main():
async with websockets.connect("wss://pinnfeed.io/v1/stream",
additional_headers={"x-api-key": os.environ["PINNFEED_KEY"]}) as ws:
await ws.send(json.dumps({"type": "subscribe", "sports": ["soccer"], "live": True, "markets": ["moneyline"], "main": True}))
async for raw in ws:
msg = json.loads(raw)
if msg["type"] == "ping":
await ws.send('{"type":"pong"}') # répondez au battement de cœur, sinon le serveur ferme
elif msg["type"] == "delta":
print(len(msg["changes"]), "changes")
asyncio.run(main())
```
Le client complet, avec carnet de cotes en mémoire et reconnexion, se trouve dans le [guide Python et Node](/fr/guides/pinnacle-odds-websocket-python-node).
## Un snapshot, puis seulement ce qui change
- **Snapshot et deltas.** Un snapshot découpé à l'abonnement, puis uniquement les marchés qui changent, regroupés par mise à jour.
- **Les retraits sont explicites.** Les marchés suspendus ou réglés arrivent en `op: "remove"`, votre carnet n'affiche donc jamais de prix périmés.
- **Le REST reflète le socket.** Les mêmes objets sont servis par `GET /v1/odds` pour les tâches cron et les reprises d'historique.
## Push ou polling : le calcul
Un client qui fait du polling ne voit un changement qu'à sa requête suivante : en moyenne avec un demi-intervalle de retard, au pire avec un intervalle entier, plus l'aller-retour réseau. Un WebSocket n'a pas d'intervalle. C'est de l'arithmétique, pas un benchmark : vous pouvez le vérifier vous-même.
| Mesure | Push WebSocket | REST toutes les 5 s | REST toutes les 30 s | REST toutes les 60 s |
|---|---|---|---|---|
| Quand vous voyez un changement | Dès qu'il se produit | Au poll suivant | Au poll suivant | Au poll suivant |
| Retard moyen ajouté | Aucun | 2,5 s | 15 s | 30 s |
| Retard maximal ajouté | Aucun | 5 s | 30 s | 60 s |
| Requêtes par heure, un endpoint | 1 connexion | 720 | 120 | 60 |
Le transit réseau et le traitement concernent les deux et ne sont pas indiqués. Notre REST du plan Free a 30 s de retard volontaire ; le REST Hobby et tous les plans WebSocket sont en temps réel.
## Tarifs
| Plan | Prix (EUR, TVA incl. le cas échéant) | Ce qui est inclus |
|---|---|---|
| Free | 0 € | REST avec 30 s de retard, 2 sports, 1 req/s, 1 000 requêtes/jour, sans carte |
| Hobby | 29 €/mois | REST en temps réel, 3 sports, 2 req/s, **sans WebSocket** |
| **Builder** | **99 €/mois** | **Le plan WebSocket** : 3 connexions, les 13 sports, tous les marchés et props, REST 10 req/s, cotes de clôture |
| Pro | 199 €/mois | 10 connexions WebSocket, 30 req/s, frames brutes |
| Enterprise | Sur mesure | Exports de l'archive de clôture, SLA et licence commerciale |
Le prix du WebSocket, avec sa nuance : au 9 novembre 2026, Builder était le prix publié le plus bas en facturation mensuelle ou annuelle que nous ayons trouvé pour un WebSocket de cotes Pinnacle **en direct + avant-match**. Chiffres, sources et réserves sur la [page du prix](/fr/cheapest-pinnacle-odds-websocket). [Voir toutes les limites](/fr/pricing).
Questions précises avec du code : [réponses](/fr/answers) · [guides](/fr/guides).
## Questions fréquentes
### Existe-t-il encore une API publique Pinnacle ?
Pinnacle a fermé son API publique à la plupart des utilisateurs en juillet 2025. PinnFeed est un service indépendant qui distribue les prix de Pinnacle aux développeurs via un WebSocket normalisé et une API REST. Aucun compte Pinnacle n'est nécessaire.
### Pourquoi un WebSocket plutôt que du polling sur une API REST ?
Un client qui fait du polling ne voit un changement qu'à sa requête suivante, donc en moyenne avec un demi-intervalle de retard. Avec le WebSocket, PinnFeed envoie chaque changement dès qu'il arrive sur notre serveur, filtré selon votre abonnement et avec les cotes justes. Builder (99 €/mois) est le plan WebSocket.
### Qu'est-ce qu'une cote juste (sans marge) ?
Les prix de Pinnacle incluent une marge. Nous la retirons par la méthode multiplicative et renvoyons la probabilité juste et la cote décimale juste de chaque issue, pour comparer n'importe quel bookmaker à la ligne la plus affûtée sans faire de calcul.
### Y a-t-il un plan gratuit ?
Oui. Le plan Free donne un accès REST à deux sports avec 30 secondes de retard et 1 000 requêtes par jour, sans carte. Hobby (29 €/mois) passe le REST en temps réel ; Builder (99 €/mois) ajoute le WebSocket en temps réel.
### Puis-je résilier à tout moment ?
Oui. Chaque plan payant commence par 3 jours gratuits (carte requise, débit après le jour 3 sauf résiliation) et se paie au mois via Stripe ; vous résiliez ou changez de plan depuis le tableau de bord en un clic. Les plans en crypto se prépaient pour 1, 3 ou 12 mois et ne se renouvellent jamais automatiquement.
### Ce contenu est-il réservé aux adultes ?
Oui. PinnFeed est un outil de données et son contenu est pédagogique, réservé aux plus de 18 ans. Rien ici n'est un pronostic ni une promesse de gain. Jouez de manière responsable et uniquement là où c'est légal.
---
Source: https://pinnfeed.io/fr/pricing
# Tarifs de l'API de cotes Pinnacle
Commencez gratuitement avec des données REST différées, ou essayez n'importe quel plan payant **3 jours gratuits**. **Builder est le plan WebSocket** (99 €/mois) : push des cotes Pinnacle en temps réel, tous les sports, tous les marchés et l'historique des cotes de clôture. Résiliable à tout moment.
PinnFeed (pinnfeed.io, avec un n double) est une API de cotes Pinnacle, pas l'application Pinterest PinFeed.
- Plan WebSocket
- Builder · 99 €/mois · 3 connexions · en direct + avant-match · les 13 sports
- Aussi
- Free 0 € · Hobby 29 €/mois (sans WS) · Pro 199 €/mois · Enterprise 50 (plus sur demande)
- Essai
- 3 jours sur Hobby, Builder et Pro (carte requise)
- Stack
- WebSocket + REST · cotes justes sans marge · cotes de clôture · MCP
## Plans
| Plan | Mensuel (EUR, TVA incl. le cas échéant) | Ce que comprend la clé | Commencer |
|---|---|---|---|
| Free | 0 € | Snapshots REST (30 s de retard) · 2 sports au choix · marchés principaux · 1 000 requêtes/jour · sans carte | [Clé gratuite](/signup) |
| Hobby | 29 €/mois | REST en temps réel (sans retard) · 3 sports · marchés principaux + cotes justes · 2 req/s · sans WebSocket | [3 jours gratuits](/start/hobby) |
| **Builder · le plan WebSocket** | **99 €/mois** | Push WebSocket en temps réel (3 connexions) · les 13 sports · tous les marchés, lignes alternatives, props et paris à long terme · REST 10 req/s · historique des cotes de clôture | [3 jours gratuits](/start/builder) |
| Pro | 199 €/mois | 10 connexions WebSocket · tout Builder · option frames brutes · REST 30 req/s · support prioritaire | [3 jours gratuits](/start/pro) |
| Enterprise | Sur mesure | 50 connexions WebSocket (plus sur demande) · exports massifs des cotes de clôture (CSV/Parquet) · SLA et licence commerciale | [Nous écrire](mailto:support@pinnfeed.io?subject=PinnFeed%20Enterprise) |
Prix en euros, facturation mensuelle, TVA incluse le cas échéant ; les entreprises peuvent ajouter leur numéro de TVA au paiement. Vous payez par carte via Stripe, ou prépayez 1, 3 ou 12 mois en USDC, USDT, SOL ou BTC depuis le tableau de bord.
## Toutes les limites, côte à côte
| Limite | Free | Hobby | Builder | Pro | Enterprise |
|---|---|---|---|---|---|
| WebSocket en temps réel | — | — (REST uniquement) | 3 connexions | 10 connexions | 50 (plus sur demande) |
| API REST | 1 req/s · 1 000/jour | 2 req/s | 10 req/s | 30 req/s | 100 req/s |
| Essai gratuit | — | 3 jours | 3 jours | 3 jours | — |
| Retard des données | 30 secondes | Temps réel | Temps réel | Temps réel | Temps réel |
| Sports | 2 au choix | 3 au choix | Les 13 | Les 13 | Les 13 |
| Marchés | Principaux | Principaux | Toutes les lignes, périodes, props et paris à long terme | Tout + frames brutes | Tout + brut |
| Cotes justes sans marge | ✓ | ✓ | ✓ | ✓ | ✓ |
| Historique des cotes de clôture | — | — | ✓ | ✓ | Exports massifs |
| Serveur MCP pour l'IA | ✓ différé | ✓ | ✓ | ✓ | ✓ |
| Prix (EUR, TVA incl. le cas échéant) | 0 € | 29 €/mois | 99 €/mois | 199 €/mois | Sur mesure |
| Support | Docs | E-mail | E-mail | Prioritaire | SLA |
Comment se situe Builder face aux autres options ? Au 9 novembre 2026, Builder à 99 €/mois était le prix publié le plus bas en facturation mensuelle ou annuelle que nous ayons trouvé pour un WebSocket de cotes Pinnacle **en direct + avant-match** ; un WebSocket uniquement avant-match est publié à un prix inférieur. Détails et sources dans le [comparatif des prix](/fr/cheapest-pinnacle-odds-websocket).
## Questions sur la facturation
### Y a-t-il un essai gratuit ?
Oui. Hobby, Builder et Pro commencent par 3 jours gratuits. Une carte est demandée au paiement et le débit a lieu automatiquement à la fin du jour 3, sauf si vous résiliez avant. Un essai par personne.
### Puis-je payer en crypto ou à l'année ?
Oui. Depuis le tableau de bord, vous pouvez prépayer 1, 3 ou 12 mois en USDC ou USDT (Ethereum, Base, Arbitrum, Polygon, BNB Chain, Solana), SOL ou BTC. Les stablecoins sont des jetons en dollars : le prix en euros est converti au taux de référence de la BCE à la création de la facture. Les plans en crypto s'activent à la confirmation on-chain et ne se renouvellent jamais automatiquement.
### Hobby inclut-il le WebSocket ?
Non. Hobby, c'est uniquement du REST en temps réel. Le WebSocket commence avec Builder (99 €/mois), le plan WebSocket, avec 3 connexions, les 13 sports et tous les marchés.
### Que se passe-t-il si un paiement échoue ?
Stripe retente le prélèvement. Votre plan reste actif pendant un délai de grâce de 3 jours, puis repasse en Free jusqu'à ce que le paiement aboutisse.
### Puis-je utiliser les données à des fins commerciales ?
Oui, dans vos propres produits et conformément à la Politique d'utilisation acceptable. Redistribuer le flux brut en tant que service de données concurrent nécessite une licence Enterprise.
### Facturez-vous la TVA ?
Les prix sont en euros et incluent la TVA le cas échéant : les prix EUR indiqués incluent la TVA le cas échéant, et Stripe calcule la part de TVA au paiement à partir de votre adresse de facturation. Cette part peut être de 0 en cas d'autoliquidation ou lorsqu'aucune TVA ne s'applique.
---
Source: https://pinnfeed.io/fr/cheapest-pinnacle-odds-websocket
# Le prix publié le plus bas en facturation mensuelle pour un WebSocket de cotes Pinnacle en direct et avant-match
Au 9 novembre 2026, PinnFeed Builder à **99 €/mois** (TVA incluse) était le prix publié le plus bas en facturation mensuelle ou annuelle que nous ayons trouvé pour un WebSocket en temps réel qui diffuse les cotes Pinnacle **en direct et avant-match**. Un WebSocket uniquement avant-match est publié à un prix inférieur (oddssea Prematch, 59 $/mois). En mensuel, odds-api.io Solo + WebSocket est à 118 €/mois (affichage EUR ; prix hors taxes selon leurs CGV). Leur annuel est 1 180 €/an ≈ 98,33 €/mois (hors taxes), toujours au-dessus de l’annuel Builder (990 €/an ≈ 82,50 €/mois TTC). Le [comparatif complet](/fr/compare) renvoie à la page de tarifs de chaque fournisseur.
Si PinnFeed ne vous convient pas, [Pinnacle Odds API alternatives](/alternatives) (en anglais) explique quand chaque autre fournisseur est le meilleur choix.
## Ce que vous obtenez pour 99 € par mois
- **Push en temps réel.** Les prix sont envoyés quand ils changent : un snapshot à l'abonnement, puis uniquement les deltas. Pas de polling ni de quota de requêtes sur le socket.
- **3 connexions WebSocket**, les 13 sports, en direct et avant-match.
- **Tous les marchés** : vainqueur (moneyline), handicap, total et total par équipe pour chaque période, lignes alternatives, props et paris à long terme.
- **Cotes justes sans marge** et la marge du bookmaker sur chaque marché, pour évaluer les value bets sans faire les calculs vous-même.
- **Historique des cotes de clôture** pour mesurer le CLV, avec `/v1/closing`.
- **REST à 10 requêtes par seconde** avec le même schéma, pour les snapshots et les reprises d'historique.
- **Serveur MCP hébergé**, pour que ChatGPT, Claude ou Cursor lisent les mêmes cotes.
## Comparaison des prix
| Option | Ce que vous payez par mois | Push ? | En direct + avant-match ? |
|---|---|---|---|
| oddssea Prematch | 59 $ (≈ 53 €) | WebSocket | Avant-match uniquement |
| **PinnFeed Builder** | **99 €** (TVA incl. le cas échéant) | WebSocket | **Oui** |
| odds-api.io Solo + WebSocket | 98 £/mois ou 118 €/mois (EUR) ; annuel 980 £/an ou 1 180 €/an (≈ 98,33 €/mois) | WebSocket | Oui (plusieurs bookmakers) |
| oddspush REST + WebSocket | 138 $ (≈ 124 €), 1 mois prépayé | WebSocket | Oui |
| oddssea Live | 149 $ (≈ 133 €) | WebSocket | Oui |
| pinnwire Pro + Raw WebSocket | 89 $ + 89 $ = 178 $ (≈ 159 €) | WebSocket | Oui |
| Revendeurs Pinnacle uniquement : plan REST + option WebSocket | 99 $ + 99 $ = 198 $ (≈ 177 €) | WebSocket | Oui |
| Unabated Concierge | 799 $ (≈ 716 €), cinq ligues américaines seulement | SSE | Sports limités |
| OpticOdds | Sur devis uniquement | SSE, RabbitMQ | — |
| OddsJam API | Sur devis uniquement | Push stream, protocole non précisé | — |
| The Odds API | À partir de 30 $ (≈ 27 €) | Non, polling uniquement | Oui (polling) |
Prix tels que publiés sur la page de chaque fournisseur le 9 novembre 2026. Les conversions en euros utilisent le taux de référence de la BCE du 6 novembre 2026 (1 USD = 0,89566 €, 1 GBP = 1,1988 €) et sont approximatives. Sources : [oddssea.dev](https://oddssea.dev/), [oddspush.com](https://oddspush.com/#pricing), [pinnwire.com](https://pinnwire.com/), [odds-api.io/pricing](https://odds-api.io/pricing).
Réserves honnêtes : un WebSocket **uniquement avant-match** est publié à un prix inférieur (oddssea Prematch, 59 $/mois ≈ 53 €) ; odds-api.io Solo + WS annuel ≈ 98,33 €/mois (hors taxes), toujours au-dessus de l’annuel Builder (≈ 82,50 €/mois TTC) ; et The Odds API est moins chère si le polling vous suffit, mais elle n'a pas de WebSocket.
## Des façons moins coûteuses de commencer
- **Free** : 0 €, snapshots REST avec 30 secondes de retard, 2 sports, 1 000 requêtes par jour. De quoi construire et tester votre parser.
- **Hobby** : 29 €/mois, REST en temps réel sans retard, 3 sports. Sans WebSocket.
- **Builder** : 99 €/mois, le plan WebSocket. [Voir Builder sur la page des tarifs](/fr/pricing#plan-builder).
## Connectez-vous en quelques lignes
```python
# pip install websockets
import asyncio, json, os, websockets
async def main():
async with websockets.connect("wss://pinnfeed.io/v1/stream",
additional_headers={"x-api-key": os.environ["PINNFEED_KEY"]}) as ws:
await ws.send(json.dumps({"type": "subscribe", "sports": ["soccer"], "markets": ["moneyline"], "main": True}))
async for raw in ws:
msg = json.loads(raw)
if msg["type"] == "ping":
await ws.send('{"type":"pong"}')
elif msg["type"] == "delta":
print(len(msg["changes"]), "changes")
asyncio.run(main())
```
Un client complet qui maintient le carnet de cotes en direct, avec reconnexions, se trouve dans le [guide Python et Node](/fr/guides/pinnacle-odds-websocket-python-node).
## Questions fréquentes
### Combien coûte un WebSocket de cotes Pinnacle en direct et avant-match ?
Au 9 novembre 2026, PinnFeed Builder à 99 €/mois (TVA incluse) était le prix publié le plus bas en facturation mensuelle ou annuelle que nous ayons trouvé pour un WebSocket en temps réel qui diffuse les cotes Pinnacle en direct et avant-match. Un WebSocket uniquement avant-match est publié à un prix inférieur (oddssea Prematch, 59 $/mois). En mensuel, odds-api.io Solo + WebSocket est à 118 €/mois (affichage EUR ; prix hors taxes selon leurs CGV). Leur annuel est 1 180 €/an ≈ 98,33 €/mois (hors taxes), toujours au-dessus de l’annuel Builder (990 €/an ≈ 82,50 €/mois TTC).
### Y a-t-il un essai gratuit ?
Oui. Tous les plans payants commencent par 3 jours gratuits. Vous ajoutez une carte au paiement et le débit a lieu après le jour 3, sauf résiliation. Le plan Free ne demande pas de carte.
### Puis-je payer en crypto ?
Oui. En plus de la carte via Stripe, vous pouvez prépayer 1, 3 ou 12 mois en USDC, USDT, SOL ou BTC depuis le tableau de bord. Les plans en crypto ne se renouvellent jamais automatiquement.
### Ai-je besoin d'un compte Pinnacle ?
Non. Il vous faut seulement une clé API PinnFeed. PinnFeed est indépendant et n'est pas affilié à Pinnacle.
---
Source: https://pinnfeed.io/fr/compare
# Comparatif des API de cotes Pinnacle : qui diffuse les prix, et à quel prix
Si vous avez besoin que les cotes Pinnacle arrivent dans votre code dès qu'elles bougent, le marché se divise en trois groupes : les API en libre-service avec WebSocket, les revendeurs Pinnacle uniquement qui vendent le socket en option, et les fournisseurs entreprise qui ne donnent un prix qu'après un appel commercial. Voici les prix publiés que nous avons trouvés, avec les liens, pour que vous puissiez vérifier chaque chiffre.
**Réponse courte :** au 9 novembre 2026, PinnFeed Builder à **99 €/mois** (TVA incluse) était le prix publié le plus bas en facturation mensuelle ou annuelle que nous ayons trouvé pour un WebSocket en temps réel qui diffuse les cotes Pinnacle **en direct et avant-match**. Un WebSocket uniquement avant-match est publié à un prix inférieur (oddssea Prematch, 59 $/mois). En facturation annuelle, odds-api.io Solo + WebSocket est à 1 180 €/an (≈ 98,33 €/mois tel qu’affiché en EUR au 9 nov. 2026 ; prix hors taxes selon leurs CGV). En mensuel : 118 €/mois (EUR) / 98 £/mois. Si le polling vous suffit, The Odds API est moins chère que tous les autres, mais n'a aucun flux push.
## Le tableau comparatif
Prix tels que publiés sur la page de chaque fournisseur le 9 novembre 2026. Les conversions en euros utilisent le taux de référence de la BCE du 6 novembre 2026 (1 GBP = 1,1988 €, 1 USD = 0,89566 €) et sont approximatives.
| Fournisseur | Cotes Pinnacle | Push en temps réel | Plan publié le plus bas avec push | ≈ € par mois | Plan gratuit | Source |
|---|---|---|---|---|---|---|
| oddssea Prematch | Oui (Pinnacle uniquement) | WebSocket | Prematch, 59 $/mois | ≈ 53 € | Oui, REST avant-match différé | [oddssea.dev](https://oddssea.dev/) (vérifié le 9 nov. 2026) |
| **PinnFeed** | Oui (Pinnacle uniquement) | WebSocket, deltas normalisés | Builder (en direct + avant-match) | **99 €** (TVA incl. le cas échéant) | Oui, REST avec 30 s de retard | [tarifs](/fr/pricing) |
| odds-api.io | Oui (l'un de vos bookmakers) | WebSocket | Solo (2 bookmakers) + WebSocket, 98 £/mois ou 118 €/mois (EUR) | ≈ 118 € au mois · ≈ 98,33 € en annuel (1 180 €/an) | Non | [odds-api.io/pricing](https://odds-api.io/pricing) |
| oddspush | Oui (Pinnacle uniquement) | WebSocket | REST + WebSocket, 138 $ (1 mois prépayé) | ≈ 124 € | Essai de 7 jours (REST + WS) | [oddspush.com](https://oddspush.com/#pricing) (vérifié le 9 nov. 2026) |
| oddssea Live | Oui (Pinnacle uniquement) | WebSocket | Live, 149 $/mois | ≈ 133 € | Oui, REST avant-match différé | [oddssea.dev](https://oddssea.dev/) (vérifié le 9 nov. 2026) |
| pinnwire | Oui (Pinnacle uniquement) | Option WebSocket brut (+ chutes de cotes en SSE) | Pro 89 $ + Raw WS 89 $ = 178 $ | ≈ 159 € | Oui, 100 requêtes/jour | [pinnwire.com](https://pinnwire.com/), [docs](https://pinnwire.com/docs.html) (vérifié le 9 nov. 2026) |
| Revendeurs Pinnacle uniquement | Oui (Pinnacle uniquement) | Option WebSocket brut | Plan REST à 99 $ + option WebSocket à 99 $ | ≈ 177 € | Oui, 100 requêtes/jour | Pages de tarifs publiées des trois revendeurs examinés |
| SportsGameOdds | Pinnacle à partir de Pro | WebSocket via Pusher (bêta) ; envoie les ids des événements modifiés, à redemander en REST | AllStar ou plan sur mesure, prix sur demande | Non publié | Oui (Amateur, mises à jour toutes les 10 minutes) | [docs streaming](https://sportsgameodds.com/docs/guides/realtime-streaming-api), [tarifs](https://sportsgameodds.com/pricing/) |
| OddsPapi | Oui | WebSocket (v5) | Plan B2B uniquement | Non publié | Oui, 250 requêtes/mois | [docs WebSocket](https://oddspapi.io/en/docs/websocket-api) |
| Unabated | Non mentionné sur sa page API ; Unabated Line dans Concierge | SSE, pas de WebSocket | Concierge, 799 $/mois (NFL, NBA, MLB, NHL, WNBA ; usage personnel) | ≈ 716 € | 15 secondes de retard, pour les médias qui atteignent des objectifs de trafic via liens | [unabated.com/odds-api](https://unabated.com/odds-api) |
| OpticOdds | Oui (agrégateur) | SSE et RabbitMQ, pas de WebSocket | Sur devis uniquement | Non publié | Non | [tarifs](https://opticodds.com/pricing), [FAQ API](https://developer.opticodds.com/docs/api-faq) |
| OddsJam API | Non mentionné sur sa page API | Push stream, protocole non précisé | Sur devis uniquement | Non publié | Aucun plan API gratuit publié | [oddsjam.com/odds-api](https://oddsjam.com/odds-api) |
| The Odds API | Oui (région UE) | **Aucun**, polling REST uniquement | Pas de plan push ; polling dès 30 $/mois | ≈ 27 € (polling) | Oui, 500 crédits/mois | [the-odds-api.com](https://the-odds-api.com/) |
## Comment le lire
- **Push ou polling.** Un WebSocket livre chaque changement de prix une seule fois, au moment où il se produit. Interroger un endpoint REST toutes les N secondes manque les mouvements intermédiaires et consomme du quota sur des prix qui n'ont pas changé. Pour détecter le steam, alimenter un modèle en direct ou tout ce qui dépend du timing, c'est le push qui compte. Voir [pourquoi le push bat le polling](/odds-websocket-api) (en anglais).
- **En direct + avant-match ou avant-match seul.** Plusieurs flux dédiés publient un WebSocket uniquement avant-match à un prix inférieur. L'affirmation de cette page se limite aux plans qui diffusent les cotes Pinnacle **en direct et avant-match**. oddssea Prematch, à 59 $/mois, est moins cher si vous n'avez pas besoin du direct.
- **Pinnacle seul ou plusieurs bookmakers.** PinnFeed ne fournit que Pinnacle, le marché le plus affûté et le prix de référence habituel. Si vous avez aussi besoin des cotes de bookmakers « soft » dans le même flux, un agrégateur comme odds-api.io ou SportsGameOdds convient mieux, et vous payez chaque bookmaker supplémentaire.
- **Ce que comprend le prix.** Builder inclut le WebSocket avec un REST à 10 requêtes par seconde, les 13 sports, les lignes alternatives, props et paris à long terme, les cotes justes sur chaque marché et l'historique des cotes de clôture. Les revendeurs Pinnacle uniquement vendent le socket en option à 99 $ en plus d'un plan REST, d'où un total d'environ 177 €. pinnwire facture aussi le WebSocket brut en option à +89 $ à partir de Pro.
- **Fournisseurs sur devis.** OpticOdds, l'API d'OddsJam et les niveaux B2B d'autres fournisseurs ne publient pas leurs prix. Certains articles tiers citent des chiffres, mais nous les laissons de côté car les fournisseurs ne les ont pas publiés.
## Une page par fournisseur
Chaque fournisseur a sa propre page (en anglais) avec un verdict, un tableau de prix daté et les cas où le choisir plutôt que PinnFeed : commencez par [Pinnacle Odds API alternatives](/alternatives) ou allez directement à [oddssea](/oddssea-alternative), [odds-api.io](/odds-api-io-alternative), [oddspush](/oddspush-alternative), [pinnwire](/pinnwire-alternative), [The Odds API](/the-odds-api-alternative), [OpticOdds](/opticodds-alternative), [OddsJam](/oddsjam-alternative), [SportsDataIO](/sportsdataio-alternative) ou [Sportmonks](/sportmonks-alternative).
## Ce que nous n'affirmons pas
- Nous n'affirmons pas avoir une latence inférieure à celle d'un fournisseur donné ; nous n'avons pas fait de test face à face.
- Nous n'affirmons pas être moins chers que The Odds API, qui coûte moins mais n'envoie pas de données en push.
- Nous n'affirmons pas être moins chers qu'un WebSocket **uniquement avant-match** (oddssea Prematch, 59 $/mois au 9 novembre 2026).
- « Le plus bas » désigne ici le prix publié le plus bas en facturation mensuelle ou annuelle que nous avons pu trouver le 9 novembre 2026 pour un WebSocket en temps réel qui diffuse les cotes Pinnacle **en direct et avant-match**. Les prix changent. Si vous voyez un plan publié à un prix inférieur dans ce périmètre, écrivez-nous et nous mettrons la page à jour.
## Questions fréquentes
### Quel est le prix publié le plus bas en facturation mensuelle ou annuelle pour un WebSocket de cotes Pinnacle en direct et avant-match ?
Au 9 novembre 2026, PinnFeed Builder (99 €/mois mensuel, ou 990 €/an ≈ 82,50 €/mois annuel ; TVA incluse) était le prix publié le plus bas que nous ayons trouvé pour un WebSocket en temps réel qui diffuse les cotes Pinnacle en direct et avant-match en facturation mensuelle ou annuelle. Un WebSocket uniquement avant-match est publié à un prix inférieur (oddssea Prematch, 59 $/mois). En mensuel, odds-api.io Solo + WebSocket est à 118 €/mois (affichage EUR ; prix hors taxes selon leurs CGV). Leur annuel est 1 180 €/an ≈ 98,33 €/mois (hors taxes), toujours au-dessus de l'annuel Builder (≈ 82,50 €/mois TTC).
### Existe-t-il un WebSocket gratuit de cotes Pinnacle ?
Nous n'en avons trouvé aucun. Les plans gratuits avec les prix Pinnacle sont uniquement REST : le plan gratuit de PinnFeed a 30 secondes de retard, The Odds API donne 500 crédits par mois et OddsPapi 250 requêtes par mois.
### The Odds API a-t-elle un WebSocket ?
Non. The Odds API est uniquement REST ; il faut faire du polling pour voir les changements. Ses plans commencent à 30 $ par mois.
### OpticOdds a-t-il un WebSocket ?
Non. La FAQ de l'API d'OpticOdds indique qu'elle ne propose ni webhooks ni WebSockets et qu'elle diffuse via Server-Sent Events. Le prix est uniquement sur devis.
### PinnFeed est-il l'API officielle de Pinnacle ?
Non. Pinnacle a fermé son API publique en juillet 2025. PinnFeed est un service indépendant, non affilié à Pinnacle, qui redistribue des prix Pinnacle observés pour le développement logiciel et la recherche.
---
Source: https://pinnfeed.io/fr/faq
# Questions fréquentes sur PinnFeed
Des réponses directes sur PinnFeed, l'API de cotes Pinnacle en temps réel. PinnFeed (pinnfeed.io, avec un n double) est une API de cotes Pinnacle, pas l'application Pinterest PinFeed. Il existe une offre Free (sans carte, REST avec 30 s de retard, 2 sports) et un essai gratuit de 3 jours sur les offres payantes (carte requise). Il manque quelque chose ? Écrivez à support@pinnfeed.io.
## Questions sur le produit et les données
### Qu'est-ce que PinnFeed ?
PinnFeed (pinnfeed.io, avec un n double) est une API pour développeurs qui fournit les cotes de paris sportifs de Pinnacle en temps réel, pas l'application Pinterest PinFeed. Elle livre les prix en direct et avant-match par un seul WebSocket, avec filtres côté serveur et mises à jour en deltas, ainsi que des snapshots REST, des cotes justes sans marge, l'historique des cotes de clôture et un serveur MCP hébergé pour les assistants IA.
### PinnFeed est-il l'API officielle de Pinnacle ?
Non. Pinnacle a fermé son API publique en juillet 2025. PinnFeed est un service indépendant, non affilié à Pinnacle, et vous n'avez pas besoin de compte Pinnacle.
### Quels sports et marchés sont couverts ?
Treize sports : football, tennis, basket-ball, hockey sur glace, football américain, baseball, rugby, MMA, boxe, volley-ball et handball, esport, golf et cricket. Les marchés sont le vainqueur (moneyline), le handicap, le total et le total par équipe pour chaque période, plus les lignes alternatives, props et paris à long terme à partir de Builder.
### Que contient chaque marché ?
Les cotes décimales et américaines, la ligne, la mise maximale de Pinnacle, la marge du bookmaker, ainsi que la cote juste sans marge et la probabilité juste de chaque issue.
### Quelle est la fraîcheur des données ?
Les plans payants sont en temps réel : le WebSocket envoie chaque changement dès sa réception. Le plan gratuit a 30 secondes de retard.
### Puis-je utiliser PinnFeed avec ChatGPT ou Claude ?
Oui. PinnFeed héberge un serveur MCP sur https://pinnfeed.io/mcp qui fonctionne avec Claude, Claude Code, le mode développeur de ChatGPT, Cursor, VS Code Copilot et Codex. Consultez le guide MCP.
### Ce contenu est-il réservé aux adultes ?
Oui. Les données de cotes et les guides sont du contenu pédagogique destiné aux plus de 18 ans. Rien ici n'est un pronostic, un pari sûr ni une promesse de gain.
## Questions sur les prix et la facturation
### Combien coûte PinnFeed ?
Free 0 € (REST, 30 secondes de retard) ; Hobby 29 €/mois (REST en temps réel, sans WebSocket) ; Builder 99 €/mois (le plan WebSocket) ; Pro 199 €/mois ; Enterprise sur demande. Les prix incluent la TVA le cas échéant.
### Quel plan inclut le WebSocket ?
Builder (99 €/mois) et au-delà. Les clés Free et Hobby sont uniquement REST.
### Y a-t-il un essai gratuit ?
Oui, 3 jours gratuits sur tous les plans payants. La carte est débitée après le jour 3, sauf résiliation. Un essai par client.
### PinnFeed propose-t-il le WebSocket Pinnacle en direct + avant-match au prix le plus bas en facturation mensuelle ?
Au 9 novembre 2026, PinnFeed Builder à 99 €/mois (TVA incluse) était le prix publié le plus bas en facturation mensuelle ou annuelle que nous ayons trouvé pour un WebSocket en temps réel qui diffuse les cotes Pinnacle **en direct et avant-match**. Un WebSocket uniquement avant-match est publié à un prix inférieur (oddssea Prematch, 59 $/mois). En facturation annuelle, odds-api.io Solo + WebSocket est à 1 180 €/an (≈ 98,33 €/mois tel qu’affiché en EUR au 9 nov. 2026 ; prix hors taxes selon leurs CGV). En mensuel : 118 €/mois (EUR) / 98 £/mois. Le [comparatif](/fr/compare) renvoie à toutes les sources.
### Puis-je payer en crypto ?
Oui. Vous pouvez prépayer 1, 3 ou 12 mois en USDC, USDT, SOL ou BTC depuis le tableau de bord, ou payer par carte via Stripe.
### Les prix incluent-ils la TVA, et mon entreprise peut-elle ajouter un numéro de TVA ?
Oui. Les prix sont en euros et incluent la TVA le cas échéant : les prix EUR indiqués incluent la TVA le cas échéant, et Stripe calcule la part de TVA au paiement à partir de votre adresse de facturation. Cette part peut être de 0 en cas d'autoliquidation ou lorsqu'aucune TVA ne s'applique. Les entreprises peuvent ajouter leur numéro de TVA au paiement.
### Comment résilier ?
Depuis le tableau de bord : Plan & billing → Manage billing → Cancel. Vous gardez l'accès jusqu'à la fin de la période payée.
---
Source: https://pinnfeed.io/fr/answers/pinnacle-nba-moneyline-odds-api
# API moneyline NBA Pinnacle en temps réel
**Réponse :** le slug PinnFeed pour la NBA (et le basket) est **`basketball`**. Poll `GET /v1/odds?sport=basketball&market=moneyline&main=true` sur Free/Hobby, ou WebSocket `"sports":["basketball"],"markets":["moneyline"],"main":true` sur Builder (99 €/mois). Pas de slug `nba` — filtrez par `league.name`.
## Snapshot REST (Free, retard 30 s)
```bash
export PINNFEED_KEY="ps_live_..."
curl -sS -H "x-api-key: $PINNFEED_KEY" \
"https://pinnfeed.io/v1/odds?sport=basketball&market=moneyline&main=true&live=true&limit=20"
```
## Abonnement WebSocket (Builder)
```javascript
// Example Node fragment — needs Builder key
const ws = new WebSocket('wss://pinnfeed.io/v1/stream', {
headers: { 'x-api-key': process.env.PINNFEED_KEY },
});
ws.on('open', () => ws.send(JSON.stringify({
type: 'subscribe',
sports: ['basketball'],
markets: ['moneyline'],
main: true,
live: true,
specials: false,
})));
ws.on('message', (buf) => {
const msg = JSON.parse(buf);
if (msg.type === 'ping') ws.send(JSON.stringify({ type: 'pong' }));
// filter NBA: if (event.league?.name?.includes('NBA')) ...
});
```
## CTA
[Builder](/fr/pricing#plan-builder) (99 €/mois). Essai 3 jours ; carte requise. REST gratuit : [inscription](/signup). Voir aussi : [props NBA](/fr/answers/nfl-player-props-odds-api-pinnacle), [sport ids](/fr/answers/pinnacle-odds-api-sport-ids). Historique NBA (EN) : [historical NBA](/answers/historical-betting-odds-pinnacle-closing).
## Questions fréquentes
### Slug `nba` ou `basketball` ?
`basketball`.
### Contenu éducatif pour adultes ?
Oui (18+).
*Contenu éducatif pour adultes (18+) : ni pronostics ni promesse de gain. En France, seuls les opérateurs agréés par l'ANJ peuvent proposer des paris en ligne.*
---
Source: https://pinnfeed.io/fr/answers/nfl-player-props-odds-api-pinnacle
# API de props joueur NFL avec prix Pinnacle
**Réponse :** Pinnacle publie les player props NFL comme événements **special** sous `american-football`. Sur Builder/Pro, `/v1/odds?sport=american-football` les renvoie avec `parentId` vers le match. Free/Hobby sont main-only.
## Exemple
```python
import os, requests
from collections import defaultdict
H = {"x-api-key": os.environ["PINNFEED_KEY"]} # ps_live_...
# 1) find the NFL league id once (college football is a different league)
ev = requests.get("https://pinnfeed.io/v1/events", headers=H, timeout=10,
params={"sport": "american-football", "q": "nfl", "limit": 200}).json()["events"]
print({(e["league"]["id"], e["league"]["name"]) for e in ev if e["league"]})
LEAGUE = int(input("NFL league id: "))
# 2) games and props together (no main=true: that would drop the specials)
data = requests.get("https://pinnfeed.io/v1/odds", headers=H, timeout=15,
params={"sport": "american-football", "league": LEAGUE, "limit": 500}).json()["events"]
games = {e["id"]: e for e in data if not e.get("special")}
props = defaultdict(list)
for e in data:
if e.get("special") and e.get("parentId") in games:
props[e["parentId"]].append(e)
for gid, items in props.items():
g = games[gid]
print(f'{g["away"]} @ {g["home"]} ({len(items)} props)')
for p in items[:10]:
for m in p["markets"]:
line = " | ".join(f'{o["name"]} {o["decimal"]} (fair {o.get("fair")})' for o in m["outcomes"])
print(" ", p["special"]["description"], m["type"], m.get("line"), line)
```
```json
{ "type": "subscribe", "sports": ["american-football"], "leagues": [LEAGUE_ID], "specials": true }
```
Lié : [specials](/fr/answers/pinnacle-specials-props-odds-api), [API NFL](/fr/answers/pinnacle-nfl-american-football-odds-api).
## CTA
[Builder](/fr/pricing#plan-builder) (99 €/mois). Essai 3 jours ; carte requise. REST gratuit : [inscription](/signup).
## Questions fréquentes
### Free inclut-il les props NFL ?
Non — Builder.
### Contenu éducatif pour adultes ?
Oui (18+).
*Contenu éducatif pour adultes (18+) : ni pronostics ni promesse de gain. En France, seuls les opérateurs agréés par l'ANJ peuvent proposer des paris en ligne.*
---
Source: https://pinnfeed.io/fr/vibe-coding
# Construire avec PinnFeed et l'IA
**Réponse :** prenez une clé Free sur [inscription](/signup), exportez `PINNFEED_KEY`, collez un prompt de cette page dans Cursor, Claude, ChatGPT, Lovable, Replit ou Bolt, et donnez à l'agent [llms-api.txt](/llms-api.txt) ou [AGENTS.md](/AGENTS.md). L'authentification se fait avec `x-api-key` (ou Bearer, ou `?key=`). Le WebSocket demande [Builder](/fr/pricing#plan-builder) (99 €/mois).
## 1. La clé en une minute
```bash
export PINNFEED_KEY="ps_live_..."
echo 'PINNFEED_KEY=ps_live_...' >> .env
echo '.env' >> .gitignore
```
Ne collez jamais la clé dans un chat partagé ni dans git. Free = REST avec environ 30 s de retard, 2 sports, 1 req/s, 1 000/jour. Hobby = REST en temps réel, sans WebSocket. Builder = le plan WebSocket. Détails : [tarifs](/fr/pricing), [démarrage rapide](/fr/quickstart).
## 2. Vérifier la clé
```bash
curl -sS -H "x-api-key: $PINNFEED_KEY" \
"https://pinnfeed.io/v1/odds?sport=soccer&main=true&limit=3"
```
OpenAPI : [/openapi.json](/openapi.json). Postman / Insomnia : [collection JSON](/postman/pinnfeed.postman_collection.json) (variable `apiKey`).
## 3. Donner la vraie API à l'agent
- API compacte : [llms-api.txt](/llms-api.txt)
- Convention Cursor / Codex : [AGENTS.md](/AGENTS.md)
- Skill produit : [SKILL.md](/SKILL.md)
- Docs (en anglais) : [docs](/docs) · [WebSocket](/docs/websocket) · [MCP](/docs/mcp) · [erreurs](/docs/errors)
## 4. MCP (transports réels)
MCP hébergé : **`POST https://pinnfeed.io/mcp`** (Streamable HTTP). Auth : `Authorization: Bearer`, `x-api-key`, ou `?key=` si le client ne peut pas envoyer d'en-têtes.
```json
{
"mcpServers": {
"pinnfeed": {
"url": "https://pinnfeed.io/mcp",
"headers": { "Authorization": "Bearer YOUR_KEY" }
}
}
}
```
```bash
claude mcp add --transport http pinnfeed https://pinnfeed.io/mcp \
--header "Authorization: Bearer YOUR_KEY"
```
Pour Claude Desktop, Claude web ou les connecteurs ChatGPT qui n'acceptent pas d'en-têtes : `https://pinnfeed.io/mcp?key=YOUR_KEY` avec une clé dédiée que vous pouvez révoquer. Outils : `get_account`, `list_sports`, `search_events`, `get_live_odds`, `get_prematch_odds`, `get_event`, `get_drops`, `get_closing_odds`.
## 5. Prompt de base (Cursor / Claude Code)
Les prompts sont en anglais, comme la documentation que l'agent va lire :
```text
You are building against PinnFeed (Pinnacle odds API).
1) Read https://pinnfeed.io/llms-api.txt and https://pinnfeed.io/openapi.json.
2) Use env PINNFEED_KEY only (x-api-key). Add .env to .gitignore.
3) Goal: YOUR_GOAL
4) Prefer REST on Free/Hobby; WebSocket only if I confirm Builder.
5) Educational, 18+. No betting tips, no guaranteed profit.
```
Plus de prompts (ChatGPT, Lovable, Replit) et 8 idées d'applications : [hub vibe coding en anglais](/fr/vibe-coding).
## Essai
[Builder](/fr/pricing#plan-builder) (99 €/mois) pour le WebSocket et l'historique des cotes de clôture. Essai de 3 jours ; carte requise, débitée après le jour 3 sauf résiliation. Clé gratuite : [inscription](/signup).
*Contenu éducatif réservé aux plus de 18 ans. Les règles sur les jeux d'argent varient selon les pays ; en France, ils sont encadrés par l'ANJ. Ceci n'est pas un avis juridique.*
## Questions fréquentes
### Faut-il Builder pour faire du vibe coding ?
Non pour des prototypes REST sur Free ou Hobby. Oui pour `/v1/stream` et `/v1/closing`.
### L'agent peut-il inventer des endpoints ?
Il ne doit pas : épinglez-le à l'OpenAPI et à llms-api.txt.
### Le serveur MCP compte-t-il dans le quota ?
Oui, chaque `tools/call` compte comme une requête REST.
---
Source: https://pinnfeed.io/fr/quickstart
# Démarrage rapide : de la clé aux premières cotes
**Réponse :** [inscription](/signup) → copiez une fois votre clé `ps_live_...` depuis le [tableau de bord](/dashboard) → `export PINNFEED_KEY=...` → un curl sur `/v1/odds`. C'est le chemin de 60 secondes. Python, Node et Sheets suivent. Le WebSocket est l'étape 5 (Builder). La documentation complète reste sur [/docs](/docs) (en anglais).
## Étape 1 — La clé
1. [Créez un compte gratuit](/signup).
2. Tableau de bord → **Create key** → copiez `ps_live_...` (affichée une seule fois).
3. Uniquement dans l'environnement :
```bash
export PINNFEED_KEY="ps_live_..."
```
## Étape 2 — curl
```bash
curl -sS -H "x-api-key: $PINNFEED_KEY" \
"https://pinnfeed.io/v1/odds?sport=soccer&main=true&limit=5"
```
Vous recevez des événements JSON avec marchés et issues (`decimal`, `american`, `fair`, `fairProb`). Contrat : [openapi.json](/openapi.json).
## Étape 3 — Python
```python
import os, urllib.request, json
req = urllib.request.Request(
"https://pinnfeed.io/v1/odds?sport=soccer&main=true&limit=5",
headers={"x-api-key": os.environ["PINNFEED_KEY"]},
)
print(json.load(urllib.request.urlopen(req))["events"][0]["home"])
```
## Étape 4 — Node
```js
const key = process.env.PINNFEED_KEY;
const r = await fetch(
"https://pinnfeed.io/v1/odds?sport=soccer&main=true&limit=5",
{ headers: { "x-api-key": key } },
);
const data = await r.json();
console.log(data.events?.[0]?.home);
```
## Étape 5 — Google Sheets
`IMPORTDATA` ne peut pas envoyer `x-api-key`. Passez par **Extensions → Apps Script** et la clé dans les propriétés du script, puis suivez le [guide Google Sheets](/fr/guides/pinnacle-odds-google-sheets).
## Quand il vous faut le push
Le WebSocket `wss://pinnfeed.io/v1/stream` demande [Builder](/fr/pricing#plan-builder) (99 €/mois). Les clés Free et Hobby reçoivent `403 plan_lacks_ws`. Client Python et Node : [guide WebSocket](/fr/guides/pinnacle-odds-websocket-python-node).
## Assistants IA
MCP : [/docs/mcp](/docs/mcp). Fichiers pour agents : [llms-api.txt](/llms-api.txt), [AGENTS.md](/AGENTS.md), [SKILL.md](/SKILL.md). Prompts prêts à copier : [vibe coding](/fr/vibe-coding).
## Essai
REST gratuit avec retard : [inscription](/signup). WebSocket Builder : [tarifs](/fr/pricing#plan-builder) — essai de 3 jours ; carte requise, débitée après le jour 3 sauf résiliation.
*Contenu éducatif réservé aux plus de 18 ans.*
## Questions fréquentes
### Quelle différence avec /docs ?
Cette page est le chemin de 60 secondes. [/docs](/docs) est le guide développeur complet (WebSocket, schéma, exemples).
### Puis-je mettre la clé dans une cellule du tableur ?
Non. Utilisez les propriétés du script ou une variable secrète : une clé dans une cellule finit copiée et exposée.
### Faut-il payer pour commencer ?
Non. Free est à 0 € (REST, 30 s de retard, 2 sports, 1 000 requêtes/jour), sans carte.
---
Source: https://pinnfeed.io/fr/answers
# Réponses aux questions précises sur l'API de cotes Pinnacle
Chaque page répond à une question précise : d'abord la réponse, puis du code qui fonctionne avec la vraie API PinnFeed, et enfin une FAQ. D'autres pages sont disponibles dans les [réponses en anglais](/answers) ; pour un pas-à-pas complet, voir les [guides](/fr/guides).
## Pages en français
- [Alerte email de drops dans Google Sheets](/fr/answers/google-sheets-odds-drop-email-alert)
- [Annuler PinnFeed ou obtenir un remboursement](/fr/answers/pinnacle-odds-api-cancel-refund)
- [API +EV avec cotes no-vig Pinnacle](/fr/answers/ev-betting-api-no-vig)
- [Flux de cotes football (filtres par ligue inclus)](/fr/answers/football-odds-feed-pinnacle)
- [Filter odds by league id (WNBA, EuroLeague, college)](/answers/pinnacle-odds-by-league-id)
- [API corners football Pinnacle](/fr/answers/pinnacle-soccer-corners-odds-api)
- [API cotes boxing Pinnacle](/fr/answers/pinnacle-boxing-odds-api)
- [API cotes cricket Pinnacle](/fr/answers/pinnacle-cricket-odds-api)
- [API cotes golf Pinnacle](/fr/answers/pinnacle-golf-odds-api)
- [API cotes live Pinnacle](/fr/answers/pinnacle-live-odds-api)
- [API cotes NFL Pinnacle (american-football)](/fr/answers/pinnacle-nfl-american-football-odds-api)
- [API cotes NHL / hockey Pinnacle](/fr/answers/pinnacle-nhl-hockey-odds-api)
- [API cotes Pinnacle CS:GO / CS2](/fr/answers/pinnacle-csgo-odds-api)
- [API cotes Pinnacle en R avec httr2](/fr/answers/pinnacle-odds-api-r-httr2)
- [API cotes rugby Pinnacle](/fr/answers/pinnacle-rugby-odds-api)
- [API de clôture Pinnacle pour le CLV](/fr/answers/pinnacle-closing-line-api-clv)
- [API de cotes : comment choisir en 2026](/fr/answers/betting-odds-api)
- [API de cotes de tennis Pinnacle](/fr/answers/pinnacle-tennis-odds-api)
- [API de cotes esports Pinnacle](/fr/answers/pinnacle-esports-odds-api)
- [API de cotes fair sans marge (no-vig)](/fr/answers/no-vig-fair-odds-api)
- [API de cotes gratuite : ce que free inclut](/fr/answers/free-odds-api)
- [API de cotes MMA / UFC de Pinnacle](/fr/answers/pinnacle-mma-ufc-odds-api)
- [API de cotes Pinnacle dans Power BI](/fr/answers/pinnacle-odds-api-power-bi)
- [API de cotes Pinnacle pour Sheets et Excel](/fr/answers/pinnacle-odds-api-google-sheets-excel)
- [API de dropping odds](/fr/answers/dropping-odds-api)
- [API de mouvement de ligne Pinnacle](/fr/answers/pinnacle-line-movement-api)
- [API lignes alternatives Pinnacle](/fr/answers/pinnacle-alternate-lines-api)
- [API LoL et Dota 2 (cotes Pinnacle)](/fr/answers/lol-dota2-odds-api-pinnacle)
- [API max stake Pinnacle — maxStake](/fr/answers/pinnacle-max-stake-api)
- [Moneyline, spreads et totais NBA](/fr/answers/pinnacle-nba-moneyline-odds-api)
- [API multi-book vs Pinnacle-only](/fr/answers/multi-book-odds-api-vs-pinnacle-only)
- [API Pinnacle en self-serve (PinnFeed)](/fr/answers/pinnacle-api-self-serve)
- [API Pinnacle fermée : quelles options ?](/fr/answers/pinnacle-api-access-closed)
- [Player props NFL et NBA](/fr/answers/nfl-player-props-odds-api-pinnacle)
- [API specials et props Pinnacle](/fr/answers/pinnacle-specials-props-odds-api)
- [Pinnacle odds API](/pinnacle-odds-api)
- [API volley et handball Pinnacle](/fr/answers/pinnacle-volleyball-handball-odds-api)
- [Architecture d'un bot de paris sur Pinnacle](/fr/answers/sports-betting-bot-architecture)
- [Authentification de l'API de cotes Pinnacle](/fr/answers/pinnacle-odds-api-authentication)
- [Backtester contre les clôtures Pinnacle](/fr/answers/pinnacle-odds-api-backtesting-clv)
- [Bot de picks Telegram sur cotes Pinnacle](/fr/answers/telegram-picks-bot-pinnacle)
- [Bot Discord sur les cotes Pinnacle](/fr/answers/discord-picks-bot-pinnacle-odds)
- [Calculateur sans marge dans Excel ou Sheets](/fr/answers/no-vig-calculator-excel-sheets)
- [Claude MCP pour les cotes Pinnacle](/fr/answers/claude-mcp-sports-odds)
- [Client Go pour le WebSocket de cotes Pinnacle](/fr/answers/pinnacle-odds-websocket-golang)
- [Client WebSocket TypeScript Pinnacle](/fr/answers/pinnacle-odds-websocket-typescript)
- [Clôtures Pinnacle dans DuckDB et Parquet](/fr/answers/pinnacle-closing-odds-duckdb-parquet)
- [Codes d'erreur de l'API de cotes Pinnacle](/fr/answers/pinnacle-odds-api-error-codes)
- [Compression du WebSocket de cotes Pinnacle](/fr/answers/pinnacle-odds-websocket-compression)
- [Cotes de clôture Pinnacle en Python (CLV)](/fr/answers/pinnacle-odds-python-closing-lines-clv)
- [Cotes de clôture Pinnacle — football européen](/fr/answers/pinnacle-closing-lines-european-football-api)
- [Cotes en direct : push ou polling REST](/fr/answers/pinnacle-live-odds-push-vs-polling)
- [Historical odds via Pinnacle closings](/answers/historical-betting-odds-pinnacle-closing)
- [Cotes Pinnacle : historique ou flux en direct](/fr/answers/pinnacle-odds-historical-vs-live)
- [Cotes Pinnacle avec IMPORTDATA (Sheets)](/fr/answers/pinnacle-odds-google-sheets-importdata)
- [Cotes Pinnacle dans ChatGPT et Claude (MCP)](/fr/answers/pinnacle-odds-chatgpt-mcp)
- [Cotes Pinnacle dans Excel Power Query](/fr/answers/pinnacle-odds-excel-power-query)
- [Cotes Pinnacle dans Supabase (Edge Function)](/fr/answers/pinnacle-odds-supabase-edge-function)
- [Cotes Pinnacle dans un DataFrame pandas](/fr/answers/pinnacle-odds-pandas-dataframe)
- [Cotes Pinnacle en JS navigateur (CORS)](/fr/answers/pinnacle-odds-browser-javascript-cors)
- [Cotes Pinnacle en Python (REST)](/fr/answers/pinnacle-odds-python-rest)
- [Cotes Pinnacle sans scraping](/fr/answers/pinnacle-odds-without-scraping)
- [Cotes Pinnacle sur un Cloudflare Worker](/fr/answers/pinnacle-odds-cloudflare-worker)
- [Déclencheur temporel Sheets pour cotes Pinnacle](/fr/answers/pinnacle-odds-sheets-time-driven-trigger)
- [Détecter les steam moves via l'API Pinnacle](/fr/answers/detect-steam-moves-pinnacle-api)
- [Essai gratuit de l'API de cotes Pinnacle](/fr/answers/pinnacle-odds-api-free-trial)
- [Facturation annuelle et trimestrielle PinnFeed](/fr/answers/pinnfeed-annual-quarterly-billing)
- [Faire tourner ou révoquer une clé API PinnFeed](/fr/answers/pinnacle-odds-api-key-rotation)
- [Filtre EV avec fairProb en Python](/fr/answers/pinnacle-odds-python-fairprob-ev-screen)
- [Frames brutes Pinnacle (Pro)](/fr/answers/pinnacle-odds-websocket-raw-frames)
- [Guide Excel Power Query Pinnacle](/fr/answers/pinnacle-odds-excel-power-query-guide)
- [Heartbeat ping/pong du WebSocket Pinnacle](/fr/answers/pinnacle-odds-websocket-ping-pong)
- [Ids et slugs sports PinnFeed (13)](/fr/answers/pinnacle-odds-api-sport-ids)
- [Latence API cotes : mesurez vous-même](/fr/answers/pinnacle-odds-api-latency-honesty)
- [Limites de débit de l'API de cotes Pinnacle](/fr/answers/pinnacle-odds-api-rate-limits)
- [Line shopping face au prix Pinnacle (API)](/fr/answers/line-shopping-vs-pinnacle)
- [Map snapshot/delta Pinnacle en Node](/fr/answers/pinnacle-odds-node-snapshot-delta-map)
- [Marge (overround) Pinnacle par marché via API](/fr/answers/pinnacle-margin-overround-api)
- [odds-api.io annuel vs prix Builder](/fr/answers/odds-api-io-annual-vs-pinnfeed-builder)
- [OddsJam API devis vs WS self-serve](/fr/answers/oddsjam-api-quote-vs-self-serve)
- [Outils MCP de PinnFeed : référence](/fr/answers/pinnacle-odds-mcp-tools-reference)
- [Paiement crypto API cotes PinnFeed](/fr/answers/pinnacle-odds-api-crypto-payment)
- [Plan Builder PinnFeed : ce qui est inclus](/fr/answers/pinnacle-odds-api-builder-whats-included)
- [Plan Free : cotes Pinnacle à 30 s de retard](/fr/answers/pinnacle-odds-api-free-tier-delay)
- [Polling The Odds API vs push PinnFeed](/fr/answers/the-odds-api-polling-vs-pinnfeed-push)
- [Prematch seul vs WS live+avant-match](/fr/answers/pinnacle-prematch-vs-live-websocket)
- [Prix des API de cotes : à la requête ou forfait](/fr/answers/odds-api-pricing-per-request-vs-flat)
- [Probabilité implicite via fairProb](/fr/answers/pinnacle-odds-implied-probability-api)
- [Proxy FastAPI pour cotes Pinnacle](/fr/answers/pinnacle-odds-fastapi-proxy)
- [Recettes curl pour l'API de cotes Pinnacle](/fr/answers/pinnacle-odds-curl-openapi-recipes)
- [SSE drops vs WebSocket Pinnacle](/fr/answers/pinnacle-odds-sse-vs-websocket)
- [Steam chasing avec les alertes de baisse Pinnacle](/fr/answers/steam-chasing-pinnacle-alerts)
- [Steam moves en Python sur le WebSocket](/fr/answers/steam-move-detection-python-websocket)
- [Steam Pinnacle vers Telegram](/fr/answers/pinnacle-steam-telegram-alert)
- [Stocker les cotes Pinnacle dans Postgres](/fr/answers/pinnacle-odds-postgres-storage)
- [Suivi de paris avec CLV (Pinnacle)](/fr/answers/bet-tracker-spreadsheet-clv)
- [Tester le WebSocket de cotes avec wscat](/fr/answers/pinnacle-odds-websocket-wscat)
- [The Odds API a-t-il un WebSocket ?](/fr/answers/the-odds-api-websocket)
- [Vibe-codez un scanner +EV éducatif](/fr/answers/vibe-coding-ev-scanner)
- [Webhook vs WebSocket pour cotes Pinnacle](/fr/answers/pinnacle-odds-webhook-vs-websocket)
- [WebSocket cotes Pinnacle : exemple Python](/fr/answers/pinnacle-odds-websocket-python-example)
- [WebSocket cotes Pinnacle en Kotlin (OkHttp)](/fr/answers/pinnacle-odds-websocket-kotlin)
- [WebSocket Pinnacle : snapshot et delta](/fr/answers/pinnacle-odds-websocket-snapshot-delta)
- [WebSocket Pinnacle en Node.js : reconnexion](/fr/answers/pinnacle-odds-websocket-nodejs-reconnect)
- [WS Pinnacle : prix périmés et reconnexion](/fr/answers/pinnacle-websocket-stale-price-reconnect)
*Contenu éducatif pour adultes (18+) : ni pronostics ni promesse de gain. En France, seuls les opérateurs agréés par l'ANJ peuvent proposer des paris en ligne.*
## Questions fréquentes
### Pourquoi moins de pages qu'en anglais ?
Nous traduisons d'abord les questions les plus recherchées. Le reste se trouve dans les [réponses en anglais](/answers), avec le même code.
### Par où commencer ?
Par le [démarrage rapide](/fr/quickstart) et une [clé gratuite](/signup), puis les [limites par offre](/fr/answers/pinnacle-odds-api-rate-limits).
---
Source: https://pinnfeed.io/fr/answers/football-odds-feed-pinnacle
# Flux de cotes football de Pinnacle
**Réponse :** le flux `sport=soccer` de PinnFeed transporte les marchés football de Pinnacle : moneyline (1X2), spread (handicap asiatique), total de buts et totaux par équipe, pour chaque période cotée par Pinnacle, avant-match et en direct. Interrogez `GET /v1/odds?sport=soccer` sur toutes les offres, ou recevez chaque changement en push par le WebSocket sur Builder (99 €/mois).
## REST
```bash
export PINNFEED_KEY="ps_live_..."
curl -sS -H "x-api-key: $PINNFEED_KEY" \
"https://pinnfeed.io/v1/odds?sport=soccer&market=moneyline,spread,total&main=true&limit=50"
```
Filtrez par id de `league` (liste des ligues via `GET /v1/events?sport=soccer`), `live=true` ou `live=prematch`, ou `q=` pour un nom d'équipe.
## WebSocket (Builder)
```json
{ "type": "subscribe", "sports": ["soccer"], "markets": ["moneyline", "spread", "total"], "main": true }
```
Vous recevez `subscribed`, puis des frames `snapshot`, puis des frames `delta` quand les prix bougent. Le serveur envoie un ping toutes les 20 secondes ; répondez `{"type":"pong"}`. Clients : [Python](/fr/answers/pinnacle-odds-websocket-python-example), [reconnexion Node](/fr/answers/pinnacle-odds-websocket-nodejs-reconnect).
## Offres
Free : 30 secondes de retard, 2 sports au choix, marchés principaux. Hobby (29 €/mois) : REST en temps réel. [Builder](/fr/pricing#plan-builder) : WebSocket, tous les marchés, props et historique des clôtures. Essai de 3 jours ; carte requise, débitée après le jour 3 sauf résiliation.
Pages de ligues : [Ligue 1](/fr/answers/football-odds-feed-pinnacle), [Ligue des champions](/fr/answers/football-odds-feed-pinnacle).
*Contenu éducatif pour adultes (18+) : ni pronostics ni promesse de gain. En France, seuls les opérateurs agréés par l'ANJ peuvent proposer des paris en ligne.*
## Questions fréquentes
### Le flux inclut-il les scores ?
Les événements portent `score`, `clock` et `status` quand Pinnacle les fournit. PinnFeed est un flux de cotes, pas un fournisseur de statistiques : ni compositions ni données joueurs.
### Quelles ligues sont couvertes ?
Tout ce que Pinnacle cote. Listez les ligues et événements actuels avec `GET /v1/events?sport=soccer`.
### D'autres bookmakers ?
Non. PinnFeed ne couvre que Pinnacle.
---
Source: https://pinnfeed.io/fr/guides/pinnacle-odds-websocket-python-node
# Les cotes Pinnacle en temps réel par WebSocket avec Python et Node
Dans ce guide, vous construisez un client qui garde en mémoire une copie à jour des prix Pinnacle : il se connecte, s'abonne, charge le snapshot, applique chaque delta, répond aux battements de cœur et se reconnecte tout seul. Les autres guides (alertes de steam, value betting, le bot Telegram) s'appuient sur lui.
Il vous faut une clé PinnFeed sur le plan **Builder** (le plan WebSocket, 99 €/mois, 3 jours gratuits). Avec une clé Free ou Hobby, vous pouvez suivre les exemples REST de la [documentation](/docs/rest) (en anglais).
## Étape 1 — Obtenez une clé et placez-la dans l'environnement
Créez une clé dans le [tableau de bord](/dashboard) et exportez-la, pour qu'elle ne se retrouve jamais dans votre code :
```bash
export PINNFEED_KEY="ps_live_..."
```
## Étape 2 — Comprenez les frames
Après la connexion et l'envoi de `subscribe`, le serveur envoie :
1. `subscribed`, puis un **snapshot** découpé (`part`, `parts`, `final`) avec tous les événements et marchés qui correspondent à vos filtres ;
2. des frames **delta**, chacune avec une liste de `changes` : `upsert` apporte le nouvel objet complet et `remove` seulement son id ;
3. un **ping** toutes les 20 secondes. Répondez par `{"type":"pong"}`, sinon le serveur ferme le socket après 60 secondes de silence.
Les marchés sont identifiés par `id` (`eventId:key`), un dictionnaire suffit donc comme état. Chaque issue porte `decimal`, `american`, `fair` (cote juste sans marge) et `fairProb`. La [référence du WebSocket](/docs/websocket) (en anglais) liste tous les champs.
## Étape 3 — Le client Python
Installez l'unique dépendance avec `pip install websockets` (Python 3.9+). Enregistrez-le sous `pinnfeed_stream.py` ; les guides steam et Telegram l'importent.
```python
# pinnfeed_stream.py : garde une copie à jour du carnet Pinnacle depuis le WebSocket PinnFeed.
# pip install websockets (Python 3.9+)
import asyncio, json, os, random
import websockets
WS_URL = os.environ.get("PINNFEED_WS", "wss://pinnfeed.io/v1/stream")
KEY = os.environ["PINNFEED_KEY"]
SIDES = {"home", "away", "draw", "over", "under"}
class Book:
"""Événements et marchés par id, mis à jour à partir des frames snapshot + delta."""
def __init__(self):
self.events, self.markets = {}, {}
def apply(self, msg, on_market=None):
if msg["type"] == "snapshot":
for e in msg["events"]:
self.events[e["id"]] = e
for m in msg["markets"]:
self.markets[m["id"]] = m
elif msg["type"] == "delta":
for c in msg["changes"]:
if c["kind"] == "event" and c["op"] == "upsert":
self.events[c["event"]["id"]] = c["event"]
elif c["kind"] == "event" and c["op"] == "remove":
self.events.pop(c["id"], None)
for mid in [k for k, m in self.markets.items() if m["eventId"] == c["id"]]:
del self.markets[mid]
elif c["kind"] == "market" and c["op"] == "upsert":
old = self.markets.get(c["market"]["id"])
self.markets[c["market"]["id"]] = c["market"]
if on_market:
on_market(old, c["market"], self.events.get(c["market"]["eventId"]))
elif c["kind"] == "market" and c["op"] == "remove":
self.markets.pop(c["id"], None)
async def stream(subscription, on_market=None, on_ready=None):
"""Se connecte, s'abonne, tient le carnet à jour ; se reconnecte avec backoff indéfiniment."""
delay = 1
while True:
book = Book()
try:
async with websockets.connect(WS_URL, additional_headers={"x-api-key": KEY}, max_size=None) as ws:
await ws.send(json.dumps({"type": "subscribe", **subscription}))
async for raw in ws:
msg = json.loads(raw)
if msg["type"] == "ping":
await ws.send('{"type":"pong"}')
elif msg["type"] == "error":
print("server error:", msg["code"], msg["message"])
elif msg["type"] in ("snapshot", "delta"):
book.apply(msg, on_market if msg["type"] == "delta" else None)
if msg["type"] == "snapshot" and msg.get("final") and on_ready:
on_ready(book)
delay = 1
except (OSError, websockets.ConnectionClosed) as e:
print(f"disconnected ({e}); reconnecting in {delay}s")
await asyncio.sleep(delay + random.random())
delay = min(delay * 2, 30)
if __name__ == "__main__":
def ready(book):
print(f"book ready: {len(book.events)} events, {len(book.markets)} markets")
def moved(old, new, event):
if old and event:
for o_old, o_new in zip(old["outcomes"], new["outcomes"]):
if o_new["name"] in SIDES and o_old["decimal"] != o_new["decimal"]:
print(f'{event["home"]} v {event["away"]} {new["type"]} {o_new["name"]}: '
f'{o_old["decimal"]} -> {o_new["decimal"]} (fair {o_new["fair"]})')
asyncio.run(stream({"sports": ["soccer"], "markets": ["moneyline"], "main": True, "specials": False}, moved, ready))
```
Lancez-le avec `python pinnfeed_stream.py`. Vous verrez `book ready: N events, M markets`, puis une ligne par mouvement de prix.
## Étape 4 — Le client Node
La même logique en Node 18+ avec `npm install ws`. Enregistrez-le sous `stream.mjs` et lancez `node stream.mjs`.
```javascript
// stream.mjs : carnet Pinnacle en direct depuis le WebSocket PinnFeed (Node 18+).
// npm install ws
import WebSocket from 'ws';
const WS_URL = process.env.PINNFEED_WS || 'wss://pinnfeed.io/v1/stream';
const KEY = process.env.PINNFEED_KEY;
const SIDES = new Set(['home', 'away', 'draw', 'over', 'under']);
const events = new Map();
const markets = new Map();
function connect(delay = 1000) {
const ws = new WebSocket(WS_URL, { headers: { 'x-api-key': KEY }, perMessageDeflate: true });
ws.on('open', () => {
delay = 1000;
ws.send(JSON.stringify({ type: 'subscribe', sports: ['soccer', 'tennis'], markets: ['moneyline'], main: true, specials: false }));
});
ws.on('message', (raw) => {
const msg = JSON.parse(raw);
if (msg.type === 'ping') return ws.send('{"type":"pong"}');
if (msg.type === 'error') return console.error('server error:', msg.code, msg.message);
if (msg.type === 'snapshot') {
if (msg.part === 1) { events.clear(); markets.clear(); }
msg.events.forEach((e) => events.set(e.id, e));
msg.markets.forEach((m) => markets.set(m.id, m));
if (msg.final) console.log(`book ready: ${events.size} events, ${markets.size} markets`);
}
if (msg.type === 'delta') {
for (const c of msg.changes) {
if (c.kind === 'event') c.op === 'upsert' ? events.set(c.event.id, c.event) : events.delete(c.id);
if (c.kind === 'market' && c.op === 'remove') markets.delete(c.id);
if (c.kind === 'market' && c.op === 'upsert') {
const old = markets.get(c.market.id);
markets.set(c.market.id, c.market);
const ev = events.get(c.market.eventId);
if (!old || !ev) continue;
c.market.outcomes.forEach((o, i) => {
const prev = old.outcomes[i];
if (prev && SIDES.has(o.name) && prev.decimal !== o.decimal) console.log(`${ev.home} v ${ev.away} ${o.name}: ${prev.decimal} -> ${o.decimal} (fair ${o.fair})`);
});
}
}
}
});
ws.on('close', (code) => {
const wait = Math.min(delay * 2, 30000);
console.log(`closed (${code}); reconnecting in ${wait / 1000}s`);
setTimeout(() => connect(wait), wait + Math.random() * 1000);
});
ws.on('error', (e) => console.error('ws error:', e.message));
}
connect();
```
## Étape 5 — Restreignez l'abonnement
Les filtres s'appliquent côté serveur : vous ne recevez et ne traitez que ce que vous demandez.
```json
{ "type": "subscribe", "sports": ["tennis"], "live": true, "markets": ["moneyline", "total"], "main": true }
```
- `sports` : slugs ou ids ; `leagues` et `events` : listes d'ids.
- `live` : `true` en direct uniquement, `false` avant-match uniquement ; omis, les deux.
- `main: true` ne garde que le vainqueur, le handicap et le total principaux de chaque événement.
- Renvoyer `subscribe` remplace l'abonnement et déclenche un nouveau snapshot.
## Liste de contrôle pour la production
- **Reconnectez-vous avec backoff et jitter** (les deux clients le font : 1 s, 2 s, 4 s, jusqu'à 30 s) et reconstruisez à partir du nouveau snapshot.
- **Activez la compression** : `websockets` en Python négocie `permessage-deflate` par défaut ; en Node, passez `perMessageDeflate: true`. Les snapshots sont réduits de 5 à 10 fois.
- **Lisez vite.** Si plus de 16 Mo s'accumulent pour un client lent, le serveur le ferme avec le code `4008`. Faites le travail lourd en dehors de la boucle du socket.
- **Utilisez `seq` pour les logs, pas pour détecter des trous** : les filtres sautent les lots auxquels vous n'êtes pas abonné.
## Questions fréquentes
### Quel plan faut-il pour le WebSocket ?
Builder (99 €/mois) ou supérieur. Les clés Free et Hobby reçoivent `403 plan_lacks_ws` sur le WebSocket et peuvent utiliser le REST.
### Combien de connexions puis-je ouvrir ?
Builder permet 3 connexions WebSocket par compte, Pro en permet 10, Enterprise 50 (plus sur demande).
### Pourquoi certaines issues ont-elles des ids de participant au lieu de home ou away ?
Les spéciaux et certains paris à long terme listent des participants plutôt qu'une équipe à domicile et à l'extérieur. Abonnez-vous avec `"specials": false` et filtrez sur `home`, `away`, `draw`, `over` et `under` si vous ne voulez que les lignes de match, comme le font les exemples.
---
Source: https://pinnfeed.io/fr/guides/dropping-odds-steam-detection
# Détectez les dropping odds et les mouvements de steam chez Pinnacle en temps réel
Un **mouvement de steam** est une baisse de prix rapide et forte chez un bookmaker qui fait le marché, comme Pinnacle, généralement parce que de l'argent « sharp » est entré d'un côté. Les bookmakers « soft » suivent souvent avec quelques secondes ou minutes de retard, ce qui fait des alertes de steam l'un des signaux les plus utiles d'un flux en direct. Dans ce guide, vous construisez un détecteur sur le WebSocket de PinnFeed. C'est un outil statistique, pas un système de pronostics.
## Étape 1 — Définissez ce qu'est un steam
Une définition pratique, à ajuster :
- la cote décimale d'une issue **baisse d'au moins 5 %** par rapport à son maximum des **2 dernières minutes** ;
- la **mise maximale** du marché est d'au moins 100, car Pinnacle relève ses limites à mesure qu'il a confiance dans un prix : les mouvements sur des marchés peu liquides sont plus bruités ;
- vous alertez **une fois par issue et par fenêtre**, pas à chaque tick.
## Étape 2 — Recevez le carnet en streaming
Utilisez le client Python du [guide Python et Node](/fr/guides/pinnacle-odds-websocket-python-node). Enregistrez-le sous `pinnfeed_stream.py` à côté du script ci-dessous ; il appelle `on_market(old, new, event)` à chaque changement de marché.
## Étape 3 — Suivez le maximum glissant de chaque issue
Gardez une courte deque de `(timestamp, price)` par marché et par issue, supprimez ce qui est plus ancien que la fenêtre et comparez le prix actuel au maximum de la fenêtre :
```python
# steam.py : signale les mouvements de steam chez Pinnacle (baisses de prix rapides et fortes) depuis le WebSocket en direct.
# Utilise pinnfeed_stream.py du guide Python/Node. pip install websockets
import asyncio, collections, os, time
from pinnfeed_stream import stream, SIDES
WINDOW_S = int(os.environ.get("WINDOW_S", 120)) # fenêtre d'observation
MIN_DROP = float(os.environ.get("MIN_DROP", 0.05)) # alerte quand la cote baisse de 5 % ou plus dans la fenêtre
MIN_STAKE = float(os.environ.get("MIN_STAKE", 100)) # ignore les marchés peu liquides : la mise maximale de Pinnacle est un signal de confiance
history = collections.defaultdict(collections.deque) # (id du marché, issue) -> deque[(ts, decimal)]
alerted = {}
def on_market(old, new, event):
if not event or (new.get("maxStake") or 0) < MIN_STAKE:
return
now = time.time()
for o in new["outcomes"]:
if o["name"] not in SIDES:
continue
h = history[(new["id"], o["name"])]
h.append((now, o["decimal"]))
while h and now - h[0][0] > WINDOW_S:
h.popleft()
high = max(p for _, p in h)
drop = 1 - o["decimal"] / high
key = (new["id"], o["name"])
if drop >= MIN_DROP and now - alerted.get(key, 0) > WINDOW_S:
alerted[key] = now
pts = o.get("points")
line = "" if pts is None else f" {pts:g}" if new["type"] == "total" else f" {pts:+g}"
print(f'STEAM {event["sport"]} | {event["home"]} v {event["away"]} | {new["type"]}{line} {o["name"]}: '
f'{high:.3f} -> {o["decimal"]:.3f} (-{drop:.1%} in {WINDOW_S}s) fair {o["fair"]:.3f} max stake {new["maxStake"]}')
asyncio.run(stream({"sports": ["soccer", "tennis", "basketball"], "markets": ["moneyline", "spread", "total"],
"main": True, "specials": False}, on_market))
```
Lancez-le avec `python steam.py`. Les seuils sont des variables d'environnement ; par exemple `MIN_DROP=0.03 WINDOW_S=300 python steam.py` pour 3 % en cinq minutes. Une ligne typique :
```text
STEAM tennis | Sebastian Baez v Daniil Glinka | moneyline away: 2.260 -> 2.050 (-9.3% in 120s) fair 2.143 max stake 975
```
## Étape 4 — Ou interrogez l'endpoint REST
Si une liste périodique vous suffit, `GET /v1/drops` renvoie les plus fortes chutes sur une fenêtre glissante, calculées côté serveur :
```bash
curl -H "x-api-key: $PINNFEED_KEY" "https://pinnfeed.io/v1/drops?sport=soccer&live=true&minutes=10&min_pct=5"
```
Chaque ligne contient l'événement, le marché, la ligne, l'issue, `from`, `to`, `dropPct` et `movedAt`. Cela fonctionne sur tous les plans, y compris Free avec ses 30 secondes de retard.
## Étape 5 — Des alertes aux sélections
- **Comparez avec les bookmakers soft.** Un steam n'a d'intérêt que là où le prix soft n'a pas encore bougé. Le [guide du value betting](/fr/guides/value-betting-no-vig-fair-odds) montre comment chiffrer cet écart avec les cotes justes de Pinnacle.
- **Privilégiez l'avant-match pour le retard des bookmakers soft** ; en direct, les mouvements viennent souvent du score plutôt que de l'argent sharp.
- **Mesurez-vous** avec le [closing line value](/fr/guides/closing-line-value-clv-tracking) : si vos sélections steam battent la cote de clôture en moyenne, le signal est réel.
- **Publiez-les** : le [bot de pronostics Telegram](/fr/guides/telegram-picks-bot) et le [bot de pronostics Discord](/fr/guides/discord-picks-bot) envoient ces alertes dans un canal.
## Questions fréquentes
### Quelle différence entre une chute de cote et un steam ?
Une chute de cote, c'est n'importe quelle baisse de prix. Le steam est une chute rapide et significative chez un bookmaker sharp, généralement provoquée par de l'argent informé, qui tend ensuite à se propager aux autres bookmakers.
### Pourquoi utiliser Pinnacle pour détecter le steam ?
Pinnacle accepte des limites élevées et ajuste ses prix en fonction de l'action sharp : ses mouvements sont le meilleur signal du marché. Les bookmakers soft les copient ou suivent avec retard.
### Puis-je le faire sans le WebSocket ?
Oui, en interrogeant `/v1/drops`, disponible sur tous les plans. Le WebSocket voit chaque mouvement au moment où il se produit ; le polling ne le voit qu'à votre requête suivante.
---
Source: https://pinnfeed.io/fr/guides/value-betting-no-vig-fair-odds
# Value bet face aux bookmakers soft avec les cotes justes de Pinnacle
Les prix de Pinnacle sont ce que le marché des paris a de plus proche d'une probabilité réelle. En retirant la marge, vous obtenez une **cote juste** ; tout bookmaker soft qui paie plus que cette cote propose un pari à espérance positive (+EV). PinnFeed calcule la cote juste sur chaque marché : le calcul se résume à une multiplication. Le +EV est une notion statistique à long terme, pas une garantie de gain.
## Étape 1 — Comprenez la cote juste
Pour un marché avec des cotes décimales `d_i` :
```text
implied_i = 1 / d_i
margin = Σ implied_i − 1
fairProb_i = implied_i / Σ implied_j (méthode multiplicative)
fair_i = 1 / fairProb_i
```
Chaque issue de l'API contient déjà `fair` et `fairProb`, et chaque marché contient `margin`. Les prix bruts sont aussi fournis, si vous préférez appliquer vous-même la méthode de la puissance ou celle de Shin.
## Étape 2 — Calculez l'espérance
Si un bookmaker soft propose la cote décimale `S` sur une issue dont la probabilité juste est `p` :
```text
EV = S × p − 1
```
Avec `S = 2.30` et `p = 0.488` (cote juste 2.049), l'EV est de +12,3 % : sur le long terme, l'espérance est de 12,3 centimes par euro misé. La plupart des parieurs fixent un seuil de 1 à 3 % pour absorber le bruit et le temps nécessaire pour placer le pari.
## Étape 3 — Calculez la mise
Le Kelly complet (`(S·p − 1) / (S − 1)`) est trop agressif avec des probabilités estimées. Un quart de Kelly est un compromis courant, et c'est ce qu'affiche le script.
## Étape 4 — Lancez le script
Remplissez `SOFT` avec les cotes relevées chez un bookmaker soft (à la main, sur un comparateur de cotes ou via une autre API), avec les noms d'équipes tels que PinnFeed les écrit. Installez `requests` et lancez `python value.py` :
```python
# value.py : trouve des cotes +EV chez un bookmaker soft grâce aux cotes justes sans marge de Pinnacle.
# pip install requests
import os, requests
BASE = os.environ.get("PINNFEED_BASE", "https://pinnfeed.io")
KEY = os.environ["PINNFEED_KEY"]
# Cotes relevées chez un bookmaker soft : (équipe à domicile, équipe à l'extérieur, issue) -> cote décimale.
SOFT = {
("Osasuna", "Malaga", "home"): 1.95,
("Colon", "Defensor Sporting", "away"): 2.30,
}
MIN_EV = 0.02 # avantage de 2 %
def kelly(price, p, fraction=0.25):
"""Mise de Kelly fractionnelle, en part de la bankroll."""
return max(0.0, fraction * (price * p - 1) / (price - 1))
r = requests.get(f"{BASE}/v1/odds", headers={"x-api-key": KEY},
params={"sport": "soccer", "market": "moneyline", "main": "true", "limit": 1000}, timeout=20)
r.raise_for_status()
for ev in r.json()["events"]:
for m in ev["markets"]:
for o in m["outcomes"]:
soft = SOFT.get((ev["home"], ev["away"], o["name"]))
if not soft:
continue
ev_pct = soft * o["fairProb"] - 1 # espérance par unité misée
flag = "VALUE" if ev_pct >= MIN_EV else "no edge"
print(f'{flag:8} {ev["home"]} v {ev["away"]} {o["name"]}: soft {soft} vs Pinnacle {o["decimal"]} '
f'(fair {o["fair"]:.3f}, margin {m["margin"]:.1%}) EV {ev_pct:+.1%} '
f'kelly/4 {kelly(soft, o["fairProb"]):.2%}')
```
La sortie ressemble à ceci :
```text
VALUE Colon v Defensor Sporting away: soft 2.3 vs Pinnacle 1.8065 (fair 2.049, margin 13.4%) EV +12.3% kelly/4 2.36%
```
L'appel REST fonctionne sur tous les plans ; en Free, les prix ont 30 secondes de retard. Pour la value en direct, il vous faut les prix en direct : faites la même comparaison dans le client WebSocket du [guide Python et Node](/fr/guides/pinnacle-odds-websocket-python-node), avec Builder.
## Étape 5 — Vérifiez avec le CLV
À court terme, les résultats sont surtout de la variance. La réponse honnête la plus rapide, c'est le **closing line value** : le prix que vous avez pris a-t-il battu la cote juste de clôture de Pinnacle ? Le [guide CLV](/fr/guides/closing-line-value-clv-tracking) enregistre chaque pari et le mesure.
## Questions fréquentes
### Pourquoi prendre Pinnacle comme référence ?
Pinnacle travaille avec des marges faibles et des limites élevées et ajuste ses prix selon l'argent sharp : son prix sans marge est largement utilisé comme la meilleure estimation publique de la probabilité réelle.
### Quelle méthode PinnFeed utilise-t-il pour retirer la marge ?
La méthode multiplicative (proportionnelle). Chaque issue inclut les cotes décimales et américaines brutes, vous pouvez donc utiliser une autre méthode.
### PinnFeed fournit-il les cotes des bookmakers soft ?
Non. PinnFeed ne fournit que Pinnacle. Combinez-le avec vos propres cotes de bookmakers soft ou avec une API multi-bookmakers comme The Odds API.
---
Source: https://pinnfeed.io/fr/guides/closing-line-value-clv-tracking
# Mesurez votre closing line value face à la clôture de Pinnacle
Le **closing line value (CLV)** compare le prix que vous avez pris au dernier prix du marché avant le coup d'envoi. Battre régulièrement la cote juste de clôture de Pinnacle est le signal précoce le plus solide que votre méthode a un avantage, bien avant que vos gains et pertes puissent le montrer, même si ce n'est jamais une garantie de profit. PinnFeed enregistre la cote de clôture de Pinnacle de chaque marché au début de l'événement et la sert via `/v1/closing`.
## Étape 1 — La formule
```text
CLV = price_taken / closing_fair_price − 1
```
Utilisez la cote de clôture **sans marge**, pas la cote brute : battre un prix qui contient encore la marge de Pinnacle est plus facile et exagère votre avantage. Si vous avez pris 2.10 et que le marché a clôturé à une cote juste de 1.95, votre CLV est de +7,7 %.
## Étape 2 — Enregistrez chaque pari
Chaque pari a besoin de l'id de l'événement, de la clé du marché et de l'issue. Les trois viennent de l'API : l'`id` de l'événement, la `key` du marché (`s;0;m` est le vainqueur du match complet, `s;0;ou;2.5` le total 2.5 du match) et le `name` de l'issue (`home`, `away`, `draw`, `over`, `under`).
## Étape 3 — Lancez le tracker
Installez `requests`, enregistrez le script sous `clv.py` et enregistrez vos paris au fur et à mesure :
```python
# clv.py : enregistre vos paris et mesure le closing line value (CLV) par rapport à la clôture sans marge de Pinnacle.
# pip install requests Utilisation :
# python clv.py bet ex. bet 1640141281 "s;0;m" home 2.10
# python clv.py report
import os, sqlite3, sys, requests
BASE = os.environ.get("PINNFEED_BASE", "https://pinnfeed.io")
KEY = os.environ["PINNFEED_KEY"]
db = sqlite3.connect(os.environ.get("CLV_DB", "bets.db"))
db.execute("CREATE TABLE IF NOT EXISTS bets (event_id INTEGER, market_key TEXT, outcome TEXT, price REAL, "
"close_fair REAL, placed_at TEXT DEFAULT CURRENT_TIMESTAMP)")
def closing_fair(event_id, market_key, outcome):
r = requests.get(f"{BASE}/v1/closing/{event_id}", headers={"x-api-key": KEY}, timeout=20)
if r.status_code == 404:
return None # pas encore clôturé (ou jamais capturé)
r.raise_for_status()
for rec in r.json()["markets"]:
if rec["market"]["key"] == market_key:
for o in rec["market"]["outcomes"]:
if o["name"] == outcome:
return o["fair"]
return None
if sys.argv[1:2] == ["bet"]:
_, _, event_id, market_key, outcome, price = sys.argv
db.execute("INSERT INTO bets (event_id, market_key, outcome, price) VALUES (?,?,?,?)",
(int(event_id), market_key, outcome, float(price)))
db.commit()
print("logged")
else:
rows = db.execute("SELECT rowid, event_id, market_key, outcome, price, close_fair FROM bets").fetchall()
clvs = []
for rowid, event_id, key, outcome, price, close in rows:
if close is None:
close = closing_fair(event_id, key, outcome)
if close:
db.execute("UPDATE bets SET close_fair=? WHERE rowid=?", (close, rowid))
if close:
clv = price / close - 1
clvs.append(clv)
print(f"{event_id} {key} {outcome}: took {price}, closed fair {close:.3f} -> CLV {clv:+.2%}")
else:
print(f"{event_id} {key} {outcome}: took {price}, waiting for close")
db.commit()
if clvs:
print(f"average CLV over {len(clvs)} bets: {sum(clvs) / len(clvs):+.2%}")
```
```bash
python clv.py bet 1640229582 "s;0;m" home 2.10
python clv.py report
```
```text
1640229582 s;0;m home: took 2.1, closed fair 3.181 -> CLV -33.99%
999 s;0;m home: took 1.9, waiting for close
average CLV over 1 bets: -33.99%
```
Lancez `report` via cron après les coups d'envoi ; la cote de clôture de chaque pari est demandée une seule fois puis conservée.
## Étape 4 — Interprétez le résultat
- Sur quelques centaines de paris, un CLV moyen de **+2 % ou plus** est un indice fort d'un avantage réel.
- Un CLV négatif avec un bénéfice positif relève généralement de la chance, qui tend à s'estomper.
- Ventilez le CLV par sport, marché et délai avant le match : vous verrez d'où vient vraiment votre avantage.
## Étape 5 — Téléchargez une journée entière
Pour la recherche ou les backtests, demandez toutes les cotes de clôture d'un jour UTC :
```bash
curl -H "x-api-key: $PINNFEED_KEY" "https://pinnfeed.io/v1/closing?date=2026-11-08&sport=soccer&main=true"
```
## Questions fréquentes
### Quel plan inclut les cotes de clôture ?
L'historique des cotes de clôture est inclus à partir de Builder (99 €/mois), ainsi que dans Pro et Enterprise.
### Quand la cote de clôture est-elle capturée ?
Au début de l'événement : le dernier prix avant-match de chaque marché est enregistré avec l'heure de capture.
### Jusqu'où remonte l'archive ?
Elle commence au lancement du service et s'enrichit chaque jour. Les plans Enterprise peuvent l'exporter en bloc au format CSV ou Parquet.
---
Source: https://pinnfeed.io/fr/guides/telegram-picks-bot
# Créez un bot de pronostics Telegram avec les cotes Pinnacle en direct
Ce bot surveille les prix de Pinnacle sur le WebSocket de PinnFeed et publie un message dans un canal Telegram chaque fois qu'un marché fait du steam, c'est-à-dire quand sa cote baisse de 5 % ou plus en deux minutes sur un marché avec une mise maximale raisonnable. C'est un seul fichier d'environ 70 lignes, sans bibliothèque Telegram : il appelle directement la Bot API.
## Étape 1 — Créez le bot
1. Dans Telegram, ouvrez **@BotFather**, envoyez `/newbot` et suivez les instructions. Copiez le token.
2. Créez un canal et ajoutez le bot comme **administrateur** avec le droit de publier.
3. Utilisez le nom public du canal (`@mychannel`) comme chat id, ou l'id numérique pour une discussion privée.
## Étape 2 — Configurez l'environnement
```bash
export PINNFEED_KEY="ps_live_..." # plan Builder (WebSocket)
export TELEGRAM_TOKEN="123456:ABC..." # fourni par @BotFather
export TELEGRAM_CHAT="@mychannel"
npm install ws
```
Si `TELEGRAM_TOKEN` n'est pas défini, le bot fonctionne en **mode test** : il affiche les messages au lieu de les envoyer.
## Étape 3 — Le bot
Enregistrez-le sous `telegram-picks-bot.mjs` :
```javascript
// telegram-picks-bot.mjs : publie les mouvements de steam de Pinnacle dans un canal Telegram sous forme de "pronostics".
// npm install ws Node 18+ (global fetch)
// environnement : PINNFEED_KEY, TELEGRAM_TOKEN (fourni par @BotFather), TELEGRAM_CHAT (ex. @mychannel ou un id de chat)
import WebSocket from 'ws';
const WS_URL = process.env.PINNFEED_WS || 'wss://pinnfeed.io/v1/stream';
const { PINNFEED_KEY, TELEGRAM_TOKEN, TELEGRAM_CHAT } = process.env;
const MIN_DROP = Number(process.env.MIN_DROP || 0.05); // baisse de 5 %...
const WINDOW_MS = Number(process.env.WINDOW_MS || 120000); // ...en moins de 2 minutes
const SIDES = new Set(['home', 'away', 'draw', 'over', 'under']);
const events = new Map();
const highs = new Map(); // "marketId|outcome" -> [{t, p}]
const sent = new Map(); // "marketId|outcome" -> heure de la dernière alerte
async function post(text) {
if (!TELEGRAM_TOKEN) return console.log('[dry run]', text);
const r = await fetch(`https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`, {
method: 'POST', headers: { 'content-type': 'application/json' },
body: JSON.stringify({ chat_id: TELEGRAM_CHAT, text, disable_web_page_preview: true }),
});
if (!r.ok) console.error('telegram', r.status, await r.text());
}
function check(m) {
const ev = events.get(m.eventId);
if (!ev || (m.maxStake ?? 0) < 100) return;
const now = Date.now();
for (const o of m.outcomes) {
if (!SIDES.has(o.name)) continue;
const k = `${m.id}|${o.name}`;
const h = (highs.get(k) || []).filter((x) => now - x.t < WINDOW_MS);
h.push({ t: now, p: o.decimal });
highs.set(k, h);
const high = Math.max(...h.map((x) => x.p));
const drop = 1 - o.decimal / high;
if (drop < MIN_DROP || now - (sent.get(k) || 0) < WINDOW_MS) continue;
sent.set(k, now);
const pick = o.name === 'home' ? ev.home : o.name === 'away' ? ev.away : o.name;
const line = o.points == null ? '' : m.type === 'total' ? ` ${o.points}` : ` ${o.points > 0 ? '+' : ''}${o.points}`;
post(`📉 ${ev.sport.toUpperCase()} · ${ev.league?.name ?? ''}\n${ev.home} v ${ev.away}\n` +
`Pick: ${pick} (${m.type}${line})\nPinnacle ${high.toFixed(2)} → ${o.decimal.toFixed(2)} (−${(drop * 100).toFixed(1)}%)\n` +
`Fair now ${o.fair.toFixed(2)} · max stake ${m.maxStake}`);
}
}
function connect(delay = 1000) {
const ws = new WebSocket(WS_URL, { headers: { 'x-api-key': PINNFEED_KEY }, perMessageDeflate: true });
ws.on('open', () => {
delay = 1000;
ws.send(JSON.stringify({ type: 'subscribe', sports: ['soccer', 'tennis', 'basketball'], markets: ['moneyline', 'spread', 'total'], main: true, specials: false }));
});
ws.on('message', (raw) => {
const msg = JSON.parse(raw);
if (msg.type === 'ping') return ws.send('{"type":"pong"}');
if (msg.type === 'snapshot') msg.events.forEach((e) => events.set(e.id, e));
if (msg.type === 'delta') for (const c of msg.changes) {
if (c.kind === 'event') c.op === 'upsert' ? events.set(c.event.id, c.event) : events.delete(c.id);
if (c.kind === 'market' && c.op === 'upsert') check(c.market);
}
});
ws.on('close', () => setTimeout(() => connect(Math.min(delay * 2, 30000)), delay));
ws.on('error', (e) => console.error('ws error:', e.message));
}
connect();
```
## Étape 4 — Lancez-le et testez-le
```bash
node telegram-picks-bot.mjs
```
Un message ressemble à ceci :
```text
📉 SOCCER · Italy - Serie A
Udinese v Fiorentina
Pick: Udinese (spread +0.25)
Pinnacle 1.88 → 1.70 (−9.5%)
Fair now 1.83 · max stake 150
```
Réglez le volume avec `MIN_DROP` et `WINDOW_MS` ; par exemple `MIN_DROP=0.08` pour des alertes moins nombreuses mais plus fortes.
## Étape 5 — Gardez-le en marche
- Lancez-le avec `systemd`, `pm2` ou un conteneur qui redémarre en cas d'échec ; le bot se reconnecte seul au WebSocket.
- Telegram autorise environ 20 messages par minute par groupe ou canal. Augmentez `MIN_DROP` si vous recevez des réponses `429`.
- Publiez votre historique honnêtement : enregistrez chaque pronostic et mesurez-le avec le [closing line value](/fr/guides/closing-line-value-clv-tracking).
## Questions fréquentes
### Quel plan PinnFeed faut-il pour le bot ?
Builder (99 €/mois) ou supérieur, car il utilise le WebSocket. Pour un bot plus lent sur Free ou Hobby, interrogez `/v1/drops` toutes les minutes.
### Puis-je publier les pronostics sur Discord ?
Oui. Remplacez la fonction `post` par un POST vers l'URL d'un webhook Discord avec le corps `{"content": text}`. Le bot complet (embeds, file d'envoi et gestion des 429) est dans le [guide du bot de pronostics Discord](/fr/guides/discord-picks-bot).
### Est-il légal de publier des pronostics ?
Les règles sur les pronostics et la publicité pour les jeux d'argent varient selon les pays. En France, les jeux d'argent en ligne et leur publicité sont encadrés par l'Autorité nationale des jeux (ANJ), et la loi du 9 juin 2023 sur l'influence commerciale restreint la promotion des paris sportifs par les influenceurs. Vérifiez les règles là où vous et votre audience vous trouvez, ne vous adressez qu'aux plus de 18 ans et ne présentez jamais un pronostic comme sûr. Ceci n'est pas un avis juridique.
---
Source: https://pinnfeed.io/fr/guides/pinnacle-odds-chatgpt-claude-mcp
# Les cotes Pinnacle en direct dans ChatGPT et Claude avec MCP
PinnFeed propose un serveur [Model Context Protocol](https://modelcontextprotocol.io) hébergé. Vous l'ajoutez une fois à votre assistant, qui peut alors consulter les cotes Pinnacle en direct et avant-match, les chutes de cotes, les cotes justes et les cotes de clôture quand vous le lui demandez. Pas de données à coller, pas de code à écrire.
## Étape 1 — Une clé pour l'assistant
Créez une clé dédiée dans le [tableau de bord](/dashboard), nommée d'après l'assistant (par exemple « claude »), pour pouvoir la révoquer seule. Chaque appel d'outil compte comme une requête REST de votre plan ; Free fonctionne avec des données différées de 30 secondes.
## Étape 2 — Ajoutez le serveur
**Claude Code**
```bash
claude mcp add --transport http pinnfeed https://pinnfeed.io/mcp --header "Authorization: Bearer YOUR_KEY"
```
**Claude (web et bureau) :** Settings → Connectors → Add custom connector, URL `https://pinnfeed.io/mcp?key=YOUR_KEY`.
**ChatGPT :** Settings → Apps & Connectors → Advanced → activez Developer mode et créez un connecteur avec l'URL de serveur `https://pinnfeed.io/mcp?key=YOUR_KEY`, sans authentification.
**Cursor** (`~/.cursor/mcp.json`) :
```json
{ "mcpServers": { "pinnfeed": { "url": "https://pinnfeed.io/mcp", "headers": { "Authorization": "Bearer YOUR_KEY" } } } }
```
Les extraits pour VS Code Copilot et Codex CLI se trouvent dans la [documentation MCP](/docs/mcp) (en anglais).
## Étape 3 — Posez vos questions
L'assistant choisit l'outil. Des prompts qui fonctionnent bien (vous pouvez les écrire en français) :
- « Quelles cotes de football ont le plus baissé chez Pinnacle ces 15 dernières minutes ? » (`get_drops`)
- « Montre-moi les vainqueurs de tennis en direct avec la cote juste sans marge et la marge. » (`get_live_odds`)
- « Quelle est la cote juste de Liverpool - Manchester United et quelle est la mise maximale ? » (`search_events` puis `get_event`)
- « Un bookmaker soft propose 2.30 sur l'extérieur dans Colon - Defensor Sporting. Est-ce +EV par rapport à Pinnacle ? » (`get_event`, puis l'assistant fait le calcul)
- « Donne-moi les cotes de clôture de l'événement 1640229582. » (`get_closing_odds`, Builder et au-delà)
## Étape 4 — Testez sans assistant
Le serveur parle JSON-RPC sur HTTP : vous pouvez tester n'importe quel outil avec curl.
```bash
curl -s https://pinnfeed.io/mcp -H "Authorization: Bearer $PINNFEED_KEY" \
-H "content-type: application/json" -H "accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_drops","arguments":{"sport":"soccer","minutes":15}}}'
```
Le résultat est un bloc de texte JSON avec les chutes : événement, marché, ligne, issue, `from`, `to`, `dropPct` et `movedAt`.
## Étape 5 — Passez au code
Quand une question devient une stratégie, passez au code : le [guide du steam](/fr/guides/dropping-odds-steam-detection) et le [guide du value bet](/fr/guides/value-betting-no-vig-fair-odds) font la même chose en continu sur le WebSocket.
## Questions fréquentes
### Quels outils le serveur MCP de PinnFeed expose-t-il ?
`get_account`, `list_sports`, `search_events`, `get_live_odds`, `get_prematch_odds`, `get_event`, `get_drops` et `get_closing_odds`.
### Le serveur MCP nécessite-t-il un plan payant ?
Non. Il fonctionne sur tous les plans, avec leurs limites : Free a 30 secondes de retard et 1 000 requêtes par jour. Les cotes de clôture nécessitent Builder ou supérieur.
### Est-ce sûr de mettre ma clé dans une URL ?
Traitez-la comme un mot de passe. Utilisez une clé dédiée par assistant et révoquez-la depuis le tableau de bord en cas de fuite.
---
Source: https://pinnfeed.io/fr/guides/pinnacle-odds-google-sheets
# Les cotes Pinnacle dans Google Sheets
Ce guide écrit les cotes 1N2 de football de Pinnacle dans une feuille Google Sheets : une ligne par match, avec les cotes décimales, les cotes justes sans marge et la marge du marché. Un déclencheur horaire met l'onglet à jour toutes les 15 minutes. Le script utilise l'API REST de PinnFeed : il fonctionne donc sur le plan **Free** (0 €, 30 secondes de retard, 1 000 requêtes/jour).
## Étape 1 — Obtenez une clé Free
1. Créez un compte sur [pinnfeed.io](/signup) et ouvrez le [tableau de bord](/dashboard).
2. Créez une clé et copiez-la. Les clés ont la forme `ps_live_…`.
3. En Free, choisissez jusqu'à deux sports dans le tableau de bord. Le script utilise le football (`soccer`) par défaut ; modifiez `SPORT` si vous en avez choisi un autre.
Builder n'est pas nécessaire pour Sheets. Builder (99 €/mois, le plan WebSocket) sert aux clients push en temps réel comme ceux du [guide Python et Node](/fr/guides/pinnacle-odds-websocket-python-node).
## Étape 2 — Créez la feuille de calcul
1. Créez une nouvelle feuille Google Sheets.
2. Renommez le premier onglet **Odds** (nom exact ; c'est ce que le script recherche).
3. Ouvrez **Extensions → Apps Script**. Supprimez la fonction d'exemple `myFunction` et laissez le projet vide pour l'étape suivante.
## Étape 3 — Collez le script et définissez les propriétés
Collez ceci dans `Code.gs` :
```javascript
// Google Apps Script : Extensions → Apps Script, collez ce fichier.
// Propriétés du script (Paramètres du projet → Propriétés du script) :
// PINNFEED_BASE = https://pinnfeed.io
// PINNFEED_KEY = ps_live_...
// Ajoutez un onglet nommé "Odds", exécutez refreshOdds une fois, puis ajoutez un déclencheur toutes les 15 minutes.
const PROPS = PropertiesService.getScriptProperties();
const BASE = PROPS.getProperty('PINNFEED_BASE') || 'https://pinnfeed.io';
const KEY = PROPS.getProperty('PINNFEED_KEY');
const SPORT = 'soccer'; // remplacez par basketball, tennis, … (doit faire partie de votre plan)
function refreshOdds() {
if (!KEY) {
console.error('Set script property PINNFEED_KEY first');
return;
}
const url = BASE + '/v1/odds'
+ '?sport=' + encodeURIComponent(SPORT)
+ '&market=moneyline&main=true&live=false&limit=500';
const res = UrlFetchApp.fetch(url, {
headers: { 'x-api-key': KEY },
muteHttpExceptions: true,
});
const code = res.getResponseCode();
if (code !== 200) {
console.warn('PinnFeed HTTP ' + code + ': ' + res.getContentText().slice(0, 300));
return; // en cas d'échec, l'onglet reste tel quel
}
const data = JSON.parse(res.getContentText());
const rows = [];
for (const ev of data.events || []) {
const ml = (ev.markets || []).find((m) => m.type === 'moneyline' && m.main);
if (!ml) continue;
const byName = {};
for (const o of ml.outcomes || []) byName[o.name] = o;
const home = byName.home || {};
const draw = byName.draw || {};
const away = byName.away || {};
rows.push([
ev.startTime ? new Date(ev.startTime) : '',
(ev.league && ev.league.name) || '',
ev.home || '',
ev.away || '',
home.decimal || '',
draw.decimal || '',
away.decimal || '',
home.fair || '',
draw.fair || '',
away.fair || '',
ml.margin != null ? ml.margin : '',
ev.id,
]);
}
const sheet = SpreadsheetApp.getActive().getSheetByName('Odds');
if (!sheet) {
console.error('Create a tab named Odds first');
return;
}
sheet.clearContents();
sheet.appendRow([
'Starts', 'League', 'Home', 'Away',
'1', 'X', '2',
'Fair 1', 'Fair X', 'Fair 2',
'Margin', 'Event id',
]);
if (rows.length) {
sheet.getRange(2, 1, rows.length, 12).setValues(rows);
}
console.log('Wrote ' + rows.length + ' moneyline rows for ' + SPORT);
}
```
Ouvrez ensuite la roue dentée du projet (**Paramètres du projet**) et, dans **Propriétés du script**, ajoutez :
| Propriété | Valeur |
|---|---|
| `PINNFEED_KEY` | votre clé (`ps_live_…`) |
| `PINNFEED_BASE` | `https://pinnfeed.io` (facultatif ; valeur par défaut) |
Ne collez jamais la clé dans les cellules de la feuille et ne partagez pas publiquement le projet Apps Script.
## Étape 4 — Lancez-le une fois et autorisez-le
1. Choisissez `refreshOdds` dans la liste des fonctions et cliquez sur **Exécuter**.
2. Google vous demande l'autorisation de vous connecter à un service externe et de modifier la feuille. Acceptez pour votre compte.
3. Rechargez la feuille. L'onglet Odds doit afficher les colonnes `Starts`, `League`, `Home`, `Away`, `1`, `X`, `2`, les trois cotes justes, `Margin` et `Event id`.
Si un appel échoue (mauvaise clé, limite de requêtes, sport hors de votre plan), le script enregistre un avertissement et **laisse les lignes précédentes intactes** : une mauvaise minute ne vide jamais le tableau.
## Étape 5 — Ajoutez un déclencheur toutes les 15 minutes
1. Dans Apps Script, ouvrez **Déclencheurs** (icône de réveil) → **Ajouter un déclencheur**.
2. Fonction : `refreshOdds`. Source de l'événement : **Déclencheur horaire**. Type : **Minuteur**. Intervalle : **Toutes les 15 minutes**.
3. Enregistrez.
Cela fait 96 appels par jour pour un sport, bien en dessous des 1 000 requêtes/jour et 1 req/s du plan Free. Deux sports toutes les 30 minutes font aussi 96 appels. Voir [plans et limites](/docs/limits) (en anglais).
| Déclencheur | Appels / jour | Compatible Free ? |
|---|---|---|
| Toutes les 15 min, 1 sport | 96 | oui |
| Toutes les 30 min, 2 sports | 96 | oui |
| Toutes les 15 min, 2 sports | 192 | oui |
| Toutes les minutes, 1 sport | 1 440 | non — nécessite Hobby ou supérieur (sans quota journalier) |
Apps Script a aussi ses propres quotas ; le déclencheur horaire le plus court est d'une minute.
## Étape 6 — Lisez les cotes justes et les marges
Chaque ligne 1N2 contient les champs sans marge de PinnFeed décrits dans le [schéma](/docs/schema) :
- `Fair 1` / `Fair X` / `Fair 2` — la cote décimale `fair` de chaque issue (marge retirée, méthode multiplicative).
- `Margin` — la `margin` du marché (surround = somme des probabilités implicites − 1).
Utilisez ces colonnes pour comparer une cote d'un bookmaker soft dans un autre onglet : l'espérance vaut `soft × (1 / fair) − 1`, le même calcul que dans le [guide du value bet](/fr/guides/value-betting-no-vig-fair-odds). Pour les mouvements de steam en direct, Sheets n'est pas le bon outil : utilisez le WebSocket de Builder et le [guide de détection du steam](/fr/guides/dropping-odds-steam-detection).
## Questions fréquentes
### Quel plan PinnFeed me faut-il ?
Free suffit pour un tableau différé mis à jour toutes les quelques minutes. Hobby (29 €/mois) supprime le quota journalier et les 30 secondes de retard, mais reste uniquement REST. Le push en temps réel nécessite [Builder](/fr/pricing#plan-builder) (99 €/mois).
### Pourquoi le script utilise-t-il `x-api-key` plutôt qu'un paramètre d'URL ?
C'est l'en-tête d'authentification recommandé dans la [documentation](/docs/authentication). `UrlFetchApp` d'Apps Script peut envoyer des en-têtes : aucune raison de mettre la clé dans l'URL (où elle peut finir dans des logs).
### Puis-je tracer l'historique des prix ?
Oui. Gardez l'onglet Odds comme tableau en direct (il est effacé et réécrit à chaque exécution). Ajoutez un second onglet qui ne fait qu'ajouter des lignes après chaque mise à jour, et insérez un graphique en courbes. Ne videz pas l'onglet d'historique.
### Ce contenu pédagogique est-il réservé aux adultes ?
Oui. Les données de cotes et les outils de tableur sont du contenu pédagogique destiné aux plus de 18 ans. Rien ici n'est un pronostic, un pari sûr ni une promesse de gain.
## Voir aussi
- [Référence de l'API REST](/docs/rest) (en anglais) — filtres et pagination de `/v1/odds`
- [Value bet avec les cotes justes sans marge](/fr/guides/value-betting-no-vig-fair-odds)
- [Bot de pronostics Telegram](/fr/guides/telegram-picks-bot) — si la feuille ne suffit plus
- [Tarifs](/fr/pricing)
---
Source: https://pinnfeed.io/fr/guides/discord-picks-bot
# Créez un bot de pronostics Discord sur les cotes Pinnacle en direct
Ce bot surveille les prix de Pinnacle sur le WebSocket de PinnFeed et publie un embed dans un salon Discord chaque fois qu'un marché fait du steam : sa cote baisse de 5 % ou plus en deux minutes, sur un marché dont la mise maximale est d'au moins 100. C'est un seul fichier d'environ 90 lignes. Il n'a besoin ni de bibliothèque Discord ni de compte bot, car il publie via un **webhook entrant** du salon.
C'est le jumeau Discord du [bot de pronostics Telegram](/fr/guides/telegram-picks-bot). La règle de détection est celle expliquée dans le [guide de détection du steam](/fr/guides/dropping-odds-steam-detection). C'est un outil pédagogique réservé aux plus de 18 ans, pas des conseils de paris.
## Étape 1 — Créez le webhook
1. Dans votre serveur Discord, ouvrez **Paramètres du serveur → Intégrations → Webhooks** et choisissez **Nouveau webhook**.
2. Donnez-lui un nom, choisissez le salon où il publiera et utilisez **Copier l'URL du webhook**.
3. Traitez cette URL comme un mot de passe : quiconque la possède peut publier dans le salon. Si elle fuit, supprimez le webhook et créez-en un autre.
## Étape 2 — Configurez l'environnement
```bash
export PINNFEED_KEY="ps_live_..." # offre Builder (WebSocket)
export DISCORD_WEBHOOK="https://discord.com/api/webhooks/..." # de l'étape 1
npm install ws
```
Si `DISCORD_WEBHOOK` n'est pas défini, le bot tourne en **mode test** : il affiche chaque alerte au lieu de la publier.
Le flux nécessite **Builder** (99 €/mois) ou supérieur. Les clés Free et Hobby reçoivent `403 plan_lacks_ws` sur `/v1/stream` ; voir les [tarifs](/fr/pricing).
## Étape 3 — Le bot
Enregistrez-le sous `discord-picks-bot.mjs` :
```javascript
// discord-picks-bot.mjs: post Pinnacle steam moves to a Discord channel through an incoming webhook.
// npm install ws Node 18+ (global fetch)
// env: PINNFEED_KEY (Builder or higher), DISCORD_WEBHOOK (channel webhook URL; unset = dry run)
import WebSocket from 'ws';
const WS_URL = process.env.PINNFEED_WS || 'wss://pinnfeed.io/v1/stream';
const { PINNFEED_KEY, DISCORD_WEBHOOK } = process.env;
const MIN_DROP = Number(process.env.MIN_DROP || 0.05); // 5% shortening...
const WINDOW_MS = Number(process.env.WINDOW_MS || 120000); // ...inside 2 minutes
const MIN_STAKE = Number(process.env.MIN_STAKE || 100); // skip thin markets
const SIDES = new Set(['home', 'away', 'draw', 'over', 'under']);
const events = new Map();
const highs = new Map(); // "marketId|outcome" -> [{t, p}]
const sent = new Map(); // "marketId|outcome" -> last alert time
const queue = []; // embeds waiting to be posted
let busy = false;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
// One worker drains the queue, so a slow or rate-limited webhook never blocks the stream.
async function drain() {
if (busy) return;
busy = true;
while (queue.length) {
const embed = queue.shift();
if (!DISCORD_WEBHOOK) { console.log('[dry run]', embed.title, '|', embed.description.replace(/\n/g, ' | ')); continue; }
for (let attempt = 0; attempt < 3; attempt++) {
const r = await fetch(DISCORD_WEBHOOK, {
method: 'POST', headers: { 'content-type': 'application/json' },
body: JSON.stringify({ embeds: [embed], allowed_mentions: { parse: [] } }),
}).catch((e) => ({ ok: false, status: 0, text: async () => e.message }));
if (r.status === 429) { const b = await r.json().catch(() => ({})); await sleep(1000 * (b.retry_after ?? 1)); continue; }
if (!r.ok) console.error('discord', r.status, await r.text());
break;
}
}
busy = false;
}
function post(embed) {
queue.push(embed);
if (queue.length > 50) queue.shift(); // an alert from minutes ago is no longer news
drain();
}
function check(m) {
const ev = events.get(m.eventId);
if (!ev || (m.maxStake ?? 0) < MIN_STAKE) return;
const now = Date.now();
for (const o of m.outcomes) {
if (!SIDES.has(o.name)) continue;
const k = `${m.id}|${o.name}`;
const h = (highs.get(k) || []).filter((x) => now - x.t < WINDOW_MS);
h.push({ t: now, p: o.decimal });
highs.set(k, h);
const high = Math.max(...h.map((x) => x.p));
const drop = 1 - o.decimal / high;
if (drop < MIN_DROP || now - (sent.get(k) || 0) < WINDOW_MS) continue;
sent.set(k, now);
const pick = o.name === 'home' ? ev.home : o.name === 'away' ? ev.away : o.name;
const line = o.points == null ? '' : m.type === 'total' ? ` ${o.points}` : ` ${o.points > 0 ? '+' : ''}${o.points}`;
post({
title: `📉 ${ev.home} v ${ev.away}`,
description: `**${pick}** (${m.type}${line})\nPinnacle ${high.toFixed(2)} → ${o.decimal.toFixed(2)} (−${(drop * 100).toFixed(1)}%)\n` +
`Fair now ${o.fair.toFixed(2)} · max stake ${m.maxStake}`,
color: 0xe8590c,
footer: { text: `${ev.sport.toUpperCase()} · ${ev.league?.name ?? ''} · 18+ · not a tip` },
timestamp: new Date(now).toISOString(),
});
}
}
function connect(delay = 1000) {
const ws = new WebSocket(WS_URL, { headers: { 'x-api-key': PINNFEED_KEY }, perMessageDeflate: true });
ws.on('open', () => {
delay = 1000;
ws.send(JSON.stringify({ type: 'subscribe', sports: ['soccer', 'tennis', 'basketball'], markets: ['moneyline', 'spread', 'total'], main: true, specials: false }));
});
ws.on('message', (raw) => {
const msg = JSON.parse(raw);
if (msg.type === 'ping') return ws.send('{"type":"pong"}');
if (msg.type === 'snapshot') msg.events.forEach((e) => events.set(e.id, e));
if (msg.type === 'delta') for (const c of msg.changes) {
if (c.kind === 'event') c.op === 'upsert' ? events.set(c.event.id, c.event) : events.delete(c.id);
if (c.kind === 'market' && c.op === 'upsert') check(c.market);
}
});
ws.on('close', () => setTimeout(() => connect(Math.min(delay * 2, 30000)), delay));
ws.on('error', (e) => console.error('ws error:', e.message));
}
connect();
```
Ce qu'il fait, dans l'ordre :
- **Il s'abonne** aux lignes principales (moneyline, handicap, total) du football, du tennis et du basket. Remplacez `sports` par l'un des 13 sports de votre offre ; le [protocole WebSocket](/docs/websocket) (en anglais) liste tous les filtres.
- **Il garde une fenêtre de 2 minutes** par marché et par issue, et signale une baisse de `MIN_DROP` par rapport au plus haut de la fenêtre. Les marchés sous `MIN_STAKE` sont ignorés, car un mouvement sur une limite faible dit peu de chose.
- **Il met les publications en file.** Un seul worker envoie les embeds au webhook, si bien qu'un webhook lent ou limité ne bloque jamais le flux. Au-delà de 50 alertes en attente, la plus ancienne est abandonnée.
- **Il respecte les 429.** Discord répond aux rafales par un `429` et une valeur `retry_after` en secondes dans le corps JSON. Le bot attend ce délai et réessaie, jusqu'à trois tentatives.
- **Aucune mention.** `allowed_mentions: { parse: [] }` empêche un nom d'équipe ou de joueur de mentionner quelqu'un dans le salon.
## Étape 4 — Lancez-le et testez-le
```bash
node discord-picks-bot.mjs
```
En mode test, une alerte s'affiche ainsi :
```text
[dry run] 📉 Udinese v Fiorentina | **Udinese** (spread +0.25) | Pinnacle 1.88 → 1.70 (−9.6%) | Fair now 1.75 · max stake 150
```
Dans Discord, la même alerte est un embed : le match en titre, le côté et le mouvement de cote dans le corps, la cote équitable sans marge et la mise maximale sur la dernière ligne, puis le sport, la ligue et la mention « 18+ · not a tip » en pied.
Réglez le volume avec des variables d'environnement, par exemple `MIN_DROP=0.08` pour des alertes plus rares et plus fortes, ou `MIN_STAKE=500` pour ne garder que les marchés plus profonds.
## Étape 5 — Gardez-le en marche
- Lancez-le sous `systemd`, `pm2` ou un conteneur qui redémarre en cas d'échec. Le bot se reconnecte seul au WebSocket avec backoff et reconstruit sa liste d'événements depuis le nouveau snapshot.
- Un webhook par salon suffit. Pour le football et le tennis dans des salons séparés, lancez deux copies avec d'autres `sports` et webhooks ; une clé Builder permet 3 connexions WebSocket.
- Tenez votre historique honnêtement : enregistrez chaque alerte et mesurez-la avec la [closing line value](/fr/guides/closing-line-value-clv-tracking) plutôt qu'avec le taux de réussite.
- Pour savoir quoi publier et comment modérer un serveur, voir le [cas d'usage des serveurs Discord](/use-cases/discord-servers) (en anglais).
## Questions fréquentes
### Quelle offre PinnFeed faut-il pour le bot Discord ?
Builder (99 €/mois) ou supérieur, car il lit le WebSocket. Pour comparer, voir la page sur le [prix du WebSocket en direct et avant-match](/fr/cheapest-pinnacle-odds-websocket). Les offres payantes ont 3 jours d'essai gratuit ; une carte est requise et elle est débitée après le jour 3 sauf résiliation.
### Puis-je le faire tourner avec l'offre Free ?
Pas tel quel. Free est uniquement REST, avec 30 secondes de retard. Pour un bot plus lent sur Free ou Hobby, interrogez `/v1/drops` une fois par minute et publiez le résultat sur le même webhook ; voir la [documentation REST](/docs) (en anglais).
### Faut-il un compte bot Discord ou discord.js ?
Non. Un webhook entrant accepte un simple `POST` JSON, le bot n'a donc besoin que de `fetch`. Utilisez un compte bot avec discord.js seulement si vous voulez des commandes slash ou des réponses.
### Comment éviter d'inonder le salon ?
Augmentez `MIN_DROP` ou `MIN_STAKE`, réduisez `sports` et gardez le délai par issue (une alerte par côté de marché par `WINDOW_MS`). La limite de la file abandonne les vieilles alertes au lieu de les publier en retard.
### Est-il légal de publier des pronostics dans un serveur Discord ?
Les règles sur les pronostics et la publicité pour les jeux d'argent varient selon les pays. En France, les jeux d'argent en ligne et leur publicité sont encadrés par l'Autorité nationale des jeux (ANJ), et la loi du 9 juin 2023 sur l'influence commerciale restreint la promotion des paris sportifs par les influenceurs. Discord a aussi ses propres règles de communauté. Vérifiez les règles là où vous et vos membres vous trouvez, réservez le serveur aux plus de 18 ans et ne présentez jamais une alerte comme un gain sûr. Ceci n'est pas un avis juridique.