Cuotas de Pinnacle en un Cloudflare Worker
Respuesta: guarda la clave con wrangler secret put PINNFEED_KEY. El handler fetch del Worker hace de proxy de /v1/odds para tu front end con una caché corta en el edge, así la clave nunca llega al navegador; el handler scheduled se ejecuta con un cron trigger, llama a /v1/drops y publica las bajadas nuevas en un webhook de Discord. Todo es REST, así que funciona desde Free (30 s de retraso).
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) }),
});
},
};
Como la ventana del cron y la ventana minutes son ambas de 2, cada bajada se publica más o menos una vez; guarda los ids en KV si necesitas una deduplicación estricta.
Límites que respetar#
Free permite 1 petición/s y 1.000 al día, Hobby 2/s y Builder 10/s. La caché del edge evita que los picos de tráfico se conviertan en llamadas a la API. Para push real, mantén el WebSocket en un servidor siempre encendido con Builder (€99/mes). Prueba de 3 días; se pide tarjeta y se cobra después del día 3 salvo que canceles.
Relacionado: apps de navegador y CORS, bot de Discord, API de cuotas que bajan.
Contenido educativo para mayores de 18 años. Sin pronósticos ni ganancias garantizadas. En España, apuesta solo con operadores con licencia de la DGOJ.
Preguntas frecuentes#
¿Puede un Worker mantener abierto el WebSocket de PinnFeed?#
Un Worker normal vive lo que dura la petición. Un Durable Object puede mantener sockets, pero para el stream es más sencillo un pequeño servidor siempre encendido.
¿La caché del edge sirve cuotas viejas?#
Como mucho durante el max-age que pongas (5 s aquí). Bájalo, o no caches las vistas en vivo.
¿El cron cuenta para mi cuota diaria?#
Sí, cada ejecución es una petición: cada 2 minutos son 720 al día, dentro de las 1.000 de Free.