WebSocket feed · /ws/feed

One open socket. Every price that moves.

Instead of asking for the board over and over, connect once to PinnRadar's WebSocket and let Pinnacle's live and prematch changes come to you, across every sport on the feed.

wss://pinnradar.com/ws/feed · key in the URL · not affiliated with Pinnacle

Connection
1, persistent
Streams
live + prematch
Payload
Raw, unmodified
Add-on
$99 / month

01 · Push vs pull

Polling shows you the past.

With REST you learn about a move on your next request, and each request costs quota. A socket stays open and hands over each change as it lands, so quick lines and steam reach you sooner.

REST pollingpinnradar ws
When you see a changeAt your next pollPushed as it happens
Quota spentOne request per pollNothing per message
Moves between checksCan be missedEach frame arrives
State on reconnectPoll againFresh snapshot sent
Best fitOccasional readsKeeping a full book in memory

02 · A session

Connect, subscribe, keep up.

  1. Open the socket at wss://pinnradar.com/ws/feed?key=…. A key without the add-on is turned away with HTTP 403 plan_lacks_ws.
  2. Subscribe within five seconds. Name whole sports, single event_ids, or both, on the live and/or prematch stream. Up to 200 event ids per stream.
  3. Load the baseline. A snapshot frame lists every event the server holds for that group. Big ones, such as prematch soccer, are split into parts numbered by seq, with final: true on the last.
  4. Apply the updates. After that, each upstream change arrives as its own frame. Merge the changed markets into the event, and remove it on op: "del". The docs carry a complete merge recipe.
  5. Answer the ping. Every 30 seconds the server sends ping; reply with pong. If the connection drops, reconnect and a new snapshot rebuilds your state.
python · websocketsfeed.py
import asyncio, json, os, websockets

URL = "wss://pinnradar.com/ws/feed?key=" + os.environ["PINNRADAR_KEY"]
book = {}

async def main():
    async with websockets.connect(URL, max_size=None) as ws:
        # tennis (2) on both streams
        await ws.send(json.dumps({"type": "subscribe",
            "streams": ["live", "prematch"], "sport_ids": [2]}))
        async for raw in ws:
            m = json.loads(raw)
            if m["type"] == "ping":
                await ws.send('{"type":"pong"}')
            elif m["type"] == "snapshot":
                for ev in m["events"]: book[ev["id"]] = ev
            elif m["type"] == "live":
                # op is add, upd (changed markets only) or del
                print(m["op"], m["rec"]["id"])

asyncio.run(main())

Clients for Node, Go and PHP, plus the full frame schema, are in the documentation.

03 · On the wire

What arrives, frame by frame.

The socket relays upstream records as received, wrapped in a small envelope. It does no drop detection of its own; that lives on the SSE streams.

snapshot

Baseline state

All events for a subscribed sport, or the records for the ids you named. Split with seq / final when large.

live

In-play change

Carries the upstream topic, an op such as upd or del, and the record in rec, all passed through untouched.

prematch_*

Pre-game updates

prematch_matchups lists a sport's fixtures each board cycle; prematch_markets is the full market list of one fixture whose version moved.

ping

Heartbeat

Every 30 s, with buffered_max_bytes so you can tell whether your reader is falling behind.

subscribed

Confirmations

Each subscribe and unsubscribe is acknowledged. Trust the reply and the snapshot, not the fact that your send succeeded.

compression

Enable deflate

Turn on permessage-deflate in your client: live frames shrink about five-fold, which matters for far-away or high-volume readers.

04 · Guard rails

Limits worth knowing.

RuleTriggerWhat to do
event_id_capMore than 200 event ids on one streamDrop finished matches; deleted events free their ids automatically
sport_id_capOver 32 sport ids in a single subscribeSplit the list across messages
subscribe_rate_limitedAbove 30 subscribes in 10 secondsBatch more into each message
slow_consumerOver 128 MB queued because you read slowlyReconnect, read faster or follow less
rate_limited (429)Too many connection attemptsWait for Retry-After, back off

05 · Access

An add-on, not a separate product.

The socket is sold as a $99 monthly add-on to any plan that includes REST: REST, Edge or Scale. Added mid-cycle, it is prorated to your renewal date; bought together with a plan it is $99 for 30 days, $297 for 90 and $594 for 180.

It is not available with the Free or Drops plan, which have no REST quota. If you only need alerts rather than the whole stream, the SSE drop streams are the lighter option.

Want to try it before paying? Message @PinnRadarSupport on Telegram or write to info@pinnradar.com if you need longer. Every new account starts with a three-day full demo that opens the socket, the SSE streams and REST at 10 requests a second.

Full plan details are on the pricing page.

06 · Questions

Socket questions.

Stuck on a frame or a close code? Message @PinnRadarSupport on Telegram or email info@pinnradar.com.

Does Pinnacle offer its own WebSocket API?

There is no public WebSocket from Pinnacle. PinnRadar runs one: its /ws/feed socket pushes Pinnacle's live and prematch market updates to you, so you stop polling for them.

How fresh are the frames?

Each update is forwarded as it happens, with no polling interval anywhere in the path. After a reconnect, a fresh snapshot brings your copy back to the current state.

Will my existing Pinnacle client code work?

The REST endpoints follow the response layout common third-party Pinnacle clients already read, so the base URL and key are usually all that change. The socket itself relays upstream records unmodified inside a thin envelope, as described in the frame reference.

Which sports and markets come through the socket?

All 13 sports on the feed, soccer, tennis, basketball, baseball, hockey and MMA included, in both live and prematch. Moneyline, spreads, totals, team totals and specials all travel on it.

Which plans can add the WebSocket?

The add-on costs $99 a month on top of REST, Edge or Scale, prorated if you add it mid-cycle. It is not sold with the Free or Drops plan. To test it first, sign up: every new account starts with a three-day full demo that unlocks the socket.

Stop polling the board.

Start on a free key, add the socket when your system is ready for it, and keep one connection open instead of thousands of requests.