Odds drop time interval filter for recent Pinnacle odds movement
PinnWire gives you a clear, programmable odds alert time window API: query recent detected drops with REST, receive new drops over SSE, and own the rolling-window and cooldown rules that fit your product.
max_age_sec for recency, not as a scan interval.
PinnWire's /api/drops and /v1/drops endpoints return detected price drops from a recent in-memory buffer. Set max_age_sec=180 for the newest three minutes, for example. For push alerts, use /odds-drop or /odds-drop-prematch; use prematch recheck when the move must persist. Keep longer rolling windows, reconnect backfill, and notification cooldowns in your application.
Three different meanings of “time window”
An odds drop time interval filter sounds like one setting, but an alert system usually has three separate clocks. Keeping them separate makes recent Pinnacle odds movement easier to audit and prevents a recency filter from being mistaken for historical tracking.
How recent is the detection?
max_age_sec filters PinnWire's recent drop buffer by detection age. It is ideal for a dashboard refresh, poll, or reconnect backfill.
Did the move hold?
recheck=N on prematch SSE waits N seconds, reads the current price, and emits only if the original drop still clears your min_drop.
When should you notify?
A rolling analysis window and alert cooldown belong in your client. You can change them without changing the PinnWire alert stream or inventing an unsupported query parameter.
Try a three-minute odds alert time window
The public demo key can test the REST endpoint without signup. It is a shared, capped allowance; use a free emailed trial key for development or repeated requests.
curl "https://pinnwire.com/api/drops?mode=live&min_drop_pct=2&max_age_sec=180&markets=moneyline,spread,total&periods=0&limit=25&key=demo&fresh=time-window-1"
This asks for live drops detected in the last three minutes, with a minimum 2% decimal-price fall, full-match period 0, and at most 25 newest rows. fresh is an optional cache-buster; it does not change the filter.
{
"total": 1,
"generated_at": "2026-08-26T10:05:12.412Z",
"drops": [{
"event_id": 1629725918,
"sport_name": "Soccer",
"market": "spread",
"period": 0,
"side": "home",
"points": -0.5,
"from": 2.37,
"to": 2.25,
"drop_pct": 5.06,
"nvp": 2.21,
"is_live": true,
"alerted": 1787738712,
"age_s": 12
}]
}
generated_at dates the response. Each REST drop has age_s for detection recency and alerted as an epoch-second detection timestamp. The REST shape uses decimal from/to prices; the drop percentage is the fall between them.
What max_age_sec actually does
max_age_sec is a precise “newer than this many seconds” filter over PinnWire's existing drop buffer. It does not schedule a scan, change how the feed is sampled, or create a comparison point exactly three minutes earlier.
PinnWire records a drop when a tracked decimal price falls by at least 1% against the previous price observed for that event, market, outcome, and points. The REST query then filters those detected records by age, threshold, sport, market, period, live state, and limit. A request with max_age_sec=30 can return an empty list simply because no qualifying drop was detected in that interval.
Supported REST controls for a time-window filter
These parameters apply to GET /api/drops and the alias /v1/drops. They filter the latest live or prematch drop buffer, which holds roughly three hours of detections.
| Parameter | Example | Use it for |
|---|---|---|
mode | live or prematch | Choose the live or prematch drop buffer. Default: live. |
max_age_sec | 300 | Return only detections from the latest five minutes. This is the server-side recency window. |
min_drop_pct | 2 | Require at least a 2% fall. Fractional values are accepted; recorded drops still have a 1% floor. |
max_drop_pct | 12 | Optionally cap the percentage, useful for separating ordinary moves from outliers. |
sport_id | 1 | Restrict results to one sport. See the sports list. |
markets | moneyline,spread | Filter exact market types: moneyline, spread, total, or team_total. |
periods | 0,1 | Filter numeric periods. Keep period in your market key. |
live | 1 | Exclude rows whose scheduled start is still in the future. |
limit | 25 | Cap the newest rows returned. Default: 500. |
Use the smallest window that fits the job, then measure empty responses, alert volume, and useful-alert rate. A time window is a freshness decision—not a promise that a market will move inside it.
Pick a window for the job
Start with a clear purpose instead of a magic interval. These are practical starting points for a PinnWire client, not guaranteed betting outcomes:
60–180 seconds
Use max_age_sec=60, 120, or 180 for a live action queue where stale recent Pinnacle odds movement is less useful.
300–900 seconds
A five- to fifteen-minute window is a balanced starting point for dashboards and scheduled checks that can tolerate a little context.
1,800–10,800 seconds
Use a longer window for reconnect backfill or a short investigation. The upper bound is roughly three hours because the buffer is in memory, not permanent storage.
For broad discovery, lower the threshold and inspect the returned volume. For a human notification, raise the threshold and add a client cooldown. Do not lower a REST threshold expecting sub-1% events: events below PinnWire's 1% recording floor were never added to the buffer.
Use SSE when the window means “alert me now”
REST is excellent for recent windows, tuning, dashboards, and recovery. If your process should receive a new detected drop without polling, PinnWire's SSE stream is the better fit.
curl -N "https://pinnwire.com/odds-drop?key=YOUR_KEY&min_drop=2"
For prematch, choose the dedicated endpoint. The recheck value is a persistence check, not a scan interval:
curl -N "https://pinnwire.com/odds-drop-prematch?key=YOUR_KEY&min_drop=3&recheck=30"
Here PinnWire holds a candidate for 30 seconds, re-reads its current price, and emits it only if the fall still passes the threshold against the original from_price. If the price bounces back, that candidate is suppressed. recheck is available on prematch SSE and ignored on the live endpoint.
/api/drops instead; the API returns a readable plan message when SSE is not enabled.Reconnect, backfill, and deduplicate
An SSE client should assume that a process can restart or lose a network connection. Record the last detection timestamp you accepted, reconnect, then query an overlapping REST window before trusting the new stream alone. The overlap closes the small gap between disconnect and reconnect; a stable key removes duplicates.
const API = "https://pinnwire.com";
const KEY = "YOUR_KEY";
const seen = new Set();
let lastAlerted = Math.floor(Date.now() / 1000) - 60;
function identity(d) {
const eventId = d.event_id ?? d.id;
const market = d.market ?? d.market_type;
const side = d.side ?? d.outcome ?? "";
return [eventId, market, d.period ?? "", side, d.points ?? "", d.alerted ?? ""].join("|");
}
function accept(d) {
const stamp = Number(d.alerted) || 0;
const id = identity(d);
if (seen.has(id)) return;
seen.add(id);
if (stamp) lastAlerted = Math.max(lastAlerted, stamp);
notifyIfInRollingWindow(d);
}
async function backfill() {
const now = Math.floor(Date.now() / 1000);
// Thirty seconds of overlap catches the reconnect edge; cap at the buffer.
const age = Math.min(10800, Math.max(60, now - lastAlerted + 30));
const url = new URL(`${API}/api/drops`);
url.search = new URLSearchParams({
mode: "live", min_drop_pct: "2", max_age_sec: String(age),
limit: "500", key: KEY, fresh: String(Date.now())
});
const body = await (await fetch(url)).json();
for (const drop of (body.drops ?? []).reverse()) accept(drop);
}
function connect() {
const stream = new EventSource(`${API}/odds-drop?key=${encodeURIComponent(KEY)}&min_drop=2`);
stream.onmessage = (event) => {
for (const drop of JSON.parse(event.data)) accept(drop);
};
stream.onerror = () => {
stream.close();
setTimeout(async () => { try { await backfill(); } finally { connect(); } }, 5000);
};
}
connect();
The REST and SSE shapes use different field names: REST maps the event to event_id, market, side, from, and to; SSE keeps fields such as id, market_type, outcome, from_price, and to_price. Normalize both before applying your policy. Keep a bounded seen store in production, and persist accepted events if recovery must cover more than the in-memory buffer.
Build rolling windows and notification cooldowns client-side
A recency query tells you what was detected recently. A rolling window tells your strategy how to interpret a sequence of detections. A cooldown tells your notification layer how often to speak. Those are separate decisions and are easy to express in a small client policy.
const WINDOW_MS = 10 * 60 * 1000; // strategy context: ten minutes
const COOLDOWN_MS = 90 * 1000; // notification policy: 90 seconds
const lastNotified = new Map();
function notifyIfInRollingWindow(drop) {
const detectedAt = Number(drop.alerted) * 1000;
if (!detectedAt || Date.now() - detectedAt > WINDOW_MS) return;
const key = [
drop.event_id ?? drop.id,
drop.market ?? drop.market_type,
drop.period ?? 0,
drop.side ?? drop.outcome ?? "",
drop.points ?? ""
].join("|");
const previous = lastNotified.get(key) ?? 0;
if (Date.now() - previous < COOLDOWN_MS) return;
lastNotified.set(key, Date.now());
sendAlert(drop);
}
Include participant_name in the key when you process specials or props. Keep the market type, period, and points: a full-match spread is not the same line as a first-half spread or a different handicap. For an event-level alert, deliberately aggregate those exact market keys instead of accidentally collapsing them.
Freshness, limits, and longer history
Check response freshness
REST responses include generated_at. Drop rows include age_s, while /v1/health exposes last_odds_update_seconds_ago. Use those fields before presenting data as current, and add a unique fresh query value if a client cache is suspected.
Respect the recent buffer
PinnWire's drop buffer covers roughly the latest three hours and is rebuilt in memory as the live feed runs. It is useful for recent windows and reconnects, not a permanent historical archive.
Persist your own timeline
Write accepted REST drops, SSE events, snapshots, or raw WebSocket updates to your database when you need a day, week, opening-line study, chart, or closing-line analysis.
For the complete current board, use the PinnWire REST docs. For every live and prematch market update—including moves that are not drops—use the optional PinnWire Pinnacle WebSocket API.
Choose the right PinnWire surface
| Goal | PinnWire surface | Time-window responsibility |
|---|---|---|
| Show recent detected drops | /api/drops or /v1/drops | Set max_age_sec; filter further in your client. |
| Alert on a new live drop | /odds-drop | Set min_drop; reconnect and backfill with REST. |
| Alert on a persistent prematch move | /odds-drop-prematch | Set min_drop and optional recheck=N. |
| Track every reprice | Optional raw /ws | Choose your own observation storage and comparison interval. |
| Keep long-term movement history | Your database plus PinnWire data | Persist events or snapshots; the API buffer is roughly three hours. |
For most alert products, the strongest pattern is PinnWire SSE for immediate delivery, REST for a focused recent window and reconnect recovery, and a client-side policy for rolling analysis and notification frequency. That combination keeps the API signal fast while leaving strategy decisions in code you control.
Odds drop time window questions
What is the best way to filter recent Pinnacle odds movement?
Use PinnWire's REST drop endpoint with mode, min_drop_pct, and max_age_sec to query detected drops from a precise recency window. Use the SSE drop stream for push delivery, then apply any longer rolling window or notification cooldown in your own application.
Is max_age_sec a Pinnacle odds drop time interval?
max_age_sec is a recency filter: it returns detections newer than the specified number of seconds. It is not a server-side scan schedule and does not compare a price with the price exactly N minutes earlier. Persist snapshots or use the optional raw WebSocket when you need that interval comparison.
How do I receive PinnWire odds alerts in real time?
Connect to /odds-drop for live drops or /odds-drop-prematch for prematch drops with min_drop as the percentage threshold. On prematch, recheck=N can hold a candidate and emit it only if the drop still passes after N seconds.
How should an odds alert client recover after disconnecting?
Record each drop's alerted detection timestamp, reconnect the SSE stream, and backfill an overlapping recent window through /api/drops with max_age_sec. Deduplicate by event, market, period, side, points, and detection time, then keep the backfill window within PinnWire's roughly three-hour buffer.
Does PinnWire provide a permanent odds movement history?
No. PinnWire keeps a recent in-memory drop buffer of roughly three hours. Persist accepted drops, REST snapshots, or raw WebSocket updates in your own storage for longer rolling windows, charts, opening lines, or closing-line analysis.
key=demo to test recent Pinnacle odds movement in REST, then get a free emailed trial key for a private allowance. Choose SSE for real-time detected drops, add prematch recheck when persistence matters, and keep your rolling strategy window and cooldown policy in code you own.