SSE SETUP
Connect the Pinnacle API SSE drop stream.
One HTTPS request to the Pinnacle odds API that never finishes. The server writes drop events to it as Pinnacle prices fall, and your client reads, filters and reconnects. This page covers the connection, the frame format, and where your rule state belongs.
Opening the Pinnacle API stream
The stream is plain HTTPS. Send a GET to /odds-drop for live
markets or /odds-drop-prematch for prematch ones, with your
key in the x-portal-apikey header or as ?key=.
Set min_drop yourself rather than relying on the default: the
documented example uses 5, and it goes as low as 1. A 200 response with a
text/event-stream content type means the connection now stays
open and alerts arrive as drops are detected.
GET /odds-drop?min_drop=5 HTTP/1.1
Host: <api host from the docs>
Accept: text/event-stream
x-portal-apikey: <your key>
Any HTTP client that reads a response incrementally works: curl for a
smoke test, your language's HTTP library in production. The browser's
EventSource can connect with ?key=, but that puts the key in a
URL every visitor can read, so run the reader server-side. Each account
gets one connection per stream: a second live connection with the same key
closes the first, while a live and a prematch connection can run side by
side. On the prematch stream, recheck=N holds each drop for N
seconds and sends it only if the price has not bounced back.
Event shape
Every message is a data: line. The first is a control object;
after it, each batch of alerts is a JSON array. This is the documented
example, trimmed:
data: {"type": "connected", "id": "d648beb8-..."}
data: [{"home": "Sunshine Coast Phoenix", "away": "Cairns Dolphins", "league": "Australia - NBL1 Women", "sport": "Basketball", "sect": "Moneyline", "outcome": "Home", "period": 4, "from_price": 2.86, "to_price": 2.7, "nvp": 3.04, "id": 1629729400, "alerted": 1777625196, ...}]
Parse each data: line as JSON. An object is a control
message: connected when the stream opens, or an error such as
plan_lacks_sse when the key's plan has no stream. An array is
a batch of alerts. Each alert names the line with sport,
league, sect, outcome and
period, carries the price before and after as
from_price and to_price, adds nvp,
the no-vig fair price after the move, and stamps the alert time in Unix
seconds as alerted. The percentage is yours to compute:
(2.86 − 2.70) ÷ 2.86 = 5.6%.
Reconnects and quiet periods
Connections die: proxies idle out, networks flap, deploys happen.
Reconnect with a pause that grows after each failure. A client that
reconnects in a tight loop gets a single rate_limited error
frame with a Retry-After: 60 header, so honor it instead of
hammering the endpoint.
Missed alerts are not replayed: the documentation promises no resume point, so treat anything that fell during the gap as missed. When a gap matters, fill it from the REST drops endpoint, which keeps recent drops for up to about three hours with a timestamp on each.
Quiet stretches are normal, prematch especially. To tell a quiet market from a broken feed, poll the health endpoint alongside the stream: it reports how long ago the live feed last wrote. If that age keeps growing while your connection says nothing, close it and reconnect.
Keeping rule state server-side
Thresholds, seen-alert sets and dedupe windows belong on the server, not in a browser tab that can sleep or close. The reader process owns the connection; whatever evaluates your rules should sit next to it.
Make processing idempotent. Build the dedupe key from id,
sect, outcome, period and
alerted rather than from one field, and drop duplicates before
your rule runs. Persist the last alert time you processed along with your
rule state, and a restart resumes cleanly instead of re-alerting on moves
you already handled.
When raw frames beat SSE
SSE is the right default for alerting: the stream detects the drops, and your client only handles events that already crossed a line. Choose raw WebSocket when your application needs every frame, because you rebuild the full market state yourself instead of consuming finished drop events. That covers tracking books that have not moved enough to alert, or applying detection logic the drop stream was never meant to run. The raw WebSocket add-on is $99 per 30 days on REST and combined plans. If your rule only reacts to drops, stay on SSE; everything on this page still applies.
Test your rule first
Before you hold a connection open, check the rule on paper. The drop alerts guide covers the percentage formula and how thresholds, windows and filters compose. Streaming access options are listed under plans.
When the rule holds up on paper, connect the stream and let it run.
If you would rather start from working code, the Python quickstart on pnclFEED has an SSE listener that reads this stream as it is.