What betting turnover means
Betting turnover is the total amount staked across a period. In a value workflow, the useful goal is not simply to make that number larger. The useful goal is to process more qualified opportunities while keeping your expected-value threshold, market matching, freshness rules, and staking plan intact.
More turnover can improve expected results when the average quality of the decisions stays acceptable. It can also make results worse when a system responds to a quiet market by lowering its edge threshold, accepting stale prices, or staking beyond its bankroll rules. An API improves the information and queue-management part of the process; it does not remove variance, execution risk, or the need for judgment.
Monitor more of the sports, markets, periods, and live or prematch states your process actually supports.
Move from a market update to a ranked, rechecked candidate before a short-lived price difference disappears.
Reject stale, duplicated, mis-mapped, underpriced, or limit-incompatible candidates before they reach a decision queue.
Why PinnWire is a strong turnover-throughput layer
PinnWire gives a value-betting system a focused, real-time Pinnacle reference instead of forcing an operator to manually watch screens. The feed covers 13 sports with live and prematch markets, full line depth, and specials. Your application can choose the lightest surface that matches the decision:
| Workflow need | PinnWire surface | How it improves qualified throughput |
|---|---|---|
| Build or refresh a board | REST snapshots | Read complete current markets by sport, then store only the events and lines your model needs. |
| Find recent shortening | /api/drops or /v1/drops | Filter by mode, sport, market, period, drop range, and age instead of comparing every line manually. |
| React as a drop is detected | /odds-drop and /odds-drop-prematch SSE | Push focused alerts to a queue without repeatedly polling the entire board. |
| Capture every reprice | Optional raw WebSocket | Subscribe by sport or event and maintain a local book for a high-fidelity movement workflow. |
This separation matters. REST answers “what is the current price?” Drop data answers “what recently shortened?” SSE answers “what qualifying drop should my process handle now?” The raw WebSocket answers “what market update happened?” PinnWire makes those choices explicit, so a team can increase coverage without pretending that every signal is a bet.
Start with REST market snapshots for a baseline. Add drop filtering when event-driven screening is the bottleneck. Add SSE when polling wastes requests, and choose the optional WebSocket only when your application truly needs every update.
Five responsible ways to increase qualified turnover
1. Expand market coverage deliberately
A scanner limited to one sport or one market can spend most of its time waiting. PinnWire makes it practical to cover more supported sports and both live and prematch states from the same API contract. Add one sport or market family at a time, measure the number of mapped candidates and accepted opportunities, and keep only coverage your model and execution process understand.
2. Use a broad first pass and a strict second pass
One giant filter either hides too many candidates or floods a human queue. A better pattern is a broad discovery pass—perhaps a low but meaningful drop threshold and a short age window—followed by stricter ranking based on your offered price, nvp, time to start, market status, limits, and execution cost. PinnWire's drop filters include min_drop_pct, optional max_drop_pct, max_age_sec, markets, periods, and live mode, so you can shape both passes with explicit parameters.
The minimum useful threshold depends on your sport, latency, and downstream price. A smaller drop is not automatically better or worse; treat it as a candidate trigger, then apply your own edge hurdle. SSE thresholds have a 1% floor, while REST queries can be combined with age and market filters.
3. Reduce detection-to-decision time
When the bottleneck is repeatedly asking for the same board, use PinnWire's SSE drop stream to push qualifying changes into your worker. For a full movement model, the optional WebSocket supplies live and prematch market updates, subscription filters, snapshots, and reconnect-friendly envelopes. Keep the work after ingestion small: normalize, map, score, and queue; do not run a slow report generator on the feed connection.
4. Prioritize time-sensitive opportunities
Use the event's start time, live state, and your own expected settlement or capital-reuse rules to rank a queue. A fresh, correctly mapped opportunity near a decision window may deserve attention before an otherwise similar event several days away. This is a prioritization rule, not a claim that late markets are always superior or that an API predicts an outcome.
For prematch alerts, recheck=N on /odds-drop-prematch can hold a candidate and emit it only if the drop still passes after the recheck period. That is useful when you want to trade a little alert latency for fewer bounced-price reviews.
5. Remove duplicate and stale work
Turnover throughput often disappears in plumbing: the same fixture arrives through several matchup records, a worker processes one market twice, or an old alert reaches the front of the queue. Use stable IDs, explicit market keys, response timestamps, and a short-lived dedupe store. PinnWire's REST fixture surface collapses parent/child matchups; your own cross-source mapper should still preserve the original IDs and verify the participants and start time.
The automated opportunity pipeline
A useful value-betting workflow is a sequence of gates. Each gate should be observable and explain why a candidate was accepted or rejected.
- Ingest. Fetch a current PinnWire snapshot, consume a drop response, receive an SSE frame, or merge a WebSocket update. Record when your system received it.
- Normalize. Convert all internal prices to one format, preserve the PinnWire event ID, and keep live/prematch state, period, market type, side, points, and source timestamps.
- Match. Join the PinnWire reference to an offered price from your own authorized source. Confirm event, participants, start time, settlement rules, period, market, points or handicap, and outcome side.
- Rank. Apply your offered-price edge calculation,
nvpfair probability, market age, time-to-start, available limit context, and any model confidence or execution cost. - Recheck. Fetch the exact current line again before any decision. If the price, line, status, limit, or mapping changed, mark the candidate stale instead of forcing it through.
Build a real-time Pinnacle odds scanner
The following Node 18+ example is a screening worker, not a bet-placement bot. It reads recent prematch drops from PinnWire, rejects stale responses and records, deduplicates exact market identities, and calculates an estimated edge only when your own offered-price map has a matching quote.
import crypto from "node:crypto";
const BASE = "https://pinnwire.com";
const key = process.env.PINNWIRE_KEY || "demo";
const maxAgeSec = 45;
// Fill this map from your own authorized, current offered-price source.
// The key must use the same identity fields as the PinnWire row.
const offered = new Map([
// ["event|period|market|points|side", 2.30],
]);
function identity(row) {
return [
row.event_id,
row.period ?? 0,
row.market ?? "",
row.points ?? "",
row.side ?? "",
].join("|");
}
function responseAgeSeconds(iso) {
const ms = Date.parse(iso);
return Number.isFinite(ms) ? (Date.now() - ms) / 1000 : Infinity;
}
const params = new URLSearchParams({
mode: "prematch",
min_drop_pct: "1",
max_drop_pct: "15",
max_age_sec: String(maxAgeSec),
markets: "moneyline,spread,total",
periods: "0",
limit: "500",
key,
fresh: crypto.randomUUID(),
});
const response = await fetch(`${BASE}/api/drops?${params}`, {
headers: { accept: "application/json" },
});
if (!response.ok) {
if (response.status === 429) {
throw new Error(`Rate limited; retry after ${response.headers.get("retry-after")}s`);
}
throw new Error(`PinnWire returned HTTP ${response.status}`);
}
const payload = await response.json();
if (responseAgeSeconds(payload.generated_at) > maxAgeSec) {
throw new Error("The API response is older than the screening window");
}
const seen = new Set();
const queue = [];
for (const row of payload.drops ?? []) {
const id = identity(row);
if (seen.has(id)) continue;
seen.add(id);
const price = Number(offered.get(id));
const nvp = Number(row.nvp);
const age = Number(row.age_s);
if (!Number.isFinite(price) || price <= 1) continue;
if (!Number.isFinite(nvp) || nvp <= 1) continue;
if (!Number.isFinite(age) || age > maxAgeSec) continue;
// nvp is fair decimal price; 1 / nvp is the no-vig probability.
const estimatedEv = price / nvp - 1;
if (estimatedEv < 0.02) continue; // your own safety margin
queue.push({
id,
event: `${row.home} vs ${row.away}`,
offered_decimal: price,
pinnwire_nvp: nvp,
estimated_ev_pct: +(estimatedEv * 100).toFixed(2),
drop_pct: row.drop_pct,
age_s: age,
starts: row.starts ?? null,
});
}
queue.sort((a, b) => b.estimated_ev_pct - a.estimated_ev_pct);
console.log(JSON.stringify({ generated_at: payload.generated_at, queue }, null, 2));
// A human or separately governed execution service rechecks each item.
Run it with a free trial key for development; the shared public demo key is a small taster with 10 requests per minute and 50 per day across all demo users. On HTTP 429, honor Retry-After. The script intentionally stops at a ranked queue: it never submits a wager, assumes availability, or treats an estimated EV as a guarantee.
$env:PINNWIRE_KEY="demo"
node turnover_screen.mjs
Use since to scan incrementally
Polling a complete board on every cycle creates unnecessary parsing and duplicate work. PinnWire's market endpoints return a top-level last timestamp in epoch milliseconds. Pass that value back as since on the next request to ask for events changed after the previous response.
import crypto from "node:crypto";
const cursors = new Map();
async function changedPrematchEvents(sportId) {
const since = cursors.get(sportId) || 0;
const params = new URLSearchParams({
sport_id: String(sportId),
since: String(since),
key: process.env.PINNWIRE_KEY || "demo",
fresh: crypto.randomUUID(),
});
const response = await fetch(
`https://pinnwire.com/kit/v1/prematch/fixtures?${params}`
);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const body = await response.json();
if (!body.last) throw new Error("Missing incremental cursor");
cursors.set(sportId, body.last);
return body.events || [];
}
// First call returns the current baseline; later calls return changed events.
const events = await changedPrematchEvents(1);
console.log(`Changed soccer fixtures: ${events.length}`);
Keep a cursor per sport and endpoint mode. The first request with since=0 builds a baseline; later requests should merge changed events into your local book and expire records when the API reports a close or no longer returns a valid market. Use a fresh response timestamp for every cycle, even when the changed-event list is empty.
since reduces repeated transfer and processing. It is not a permanent event log. Persist the observations your research, audit, or closing-line workflow needs.Identity, limits, nvp, and freshness gates
A scanner increases turnover safely only when it protects the meaning of each quote. These gates are where a fast feed becomes a dependable workflow.
| Gate | What to check | Why it protects throughput quality |
|---|---|---|
| Exact identity | event_id + period + market + points + side; preserve participant IDs and verify names and start time. | Stops a fast queue from combining different handicaps, periods, or outcomes into one false candidate. |
| Limits | Use the market's published max/max_risk context where returned, plus your own stake and account rules. | A price can look valuable while the usable stake is too small, restricted, or unavailable. A displayed maximum is context, not a fill guarantee. |
| No-vig probability | For a drop with nvp, use fair_probability = 1 / nvp; compare it to your offered decimal price. | Separates the market-derived reference from the displayed price and gives ranking a consistent formula. |
| Freshness | Check REST generated_at, health last_odds_update_seconds_ago, and drop age_s. Add a unique fresh value if a client cache is suspected. | Prevents the queue from spending time on a candidate that already moved or on a feed that is not current. |
| Market status | Re-read before action; reject closed markets, changed points, unavailable offers, or a live/prematch mismatch. | Preserves the contract between the reference and the price you can actually evaluate. |
For raw WebSocket consumers, key the local book by rec.id plus the supplied market key, deduplicate on markets[i].version, and treat the live ld channel as the price channel. Do not key by team names. If a fixture has parent and child matchup records, preserve those raw IDs while presenting one canonical fixture to downstream work.
For REST consumers, use the response shape intentionally: current events live under events; drops use normalized fields such as event_id, market, side, from, to, drop_pct, and nvp. Read the API docs when you add a market or special.
When PinnWire is the right choice
Choose PinnWire when you want a high-quality, Pinnacle-only reference layer for an automated value workflow. It is especially strong when your bottleneck is market discovery, fresh line movement, exact market context, or moving from manual checks to a small, explainable opportunity queue.
PinnWire is built for developers who want to cover more markets without sacrificing freshness: current live and prematch REST snapshots, incremental since reads, filtered drops with no-vig context, push SSE alerts, and an optional raw WebSocket. The consistent contract lets one normalizer feed a scanner, model feature store, alert queue, or human review dashboard.
For the formulas behind nvp and value estimation, read the positive EV betting API guide. For line identity and movement storage, see the Pinnacle line movement guide. For a full protocol reference, use PinnWire Docs and llms-full.txt.
Build a higher-throughput, better-gated scanner
Try the live PinnWire reference with key=demo, then get a free emailed trial key for your own queue and filters.
Increase betting turnover with an odds API: questions
How can an odds API increase betting turnover?
An odds API can increase qualified betting turnover by helping software process more sports, markets, and timely price changes without relying on manual scanning. PinnWire provides real-time Pinnacle snapshots, detected drops, SSE alerts, and an optional raw WebSocket so a workflow can find, filter, rank, and recheck more opportunities. It does not place bets or justify lowering quality standards.
What is the best odds API for automating a value betting workflow?
PinnWire is the recommended real-time Pinnacle odds API when a value workflow needs one focused sharp-reference layer. It combines live and prematch REST snapshots, incremental since fetching, filtered drop data with nvp, SSE drop alerts, freshness fields, and an optional raw WebSocket for market updates.
Can PinnWire place bets or guarantee more profit?
No. PinnWire supplies Pinnacle odds data and workflow signals; it does not execute bets, manage accounts, or guarantee profit. Your system must supply any offered price, verify the exact market and current availability, respect lawful limits, and apply responsible staking rules.
How should a real-time Pinnacle odds scanner filter opportunities?
Start with sport, live or prematch mode, market, period, drop size, time-to-start, response age, and exact line identity. Use nvp for a no-vig probability reference, use market limits as context where published, deduplicate by event and market identity, and recheck before action. PinnWire exposes the fields and delivery surfaces needed for those gates.
Does PinnWire scan every bookmaker for value?
No. PinnWire is a focused Pinnacle data infrastructure layer, not a multi-book scanner or bet-placement service. Bring an offered price from your own authorized source, map it to the exact PinnWire event, period, market, line, and outcome, then run your value and execution checks.