How to Get Instant Alerts When Pinnacle Odds Drop Below Your Threshold
Open an SSE stream to pinnapi's odds-drop endpoint, set min_drop to your threshold, and Pinnacle drops reach your code in tens of milliseconds. Here's how.
How to Get Instant Alerts When Pinnacle Odds Drop Below Your Threshold
People ask this in almost the same words every time: how do I get instant alerts when Pinnacle odds drop below a certain threshold? Here is the whole answer in three moves. Open a Server-Sent Events connection to pinnapi's odds-drop stream, put your threshold in the URL with min_drop, and handle the JSON frames that arrive whenever a price falls by at least that much. The watching happens on our side; your code only wakes up when something actually dropped. The rest of this post is the working detail: endpoints, auth, the payload, two runnable clients, and the honest limits.
The two endpoints
One stream per phase of the match:
https://pinnapi.com/odds-dropfor live, in-play dropshttps://pinnapi.com/odds-drop-prematchfor upcoming fixtures
Both are plain SSE over HTTPS, available on the Drops, Edge, and Scale plans. If you want raw odds frames rather than filtered drop events, that is a different transport, covered in the WebSocket guide; this post is about the alert stream.
Auth, including the one that doesn't work
Two ways in. The normal one is a header, x-portal-apikey: YOUR_KEY (x-api-key is accepted too). The second is a query parameter, ?key=YOUR_KEY, and it exists for a specific reason: the browser's EventSource API cannot set custom headers, so a purely client-side page has to carry the key in the URL. One negative worth stating because it costs people real debugging time: Authorization: Bearer does not work on this API. Header or query param, nothing else.
The threshold: min_drop
This is the heart of the feature. ?min_drop=N sets your threshold in percent. The default is 5 and the minimum is 1. min_drop=7 means you only hear about prices that fell 7% or more; min_drop=1 means every drop, including the small ones. The filtering is server-side: you pick the number, our side does the watching, and nothing crosses the wire unless it cleared your bar. That is what makes this an alert system rather than a diff job you run yourself on snapshots.
Prematch has one extra dial. ?recheck=N holds each alert for N seconds and re-verifies the price before emitting it. Prematch lines flick down and bounce straight back all the time; recheck filters those flickers so that what reaches you is a move that held. Survivors gain a rechecked_ms field carrying the actual wait, bounced prices are silently suppressed, and omitting the parameter (or passing 0) gives you the default instant feed. What a real drop tends to mean, and why the sharp line moves at all, is its own topic.
What arrives on the wire
The first frame after connecting is a handshake, {"type": "connected", "id": "..."}. After that, each data: frame carries a JSON array of drop objects. Here is a real one, captured live and trimmed:
{
"home": "Joao Silva",
"away": "Pedro Vives Marcos",
"league": "ATP Challenger Porto - Qualifiers",
"sport": "Tennis",
"sect": "Moneyline",
"outcome": "Home",
"period": 0,
"from_price": 18.57,
"to_price": 15.0,
"limit": 100.0
}
That is a tennis moneyline falling from 18.57 to 15.0, roughly a 19% drop, pushed the moment it happened. Per the docs, the payload also carries the no-vig price for the market, so you can compute an edge against a soft book without a second request.
Coverage, and the honest limit that goes with it: drop alerts watch the main markets, meaning moneyline, spreads, totals, and team totals, per period. Specials and player props do not fire drop alerts; if you need to track a prop over time, you poll and diff it yourself.
A Python client
Minimal and runnable: stream the live endpoint with your threshold at 7%, skip the handshake, print the drops.
import os, json, requests
KEY = os.environ["PINNAPI_KEY"]
URL = "https://pinnapi.com/odds-drop?min_drop=7"
with requests.get(URL, headers={"x-portal-apikey": KEY}, stream=True, timeout=None) as r:
r.raise_for_status()
for line in r.iter_lines(decode_unicode=True):
if not line or not line.startswith("data:"):
continue
payload = json.loads(line[5:].strip())
if isinstance(payload, dict): # "connected" handshake or an error frame
if payload.get("type") == "error":
raise RuntimeError(f'{payload.get("error")}: {payload.get("message")}')
continue
for drop in payload:
print(f'{drop["home"]} vs {drop["away"]}: '
f'{drop["from_price"]} -> {drop["to_price"]} ({drop["sect"]})')
A browser client
// EventSource cannot set custom headers, which is why the key goes in the URL
const es = new EventSource("https://pinnapi.com/odds-drop?min_drop=7&key=YOUR_KEY");
es.onmessage = (e) => {
const payload = JSON.parse(e.data);
if (payload.type === "connected") return;
if (payload.type === "error") { console.error(payload.error, payload.message); return; }
for (const drop of payload) {
console.log(`${drop.home} vs ${drop.away}: ${drop.from_price} -> ${drop.to_price}`);
}
};
Make it an alert
The stream handler is the trigger; everything after it is a few lines of plumbing. Wherever you want the ping (a Telegram bot message, a Discord webhook, a push service, or straight into your trading logic), call it from the loop:
for drop in payload:
pct = (drop["from_price"] - drop["to_price"]) / drop["from_price"] * 100
msg = (f'{drop["sport"]}: {drop["home"]} vs {drop["away"]} '
f'{drop["from_price"]} -> {drop["to_price"]} ({pct:.0f}% drop)')
send_telegram(msg) # or post_discord_webhook(msg), or hand it to your bot
We will not fake any specific service's API here; each is a few documented lines. The point is architectural: because the filtering is server-side, the handler stays small and every message it sends already cleared your threshold. On speed, the push path runs in our published 15–40 ms band (methodology here), so "instant" means tens of milliseconds, not a polling interval.
What you do with the alert is the strategy half: a hard drop at the sharpest book is often a steam move forming, and there is a whole discipline to trading the line's direction. This post's job ends at getting the signal to your code fast.
Takeaway
Connect to odds-drop or odds-drop-prematch with your key, set min_drop to the percentage you care about, add recheck on prematch if flickers annoy you, and handle arrays of drop objects as they arrive. Main markets only, props excluded, and the threshold decision is yours rather than ours. That is the entire feature: you define "worth waking up for," and the stream honors it.
Frequently asked questions
How do I get instant alerts when Pinnacle odds drop below a certain threshold?
Open an SSE connection to https://pinnapi.com/odds-drop (live) or https://pinnapi.com/odds-drop-prematch (upcoming) with your API key and min_drop=N in the URL, then handle the JSON frames that arrive whenever a price falls by N percent or more. The filtering runs server-side, so your code only hears about drops that cleared your threshold.
Can I set my own drop threshold?
Yes, with the min_drop query parameter. The default is 5 percent and the minimum is 1: min_drop=7 delivers only drops of 7% or more, while min_drop=1 delivers every drop including the small ones.
Does it work for prematch as well as live?
Yes, through two endpoints: live drops stream from /odds-drop and upcoming fixtures from /odds-drop-prematch. The prematch stream adds recheck=N, which holds each alert for N seconds and re-verifies the price, so flickers that bounce straight back never reach you.
Do player props trigger drop alerts?
No. Drop alerts watch the main markets, meaning moneyline, spreads, totals, and team totals per period; specials and player props do not fire them. Track prop movement by polling snapshots and diffing them yourself.
How fast do the alerts arrive?
The push path runs in our published 15–40 ms band to a nearby client. That is our measurement under our stated conditions, so reproduce it from your own infrastructure before you build anything latency-critical on top of it.
Get real-time Pinnacle odds in your code
Live & prematch markets with sub-second odds-drop alerts. Free trial key in seconds — no card.
Start free trial