Why does /v1/stream return 403?
Answer: HTTP 403 with "error": "plan_lacks_ws" means that key is on Free or Hobby. Those plans have no WebSocket. Upgrade to Builder (€99/mo, VAT incl. where applicable, 3 connections) or Pro (10 connections), then connect to wss://pinnfeed.io/v1/stream with header x-api-key and send a subscribe frame within 30 seconds. If you only need snapshots, keep polling GET /v1/odds — Hobby is real-time REST; Free is delayed by about 30 seconds.
Working upgrade path#
# This fails on a Free or Hobby key:
curl -i -N -H "x-api-key: $PINNFEED_KEY" \
"https://pinnfeed.io/v1/stream"
# Look for 403 and plan_lacks_ws, then start a Builder trial and retry on wss://
const ws = new WebSocket("wss://pinnfeed.io/v1/stream?key=" + process.env.PINNFEED_KEY);
ws.onopen = () => ws.send(JSON.stringify({
type: "subscribe",
sports: ["soccer"],
live: true
}));
Prefer the x-api-key header from a server. Do not paste a paid key into a public page. Full client: Python WebSocket example. Other codes: error catalogue.
Do not confuse this with other closes#
| What you see | Meaning |
|---|---|
HTTP 403 plan_lacks_ws | Plan has no WebSocket — upgrade |
HTTP 401 invalid_key / missing_key | Wrong or missing ps_live_ key |
429 connection_limit | Builder already has 3 sockets open (Pro: 10) |
| Close code 4002 | You connected but did not subscribe within 30 s |
Plans#
Builder trial: card required, charged after day 3 unless you cancel. Free REST: signup.
Educational content for adults (18+).
Questions people ask#
Does Hobby include the socket if I poll very fast?#
No. Hobby is real-time REST only. The stream stays 403 until the key is on Builder or Pro.
Is this educational content for adults?#
Yes (18+).