Pinnacle odds WebSocket client in Deno
Answer: Deno ships a standard WebSocket, so no package is needed. The standard constructor has no headers option, so on the server pass the key as ?key= read from an environment variable, subscribe in onopen, reply {"type":"pong"} to each ping (every 20 s), and keep a Map of markets updated from snapshot and delta frames. Run with deno run --allow-net --allow-env stream.ts. Builder or Pro key required.
stream.ts#
const KEY = Deno.env.get('PINNFEED_KEY'); // ps_live_...
if (!KEY) throw new Error('set PINNFEED_KEY');
const markets = new Map<string, any>();
let backoff = 1000;
function connect() {
const ws = new WebSocket(`wss://pinnfeed.io/v1/stream?key=${encodeURIComponent(KEY!)}`);
ws.onopen = () => {
backoff = 1000;
ws.send(JSON.stringify({ type: 'subscribe', sports: ['basketball'], markets: ['spread', 'total'], main: true }));
};
ws.onmessage = (ev) => {
const msg = JSON.parse(ev.data);
if (msg.type === 'ping') return ws.send('{"type":"pong"}');
if (msg.type === 'snapshot') {
if (msg.part === 1) markets.clear();
for (const m of msg.markets) markets.set(m.id, m);
if (msg.final) console.log('snapshot ready:', markets.size, 'markets');
} else if (msg.type === 'delta') {
for (const ch of msg.changes) {
if (ch.kind !== 'market') continue;
if (ch.op === 'remove') markets.delete(ch.id);
else markets.set(ch.market.id, ch.market);
}
} else if (msg.type === 'error') console.error(msg.code, msg.message);
};
ws.onclose = (ev) => {
console.log('closed', ev.code, ev.reason);
if (ev.code === 4001) return; // key revoked: stop
setTimeout(connect, backoff);
backoff = Math.min(backoff * 2, 30000);
};
}
connect();
The key in the URL never leaves your server here, but keep it out of logs. Close codes: 4002 no subscribe in 30 s, 4008 slow consumer (buffer over 16 MB), 4001 key revoked.
Plans#
WebSocket on Builder (€99/mo, 3 connections) and Pro. 3-day trial; a card is required and it is charged after day 3 unless you cancel. Same pattern in TypeScript/Node and Bun.
Educational content for adults (18+).
Questions people ask#
Can I use Deno Deploy?#
Deploy is request-driven; for a 24/7 stream, run the script on a VM or container. For scheduled REST, see Supabase Edge Functions.
Why not set the x-api-key header?#
The web-standard constructor has no headers argument. The URL key works the same on the server.
Does Deno support compression?#
PinnFeed only compresses when the client negotiates permessage-deflate; see compression.