Dropping Odds API: Catch Line Moves As They Happen

How a dropping odds API works: what a drop actually is, why polling misses moves, and how push-based odds drop alerts stream from Pinnacle with limit and nvp fields.
A dropping odds API tells you when a price moved, not just what the price is now. That distinction is the whole product: a snapshot endpoint gives you the current market, a drop feed gives you the transition — this selection was 2.10, it is now 1.94, here is the event, here is the max stake behind it.
If you have ever written a cron job that hits an odds endpoint every ten seconds and diffs the results, you have already built a bad version of this. It works until it doesn't, and it fails silently on exactly the moves you care about most.
What a "dropping odds" actually means
A drop is a price falling against its own recent history. Nothing more exotic than that.
Take a soccer Over 2.5 at 1.95. Money arrives, or the model updates, and it is repriced to 1.82. The implied probability went from roughly 51% to roughly 55%. That's a drop on the Over, and mechanically it is a rise on the Under — the same event described from the other side of the book. A drop feed fires on the falling side because that is the side the market is buying.
Two things people conflate with drops:
- Line movement is the broader term. A handicap moving from -0.75 to -1.0 is line movement, but it is a line change, not a price change on a fixed line. Both matter; they are different signals.
- Steam is a drop with corroboration — the same side moving fast, usually across multiple books, usually with volume behind it. A single-book drop is evidence. Steam is a pattern. Calling every drop "steam" is how people talk themselves into bad bets.
Because pinnodds sources from Pinnacle, a drop here has a specific meaning: the market that most of the industry treats as the price-setter repriced. That is a stronger signal than a soft book moving, and it is also a much lower-noise one, because Pinnacle does not shade lines to manage recreational action the way many books do.
Why polling misses the moves you want
Polling gives you interval-resolution truth about a continuous process.
Say you poll every 10 seconds. A market goes 1.95 → 1.86 → 1.93 inside your window. Your two samples read 1.95 and 1.93. You logged a 1% wobble. What actually happened was a 4.6% move and a partial retrace, which is a completely different story about who was betting and how much.
There are three separate failure modes stacked on top of each other:
- Aliasing. Fast round-trips vanish entirely. These are disproportionately the interesting ones, because speed implies conviction.
- Ordering. With a snapshot you cannot tell whether the total moved before or after the handicap. Sequence is often the signal.
- Cost. Getting to 1-second resolution across a soccer prematch board — roughly 1,500 events before you turn specials on — means a lot of requests to discover that almost nothing changed. Rate limits exist for a reason.
So pinnodds pushes. The raw market feed is a WebSocket passthrough at /ws/feed, and drops arrive as Server-Sent Events on /odds-drop (live) and /odds-drop-prematch. You hold the connection open and the transitions come to you, sub-second, in the order they happened. No diffing, no scheduler, no gaps.
The fields you get, and why each one is there
An SSE drop frame is deliberately lean. The field names matter, so here they are exactly:
sect— the market the move happened inoutcome— the specific selection that movedfrom_price/to_price— where it was, where it wentid— the eventlimit— Pinnacle's max stake on that selectionnvp— the no-vig fair price
limit is the field most people ignore and shouldn't. A drop on a market with a healthy max stake is a very different object from a drop on a market Pinnacle has throttled to pocket change. Limits contract when the book is uncertain — pre-lineup, injury rumours, thin leagues. Filtering by limit is the single cheapest false-positive filter you can write.
nvp is your margin-stripped reference. to_price is what you could bet; nvp is what the market thinks it's worth. If you are comparing Pinnacle against a soft book, compare against nvp, not against the raw price, or you will systematically overrate your edge.
One thing the SSE frame does not carry: a drop percentage. That is intentional — it is the wire format, and you already have both endpoints of the move. If you want the enriched, precomputed form, that is the REST side.
A GET /api/drops row (mode=live or mode=prematch) is the same event in fuller dress, with different names: market, designation, from, to, event_id, and a drop_pct that is already calculated for you.
Yes, the naming differs between the two surfaces. sect vs market, outcome vs designation, id vs event_id. Map it once in your ingest layer and forget it — the docs list both shapes side by side.
Worked example: stream, filter, act
Here is a real filter. Subscribe to prematch drops, ignore anything under a 3% move or with a max stake below 500, and compute the percentage yourself since the stream doesn't ship one.
import json, requests
KEY = "YOUR_KEY"
URL = "https://pinnodds.com/odds-drop-prematch?key=" + KEY
MIN_DROP_PCT = 3.0
MIN_LIMIT = 500
def drop_pct(from_price, to_price):
# implied probability delta, expressed against the original price
return (from_price - to_price) / from_price * 100
with requests.get(URL, stream=True) as r:
for raw in r.iter_lines(decode_unicode=True):
if not raw or not raw.startswith("data:"):
continue
d = json.loads(raw[5:])
pct = drop_pct(d["from_price"], d["to_price"])
if pct < MIN_DROP_PCT or d.get("limit", 0) < MIN_LIMIT:
continue
print(f"{d['id']} | {d['sect']} | {d['outcome']} | "
f"{d['from_price']} -> {d['to_price']} "
f"({pct:.1f}%) limit={d['limit']} nvp={d['nvp']}")
The official SDKs (pip install pinnodds, npm install pinnodds) wrap the same surface if you would rather not hand-parse SSE frames. Auth is one API key everywhere — x-api-key: YOUR_KEY on REST, ?key= on the streams. The key doubles as your login.
For backfill or a dashboard load, hit REST instead and let drop_pct do the arithmetic:
curl -H "x-api-key: $PINNODDS_KEY" \
"https://pinnodds.com/api/drops?mode=live"
My recommendation: SSE for anything that triggers an action, REST /api/drops for anything a human reads. Streams are for reflexes, snapshots are for review.
Where the depth pays off
Drops on the main line are the ones everyone sees. The interesting ones are usually one line over.
pinnodds passes through every line Pinnacle prices, quarter lines included — soccer totals at 1.75, 2.25, 2.75, 3.25 and quarter-ball handicaps at -0.75, -1.25, -1.75, -2.25. If your feed rounds to whole and half lines, you lose the resolution that shows you how a market is migrating. A total drifting 2.5 → 2.75 → 3.0 across three drops on adjacent lines is a much clearer read than one jump appearing out of nowhere.
Props and outrights are behind a flag. Add include_specials=1 and player/team props, exact scores, futures and outrights show up as their own event rows, each carrying special, special_category, special_markets and a parent_id pointing at the parent fixture. It is off by default for a blunt reason: soccer prematch goes from roughly 1,500 events to roughly 12,400 with it on. Turn it on when you actually want props, and expect the drop volume to scale with the payload.
What a drop does not tell you
This is the part most "dropping odds" tooling glosses over, so let's be blunabout it.
A drop has no cause attached. from_price and to_price are facts. The reason is not in the payload. A 5% move can be sharp money, a confirmed lineup, an injury tweet, a limit adjustment, a correlated move in another market, or the book's model updating on its own. If your strategy assumes every drop is informed money, you are trading on a premise the data does not support.
False positives are structural, not a bug. Common sources:
- Thin markets. Low
limit, wide spread, prices that jitter. Filter onlimit. - Pre-lineup prematch. Hours out from kickoff, prices move on very little.
- Deep alternate lines. A -2.25 handicap in a mismatch can swing on almost no volume.
- Retraces. A drop followed by an immediate reversal was noise. A drop that holds is information. The feed cannot tell you which it is at the moment it fires — only time can.
A drop is not an edge. It says the market moved. Whether you can beat it depends on what you can still get down elsewhere and at what price, and that comparison needs nvp, not the headline number.
Where this feed is the wrong tool
Be honest with yourself about the fit before you wire anything up.
- You want consensus across many books. This is Pinnacle only. If your model needs 30-40 bookmakers to compute a market average, use an aggregator — possibly alongside this, using Pinnacle as the sharp anchor and the aggregator for the soft side.
- You want a historical odds archive. There isn't one. These are live and prematch feeds; if you need years of closing lines for backtesting, you need to record it yourself from day one, or buy a historical dataset.
- You want the drop reasons. No injury feed, no news attribution, no volume figures. Prices and limits, not narrative.
- You want retail-book prices to bet into. Pinnacle's price is a reference and a signal source. It is not a survey of where you personally can get action.
- You are building a static odds comparison page. Push infrastructure is overkill for a page that refreshes on load. Hit
/kit/v1/marketsor/kit/v1/prematch/marketsand skip the stream. Note that SSE push access is a plan-level feature — depth is identical across plans, but streams start on Pro + SSE at $149/mo, with Pro at $99 for REST. Details on pricing.
Takeaway
Build your pipeline around the transition, not the snapshot. Consume /odds-drop or /odds-drop-prematch, compute your own percentage from from_price and from_price - to_price, hard-filter on limit before anything reaches your alerting layer, and treat nvp as the number you compare against — never the raw price. Then log every frame you receive, including the ones you filter out. Two weeks of your own retained stream tells you what your real drop threshold should be far better than any default someone else picked, and it is the only way to find out how often a drop in your leagues actually holds. Start with the REST endpoints to shape your data model, then switch the same handler onto the stream.
Frequently asked questions
What is a dropping odds API?
It is an API that tells you when a market's price falls against its own recent history, rather than just handing you the current price. pinnodds does this two ways: a pushed SSE stream at /odds-drop and /odds-drop-prematch, and an enriched REST snapshot at /api/drops with a precomputed drop_pct.
Why does polling an odds API miss line movement?
Because a price can move and settle back between two polls, so the interval hides it. Polling every 10 seconds gives you 10-second-resolution truth about a market that can reprice several times inside that window; a pushed feed emits the transition itself.
What fields does an odds drop alert contain?
An SSE frame from pinnodds names the market in sect, the moving selection in outcome, prices in from_price and to_price, the event in id, plus limit (Pinnacle's max stake) and nvp (the no-vig fair price). It does not include a drop percentage — /api/drops does, as drop_pct.
Is there still a public Pinnacle API?
No. Pinnacle closed its own public API in July 2025. pinnodds is an independent service that carries the same market data, including full line depth and quarter lines.
Does a dropping odds alert mean sharp money moved the line?
Not on its own. A drop can also come from an injury update, a lineup announcement, a limit change, or Pinnacle simply following its own model — the alert tells you the price changed, not why.
Get real-time Pinnacle odds in your code
The Pinnacle APIby pinnodds: live & prematch markets with instant odds-drop alerts over SSE and WebSocket. See plans and pricing, or get a free key in seconds — no card, no Pinnacle account.
Get your free API key