Odds da Pinnacle num Cloudflare Worker
Resposta: guarde a chave com wrangler secret put PINNFEED_KEY. O handler fetch do Worker faz proxy de /v1/odds para o seu front end com um cache curto no edge, então a chave nunca chega ao navegador; o handler scheduled roda num cron trigger, chama /v1/drops e publica as quedas novas num webhook do Discord. É tudo REST, então funciona a partir do Free (30 s de atraso).
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 a janela do cron e a janela minutes são ambas de 2, cada queda é publicada mais ou menos uma vez; guarde os ids no KV se precisar de deduplicação estrita.
Limites a respeitar#
O Free permite 1 requisição/s e 1.000 por dia, o Hobby 2/s e o Builder 10/s. O cache do edge evita que picos de tráfego virem chamadas à API. Para push de verdade, mantenha o WebSocket num servidor sempre ligado com o Builder (€99/mês). Teste de 3 dias; cartão obrigatório, cobrado após o dia 3 a menos que você cancele.
Relacionado: apps de navegador e CORS, bot de Discord, API de odds em queda.
Conteúdo educativo para maiores de 18 anos. Sem palpites nem lucro garantido. No Brasil, aposte apenas em operadores autorizados pela SPA/MF.
Perguntas frequentes#
Um Worker consegue manter o WebSocket do PinnFeed aberto?#
Um Worker comum dura o tempo da requisição. Um Durable Object pode manter sockets, mas para o stream um pequeno servidor sempre ligado é mais simples.
O cache do edge entrega odds velhas?#
No máximo pelo max-age que você definir (5 s aqui). Diminua, ou não faça cache nas visões ao vivo.
O cron conta na minha cota diária?#
Sim, cada execução é uma requisição: a cada 2 minutos são 720 por dia, dentro das 1.000 do Free.