TWO WAYS TO GET DROPS
SSE stream or REST drops endpoint?
The Pinnacle odds API reports price drops two ways: pushed over the SSE stream as they are detected, or pulled from the REST drops endpoint when you ask. The two carry different field names, suit different code and come with different plans. Use the stream to react and the endpoint to look back.
Same drops, two shapes
An SSE alert describes the move with from_price and
to_price, names the market in sect and the side
in outcome, and carries the sport as both sport
and sport_id. It has an id, an
alerted timestamp and the fair price in nvp. The
percentage is yours to compute.
The REST endpoint, GET /api/drops, returns the same moves as
objects with from, to, market,
side and sport_name, and it adds
drop_pct, age_s and is_live. Code
that reads one shape as if it were the other silently loses the numbers,
so the mapping is worth writing down once:
SSE alert REST drop
from_price -> from
to_price -> to
sect -> market
outcome -> side
sport -> sport_name
nvp -> nvp
(computed) -> drop_pct
When the stream is the right tool
Anything that reacts belongs on the stream: a relay into a chat channel, a bot that re-prices its own quotes, a monitor that wakes a model when a line moves. One open connection replaces a polling loop, the alert arrives as the engine detects it, and no request budget is spent waiting. Live and prematch have their own streams, so a process that needs both holds two connections.
The stream comes with the SSE alerts plan and the two combined plans. It
has no sport filter of its own; filter on sport as alerts
arrive.
When the endpoint is the right tool
Anything that looks back belongs on the endpoint: a dashboard panel that
lists the last five minutes of moves, a scheduled job that runs at the top
of each hour, a check on startup to see what happened while a relay was
down. The query selects the phase with mode=live or
mode=prematch, the size with min_drop_pct, the
window with max_age_sec and the count with
limit. Each call is a REST request and draws on the plan's
REST allowance like any other.
Because the endpoint answers with a bounded, recent window, it is not an archive. A move older than the window is gone from it, and nothing on the API replays it. The live panel on the pnclFEED home page draws exactly this call, so you can see the endpoint's own field names before you write a line.
Using both together
The two combine well in one process. At startup, call the endpoint with
max_age_sec=300 and treat the result as the alerts you missed;
then open the stream and switch to pushed alerts from there. After a
reconnect, do the same again. Deduplicate across the two sources by the
selection key rather than by alert id, since the endpoint's rows have no
stream ids; the dedupe page
sets that key out.
Common questions
Do the stream and the endpoint report the same moves?
They come from the same detection, so a move that alerts on the stream shows up in the endpoint's window as long as it is inside the requested age and above the requested percentage. The endpoint is bounded, so an old move drops out of it.
Can I poll the endpoint instead of holding a stream open?
You can, at the cost of REST requests and latency. Polling every ten seconds is 8,640 requests a day, which needs a paid REST plan, and a move still waits up to ten seconds. The stream costs no requests and delivers on detection.
Which one carries the fair price?
Both. The field is nvp on each, the no-vig price of the alerted selection after the margin is removed. It can be null, so treat it as unknown rather than zero.
Field names follow the vendor's published documentation, checked on 26 September 2026. Published .