On the wire · 04:53:15 UTC Live 550 · Prematch 14,382 · Markets 56,948 Vol. I · No. 5 · Friday 13 November 2026 wss://pinnfeed.io/v1/stream
PinnFeed
Tutorial · Cloudflare · REST

Pinnacle-Quoten auf einem Cloudflare Worker

Aktualisiert am · PinnFeed · 2 Min. Lesezeit

Antwort: speichere den Key mit wrangler secret put PINNFEED_KEY. Der fetch-Handler des Workers leitet /v1/odds für dein Frontend mit einem kurzen Edge-Cache weiter, sodass der Key nie im Browser landet; der scheduled-Handler läuft per Cron-Trigger, ruft /v1/drops auf und postet neue Stürze an einen Discord-Webhook. Alles REST, daher funktioniert es ab Free (30 s Verzögerung).

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) }),
    });
  },
};

Da das Cron-Fenster und das minutes-Fenster beide 2 betragen, wird jeder Sturz etwa einmal gepostet; speichere IDs in KV, wenn du strikte Deduplizierung brauchst.

Limits beachten#

Free erlaubt 1 Anfrage/s und 1.000 pro Tag, Hobby 2/s, Builder 10/s. Der Edge-Cache verhindert, dass Traffic-Spitzen zu API-Aufrufen werden. Für echten Push hältst du den WebSocket auf einem dauerhaft laufenden Server mit Builder (99 €/Monat). Testphase 3 Tage; eine Karte ist nötig und wird nach Tag 3 belastet, wenn du nicht kündigst.

Siehe auch: Browser-Apps und CORS, Discord-Bot, Dropping-Odds-API.

Bildungsinhalt für Erwachsene (18+). Keine Tipps, kein Gewinnversprechen. In Deutschland nur bei Anbietern auf der GGL-Whitelist wetten.

Häufige Fragen#

Kann ein Worker den PinnFeed-WebSocket offen halten?#

Ein normaler Worker lebt nur so lange wie die Anfrage. Ein Durable Object kann Sockets halten, aber für den Stream ist ein kleiner, dauerhaft laufender Server einfacher.

Liefert der Edge-Cache veraltete Quoten?#

Höchstens für das eingestellte max-age (hier 5 s). Senke es oder cache Live-Ansichten nicht.

Zählt der Cron gegen mein Tageskontingent?#

Ja, jeder Lauf ist eine Anfrage: alle 2 Minuten sind 720 pro Tag, innerhalb der 1.000 von Free.

Der WebSocket-Plan: Builder, 99 €/Monat.

Pinnacle-Quoten in Echtzeit über einen einzigen WebSocket: alle 13 Sportarten, alle Märkte, faire Quoten ohne Marge und Schlussquoten. 3 Tage kostenlos, mit einem Klick kündbar.

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.