On the wire · 04:55:08 UTC Live 549 · Prematch 14,380 · Markets 56,928 Vol. I · No. 5 · Friday 13 November 2026 wss://pinnfeed.io/v1/stream
PinnFeed
Tutoriel · Cloudflare · REST

Cotes Pinnacle sur un Cloudflare Worker

Mis à jour le · PinnFeed · 2 min de lecture

Réponse : stockez la clé avec wrangler secret put PINNFEED_KEY. Le handler fetch du Worker proxy /v1/odds pour votre front avec un court cache edge (la clé n'atteint jamais le navigateur) ; le handler scheduled tourne sur un cron, appelle /v1/drops et poste les nouveaux drops sur un webhook Discord. Tout est REST — fonctionne dès Free (retard 30 s).

wrangler.toml#

name = "pinnfeed-worker"
main = "src/index.js"
compatibility_date = "2026-11-01"

[triggers]
crons = ["*/2 * * * *"]
npx wrangler secret put PINNFEED_KEY      # ps_live_...
npx wrangler secret put DISCORD_WEBHOOK   # https://discord.com/api/webhooks/...
npx wrangler deploy

src/index.js#

const API = 'https://pinnfeed.io/v1';

export default {
  async fetch(req, env, ctx) {
    const url = new URL(req.url);
    if (url.pathname !== '/odds') return new Response('not found', { status: 404 });
    const sport = url.searchParams.get('sport') || 'soccer';
    const cache = caches.default;
    const cacheKey = new Request(`${url.origin}/odds?sport=${sport}`);
    let res = await cache.match(cacheKey);
    if (!res) {
      const r = await fetch(`${API}/odds?sport=${sport}&market=moneyline&main=true&limit=50`, {
        headers: { 'x-api-key': env.PINNFEED_KEY },
      });
      res = new Response(r.body, { status: r.status, headers: { 'content-type': 'application/json', 'cache-control': 'max-age=5' } });
      if (r.ok) ctx.waitUntil(cache.put(cacheKey, res.clone()));
    }
    return res;
  },

  async scheduled(_event, env) {
    const r = await fetch(`${API}/drops?sport=soccer&minutes=2&min_pct=5&limit=10`, {
      headers: { 'x-api-key': env.PINNFEED_KEY },
    });
    if (!r.ok) return;
    const { drops } = await r.json();
    if (!drops.length) return;
    const lines = drops.map((d) => `${d.home} v ${d.away}: ${d.market} ${d.outcome} ${d.from} → ${d.to} (${d.dropPct}%)`);
    await fetch(env.DISCORD_WEBHOOK, {
      method: 'POST', headers: { 'content-type': 'application/json' },
      body: JSON.stringify({ content: lines.join('\n').slice(0, 1900) }),
    });
  },
};

Limites à respecter#

Free : 1 req/s et 1 000/jour ; Hobby 2/s ; Builder 10/s. Le cache edge évite que les pics deviennent des appels API. Pour du push réel, gardez le WebSocket sur un serveur toujours allumé avec Builder (99 €/mois). Essai 3 jours ; carte requise. REST gratuit : inscription.. Lié : JS navigateur / CORS, proxy FastAPI.

Questions fréquentes#

Le Worker peut-il ouvrir le WebSocket ?#

Non de façon fiable (exécution courte). Utilisez REST ici ; WS sur un serveur long-running.

Discord est-il obligatoire ?#

Non — remplacez l'URL du webhook par Slack, Telegram, etc.

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.

Le plan WebSocket : Builder, 99 €/mois.

Les cotes Pinnacle en temps réel sur un seul WebSocket : les 13 sports, tous les marchés, cotes justes sans marge et cotes de clôture. 3 jours gratuits, résiliable en un clic.

Form K-1 · Free API key

Get your free API key.

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

By continuing you agree to the Terms and Privacy Policy.

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