Proxy de cotes Pinnacle avec FastAPI
Réponse : lancez une petite app FastAPI qui lit PINNFEED_KEY depuis l'environnement, appelle /v1/odds avec httpx, met le résultat en cache quelques secondes et ne renvoie que les champs utiles. Le navigateur parle à votre API ; la clé ne quitte pas le serveur, et le cache garde beaucoup de visiteurs dans votre rate limit.
app.py#
import os, time
import httpx
from fastapi import FastAPI, HTTPException
KEY = os.environ["PINNFEED_KEY"] # ps_live_...
API = "https://pinnfeed.io/v1"
TTL = 5 # seconds
cache: dict[str, tuple[float, list]] = {}
app = FastAPI()
client = httpx.AsyncClient(headers={"x-api-key": KEY}, timeout=10)
@app.get("/odds/{sport}")
async def odds(sport: str, q: str | None = None):
ck = f"{sport}|{q}"
hit = cache.get(ck)
if hit and time.time() - hit[0] < TTL:
return hit[1]
params = {"sport": sport, "market": "moneyline", "main": "true", "limit": 100}
if q:
params["q"] = q
r = await client.get(f"{API}/odds", params=params)
if r.status_code != 200:
raise HTTPException(r.status_code, r.json().get("error", {}).get("message", "upstream error"))
rows = [
{"id": e["id"], "home": e["home"], "away": e["away"], "start": e["startTime"], "live": e["live"],
"prices": {o["name"]: o["decimal"] for m in e["markets"] for o in m["outcomes"]},
"maxStake": max((m["maxStake"] or 0) for m in e["markets"]) if e["markets"] else None}
for e in r.json()["events"]
]
cache[ck] = (time.time(), rows)
return rows
Lancez avec pip install fastapi uvicorn httpx puis uvicorn app:app --port 8000, et appelez /odds/soccer?q=arsenal.
Notes prod#
- Ajoutez votre auth ou un rate limit sur le proxy s'il est public.
- Respectez
429avecRetry-Afterde PinnFeed ; plans : 1 (Free), 2 (Hobby), 10 (Builder) ou 30 (Pro) req/s. - Pour les tableaux live, un WebSocket serveur (Builder) et fan-out : WebSocket Python.
CTA#
Builder (99 €/mois). Essai 3 jours ; carte requise. REST gratuit : inscription. Autres hôtes : Cloudflare Worker, Supabase. Lié : JS navigateur / CORS.
Questions fréquentes#
Pourquoi ne pas appeler PinnFeed depuis JavaScript ?#
CORS le permet, mais la clé serait publique : JS navigateur et CORS.
Le cache rend-il les cotes périmées ?#
Jusqu'à TTL secondes. 1–5 s pour le prematch ; WebSocket pour le live.
Puis-je utiliser Flask ?#
Oui ; même motif avec requests et un dict cache.
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.