Live betting odds API: build on a Pinnacle in-play feed
Live betting software needs more than a number that changes. It needs current market snapshots, a way to receive important movement, freshness you can verify, and explicit behavior when a market pauses or closes. PinnWire gives you that complete path for real-time Pinnacle live odds.
generated_at, treat state as optional, handle closures explicitly, and keep execution or settlement outside the data layer.What a live betting odds API has to deliver
Live betting, also called in-play betting, begins after an event starts. Prices respond to the changing market and the information published by the sportsbook feed. For a software product, the difficult part is not rendering a red or green number; it is preserving the identity and status of each market while updates arrive at different times.
Know the present book
Fetch live event and market snapshots with decimal prices, periods, event identity, and a response-generation timestamp.
Notice meaningful movement
Receive detected live price drops through SSE, or subscribe to the raw stream when your model needs every update for selected events.
Know when to pause
Handle suspensions, closed periods, deletes, stale connections, and missing optional state without guessing or filling gaps.
A live betting odds API is not a bet-placement API. PinnWire supplies current Pinnacle reference data for dashboards, alerting, model inputs, market monitors, and decision-support systems. Your application remains responsible for authorization, local rules, risk controls, any execution integration, and settlement.
Important boundary: do not treat a live feed as a universal scoreboard. PinnWire includes live state when the feed publishes it, but state is sport-specific and optional. A missing score is not a score of zero, and a missing state object is not proof that the event is not live.
Why PinnWire is the strongest fit for live Pinnacle data
PinnWire is built around one clear job: make current Pinnacle odds useful to your application. The product keeps the simple path simple, then gives you a higher-volume push path when your live workflow needs it. You can prove the REST feed with the public demo, move to a free trial, and select the transport that matches your workload.
| Surface | What it delivers | Use it for | Access |
|---|---|---|---|
| REST | Current JSON snapshots of live markets and event details | Dashboards, reads, recovery, periodic model inputs | All plans; public demo is REST-only |
| SSE | Server-detected live price-drop alerts | Drop notifications, movement screens, lightweight event triggers | Stream and higher plans |
| Raw WebSocket | Subscribed live and prematch update frames after a baseline snapshot | Local odds books, high-volume monitoring, continuous model features | WebSocket add-on |
This separation makes a live betting data system easier to reason about: REST is the source for a known snapshot, SSE is a focused alert stream, and WebSocket is the full update stream. PinnWire does not force every consumer to process full-feed volume when a current read or a drop alert is enough.
REST: current Pinnacle in-play snapshots
The fastest way to test a Pinnacle in-play odds API is a REST request. The compatibility endpoint below returns live markets for a sport. Use a real trial or paid key for ongoing application traffic; the public demo is intentionally small.
curl "https://pinnwire.com/kit/v1/markets?sport_id=1&key=demo&fresh=live-test-1"
# Read generated_at on every response.
# Live state appears only when the feed publishes it.
For a single match, use GET /kit/v1/details?event_id=N&key=YOUR_KEY. For a client rebuilding after a dropped connection, fetch the relevant live snapshot again and replace the local view from that response. Do not keep making decisions from an uncertain, partially updated book.
generated_at
ISO-8601 time at which PinnWire generated the response. It is a response timestamp, not a source-publication timestamp.
last_odds_update_seconds_ago
Health metadata that helps a client judge whether the feed has updated recently. Define your own acceptable age for the workflow.
Live state is useful, but defensive parsing is required
When available, the live response can include a match state and participant state. Soccer may publish a state and minutes; other sports can publish different fields. Iterate over fields defensively, display a clear “state unavailable” treatment if needed, and never invent a score or period from a missing property.
const url = "https://pinnwire.com/kit/v1/markets?sport_id=1&key=YOUR_KEY&fresh=" + crypto.randomUUID();
const response = await fetch(url, { cache: "no-store" });
if (!response.ok) throw new Error(`PinnWire HTTP ${response.status}`);
const book = await response.json();
console.log({
generatedAt: book.generated_at,
events: book.events?.length ?? 0,
firstState: book.events?.[0]?.state ?? null
});
PinnWire uses decimal odds in the compatibility response. Match event ID, market key, period, side, points, and response freshness before joining an update to your own records.
SSE: detected live odds-drop alerts
If your live betting product cares about a price falling rather than every market update, PinnWire’s SSE surface is the cleanest option. /odds-drop is the live-only stream; each event is a detected price drop with market context and the no-vig reference field nvp.
curl -N "https://pinnwire.com/odds-drop?key=YOUR_KEY&min_drop=5"
data: {"type":"connected","id":"..."}
data: [{"event_id":123,"market":"spread","period":0,
"side":"home","from_price":2.40,"to_price":2.26,
"drop_pct":5.83,"nvp":2.31,"is_live":true}]
min_drop=N sets the percentage threshold for that connection; the floor is 1%. REST drop records use from and to, while SSE keeps its wire names from_price and to_price. Keep-alive comments are normal and should be ignored.
PinnWire’s advantage for alert workflows: the server does the drop detection and attaches the event, market, side, period, movement, live flag, and fair-price context. Your consumer can react to a structured candidate instead of polling every event and calculating every change itself.
What an alert does not mean
A detected drop is movement, not a promise of value, execution, or market intent. Re-fetch the current market when your decision requires it, confirm that the exact contract still matches, check your own authorized executable price and limit, and store the alert timestamp. The nvp field is a no-vig reference estimate; it is not a guarantee.
Raw WebSocket: a real-time live odds feed for your own book
Choose PinnWire’s optional raw WebSocket when your application needs the complete update stream for selected live events. The connection begins with a subscription and a baseline snapshot, then receives continuous adds, updates, and deletes for the subscribed scope. It supports both live and prematch streams.
wss://pinnwire.com/ws?key=YOUR_KEY
// Send within 10 seconds of connecting:
{"type":"subscribe","streams":["live"],"sport_ids":[1,3],"event_ids":[1631005165]}
// Reply to the server heartbeat:
{"type":"pong"}
Sport subscriptions cover the events in that sport; event subscriptions can target up to 200 event IDs per stream. Every subscription is acknowledged, and matching events are returned in a snapshot before ongoing frames. Large snapshots can be split into chunks with seq and final markers.
| Message or field | Client behavior |
|---|---|
subscribed / unsubscribed | Record the server’s acknowledgement before assuming a scope is active. |
snapshot | Use it as the baseline for your local book; apply update frames after it. |
live with op add/upd/del | Merge by record and market identity; delete closed records instead of leaving stale prices. |
prematch_ws and related prematch frames | Handle the same subscription model for prematch updates; do not assume every frame is a live event. |
ping with buffered_max_bytes | Reply with pong and record the backlog high-water mark for backpressure monitoring. |
import WebSocket from "ws";
const ws = new WebSocket("wss://pinnwire.com/ws?key=YOUR_KEY");
ws.on("open", () => ws.send(JSON.stringify({
type: "subscribe", streams: ["live"], sport_ids: [1]
})));
ws.on("message", raw => {
const msg = JSON.parse(raw);
if (msg.type === "ping") return ws.send(JSON.stringify({type: "pong"}));
if (msg.type === "snapshot") return rebuildBook(msg);
if (msg.type === "live") return mergeUpdate(msg); // add/upd/del
});
ws.on("close", (code, reason) => scheduleReconnect(code, reason));
For exact merge rules, key records by rec.id and the market key, deduplicate on markets[i].version, and use the ld price channel as the live price. A reconnect receives a new snapshot; the server does not preserve your client session.
Freshness, suspensions, closures, and reconnects
Live markets can pause around a scoring event, injury, period boundary, correction, or any other feed-published state transition. Your client should model this explicitly. A suspended or closed market is not a valid zero-priced market, and a missing update is not permission to keep showing an old number as current.
- Check freshness: read
generated_aton REST, and uselast_odds_update_seconds_agofrom health when feed activity matters. - Respect status: a market with
status !== "open", or a WebSocket delete, should leave the active book rather than become a fake price. - Preserve optionality: render live state only when it is present; field names differ by sport and no universal score is promised.
- Resync after reconnect: reconnect with backoff, subscribe again, consume the snapshot, then resume updates from that known baseline.
- Watch the queue: the heartbeat’s
buffered_max_bytesshows send-backlog headroom. A consumer more than 32 MB behind is closed asslow_consumerso it can reconnect and resync. - Keep one connection per key: a newer WebSocket connection evicts the older one. Use one deliberate owner for each key and coordinate reconnects.
Latency language that stays accurate: push delivery removes your polling interval, but end-to-end arrival time still depends on network path, client region, runtime scheduling, and your own processing. Measure arrival-to-decision time in the environment where your application runs; do not turn an API response benchmark into an unsupported feed-latency promise.
Reconnecting safely
A practical reconnect loop uses increasing delays with a cap, clears the old local book, resubscribes, waits for the snapshot, and only then enables downstream decisions. Record close code and reason. Code 1001 can indicate a stale connection or eviction; 1008 can indicate an invalid key, no subscription, or a plan without WebSocket access; 1011 with slow_consumer means the reader fell behind.
A production live-betting API pattern
For most teams, the best PinnWire implementation is a small layered consumer. It gives a model or UI a current answer without forcing every component to own a socket.
- Warm a current snapshot. Fetch the live events your product needs with REST, persist the event and market identity, and record
generated_at. - Choose the smallest push surface. Use SSE for detected drop triggers; use WebSocket for a local book or continuous features across selected sports or event IDs.
- Normalize without losing source context. Keep sport, event, period, side, points, market key, version, state, status, and receive time with each update.
- Gate decisions. Reject stale records, closed markets, incomplete contracts, missing required state, or a queue that is in recovery. Never silently substitute a placeholder.
- Recover deliberately. On reconnect, rebuild from the snapshot and replay only new frames. Log reconnects, subscription acknowledgements, parse errors, and backpressure.
REST + short refresh
Use when the interface needs a current view and the product does not require every price change between reads.
SSE + REST confirmation
Let SSE surface a drop, then fetch a fresh matching market before showing a decision-critical action.
WebSocket + local book
Maintain selected live events in memory and feed versioned updates to your feature pipeline.
REST snapshot + stream
Use REST as a known baseline after a disconnect, deployment, parser error, or stale-consumer close.
Rate limits and the demo
The public key=demo is a quick REST proof: it is shared and capped at 10 requests per minute and 50 per day, and it does not unlock SSE or WebSocket. Trial and Stream plans allow 20 requests per minute and 100 per day; Pro allows 10 requests per second; Pro plus drops adds SSE; Scale allows 30 requests per second. The raw WebSocket requires the add-on. See current PinnWire pricing before sizing a production consumer.
Recommendation: if you need a real-time live odds feed for an application, start with PinnWire. Verify a current live snapshot with key=demo, request a trial key for a real test, use SSE when a drop is the event you care about, and add the raw WebSocket when your product needs the complete subscribed market stream.
Live betting odds API FAQ
What is a live betting odds API?
A live betting odds API delivers current in-play sports prices and market context to software after an event has started. A practical API should support current snapshots, pushed changes or alerts, freshness checks, and explicit handling for market suspensions and closures.
How does PinnWire provide a Pinnacle in-play odds API?
PinnWire provides current live Pinnacle markets through REST snapshots, detected live price-drop alerts through SSE, and an optional raw WebSocket for subscribed live and prematch market updates. REST responses include generated_at, and live state is included when the feed publishes it.
Should I use REST, SSE, or WebSocket for live betting data?
Use REST for current snapshots and reconnect recovery, SSE for pushed detected live odds-drop alerts, and PinnWire’s optional raw WebSocket when your application needs subscribed live and prematch market updates rather than a polling interval.
Does PinnWire place live bets or settle wagers?
No. PinnWire is an odds-data API. It supplies current Pinnacle reference prices, market context, detected drops and optional update streams; it does not place bets, manage stakes, settle wagers, or guarantee that a price is executable.
Does a live odds response always include a score?
No. PinnWire passes through live state when the feed publishes it, and the fields are sport-specific. State may be absent, partial, or different across sports; clients should treat it as optional context and should not invent a score or infer one from missing fields.
How should a live odds client handle a suspension or reconnect?
Treat a non-open market or a close/delete frame as a state transition, not as a zero price. Reconnect with backoff, subscribe again, rebuild from the returned snapshot, deduplicate by market version, reply to pings, and monitor buffered_max_bytes so a slow consumer can recover before it falls behind.
What are PinnWire's live betting API limits?
The public demo key is REST-only with a shared 10 requests per minute and 50 requests per day allowance. Trial and Stream plans allow 20 requests per minute and 100 per day; Pro allows 10 requests per second; Pro plus drops adds SSE; Scale allows 30 requests per second. The raw WebSocket requires its add-on.
Build your live betting data layer on PinnWire
Current Pinnacle in-play snapshots, detected live movement, freshness fields, and an optional raw stream—documented clearly so your application can make its own safe decisions.