Sportsbook Odds Feed: WebSocket-First Pricing Pipeline for Operators

Sportsbook Odds Feed - OddsPapi API Blog
How To Guides June 19, 2026

Your Odds Feed Is Your Pricing Engine

If you run a sportsbook, a trading desk, or any platform that prices markets in real time, your odds feed is not infrastructure — it is your product. A two-second delay exposes you to arbitrageurs. A stale line on a bookmaker that just moved lets sharp money in before you can close. A feed that drops and reconnects from scratch means a gap in your audit trail you cannot explain to regulators.

Most operators discover this after an incident. The generic developer APIs on the market were built for analysts polling once every five seconds — not for operators who need to act on a price change in under a second. OddsPapi’s B2B feed, documented at docs.oddspapi.io, is built for the second use case.

Why Current Solutions Break at Operator Scale

There are three ways operators typically try to source aggregated bookmaker data. All three have structural problems at production scale.

Approach Time to Production Coverage Stale Detection Failure Mode
Scraping Days (then breaks monthly) What you can parse None — you don’t know Rate limit, DOM change, legal risk
Bilateral data contract Months (NDA, integration, UAT) One bookmaker per contract Depends on partner SLA Feed drops silently, no fallback
Generic developer REST API Hours Wide but polling-only None — timestamps only Rate limit, polling gap, no stale signal
OddsPapi B2B (WebSocket) Hours 200+ bookmakers, one connection Built-in staleOdds flag Cursor resumes from last event, no gap

The gap between a REST polling architecture and a WebSocket-first architecture is not academic. At 10-second polling intervals you miss every price movement that opens and closes between polls — which, for sharp books during live in-play, can be dozens per minute. The polling vs WebSocket explainer covers the update cadence in detail.

OddsPapi B2B: WebSocket-First Architecture

The B2B feed is structured as a set of typed channels. Each channel delivers a specific data type; your systems subscribe to exactly what they need and nothing else. Authentication is a single login frame sent after connection, which returns your access tier (access.live and access.pregame) and your starting cursor position.

The Channel Set

Channel What It Delivers Typical Consumer
odds High-throughput real-time betting odds from 200+ bookmakers Pricing engine, line-monitoring, arbitrage detector
bookmakers Per-bookmaker feed status, including staleOdds flag Trading safety layer — pause automation on stale
fixtures Match metadata, status transitions, participant mapping Market lifecycle management
scores Period and final scores, scoped to fixtureId In-play risk management, live market suspension
clocks Live match clock — period, elapsed time, stopped state In-play pricing model input, suspension timing
injuries / lineups / stats Player-level supplementary data Pre-match model refresh, prop market triggers
futures / oddsFutures Season-long and outright market metadata and prices Outright book management, election/politics markets
currencies Global exchange rates including crypto Multi-currency settlement, crypto book pricing

Every odds message is keyed by {fixtureId}:{bookmaker}:{outcomeId}:{playerId}. This composite key means your downstream systems can merge updates into a local state without a join — a single dict lookup routes each message to the right market position.

The staleOdds Flag: Your Automated Trading Safety Net

The most important field in the B2B feed is not a price — it is staleOdds, a boolean delivered on the bookmakers channel.

When OddsPapi’s aggregation layer loses connectivity to a source bookmaker, it does not silently continue serving the last known price. It flips staleOdds: true for that bookmaker. Your system’s correct response is to suspend any automated strategy that references that bookmaker’s line until staleOdds returns to false.

This matters most in two scenarios:

  • Automated arbitrage: An arb scanner comparing Pinnacle to Bet365 on a live in-play market needs to know if either leg is quoting a price that is 90 seconds old. Without staleOdds, a false arb triggers a losing position.
  • Model-driven line setting: If your model uses an external sharp book as a price anchor, a stale anchor means your lines diverge from the market without a signal that anything is wrong.
import asyncio, json
import websockets

# Simplified B2B connection sketch — see docs.oddspapi.io for full spec
async def feed():
    async with websockets.connect("wss://YOUR_B2B_ENDPOINT") as ws:

        # Login frame
        await ws.send(json.dumps({
            "action": "login",
            "apiKey": "YOUR_B2B_KEY",
            "receiveType": "json"          # or "zstd" / "zstd-dict" / "binary"
        }))
        login_resp = json.loads(await ws.recv())
        # login_resp["access"]["live"] == True for live feed access

        # Subscribe to odds + bookmaker status channels
        await ws.send(json.dumps({
            "action": "subscribe",
            "channels": ["odds", "bookmakers"]
        }))

        # Maintain stale state per bookmaker slug
        stale = {}

        async for raw in ws:
            msg = json.loads(raw)
            channel = msg.get("channel")

            if channel == "bookmakers":
                slug = msg["bookmaker"]
                stale[slug] = msg.get("staleOdds", False)
                if stale[slug]:
                    print(f"ALERT: {slug} feed is stale — pausing strategies")

            elif channel == "odds":
                slug = msg["bookmaker"]
                if stale.get(slug):
                    continue   # Do not act on prices from a stale source
                process_price(msg)

asyncio.run(feed())

The staleOdds check is a one-line guard, but it is the difference between a trading system that survives bookmaker connectivity incidents and one that compounds losses on phantom prices.

The participantsRotated Flag

A second safety flag on the fixtures channel: participantsRotated. This signals that the bookmaker’s home/away assignment differs from OddsPapi’s canonical mapping for that fixture. If your moneyline parser maps outcome 1 to “home win” and the source book has the teams inverted, every position you open on that outcome is on the wrong side. Check this flag before writing any outcome to your market model.

Resume and Replay: No Data Loss on Disconnect

WebSocket connections drop. The question is what happens when they do.

The B2B feed maintains per-channel cursors via two fields: entryId and serverEpoch. Your client stores these with every message. On reconnect, you send your last known cursor and the server replays any events you missed during the gap — up to the resumeWindowMs (default 60 seconds).

The recovery pattern has two branches:

  • Short disconnect (within resume window): Send last cursor on login. Server replays missed events, then continues the live stream. No data loss, no manual reconciliation.
  • Long disconnect (outside resume window): Server responds with snapshot_required. Fetch a REST snapshot via GET /fixtures/odds to rebuild your state, then reconnect with a fresh cursor. Worst case is one REST call — not an open-ended data hole.

The design goal is explicit in the docs: “short interruptions resume with no data loss.” That guarantee is only possible because cursors are server-side state tied to the feed delivery, not client-reconstructed timestamps. This is a different architecture from “reconnect and re-subscribe” approaches where the gap is whatever you missed during downtime.

Compression Options for High-Throughput Environments

Raw JSON odds messages are verbose. At scale — hundreds of bookmakers, dozens of live in-play fixtures, high-cadence markets — the wire cost of uncompressed JSON becomes the constraint.

Mode Compression Ratio vs JSON Use Case
json 1x (baseline) Development, debugging, low-volume monitoring
binary (MessagePack) ~2-3x Latency-sensitive, low overhead deserialization
zstd ~5-6x High-throughput pipelines where bandwidth is the cost
zstd-dict ~7-9x Maximum compression; server re-sends dictionary on reconnect

For a trading desk processing 100+ live fixtures simultaneously across 200 bookmakers, the difference between json and zstd-dict is roughly an 8x reduction in ingress bandwidth and a corresponding reduction in the time your parse pipeline is blocked on I/O. The receiveType is set in the login frame — no separate negotiation required.

Settlement: Closing the Pricing Loop

A pricing feed that does not connect to settlement is half a pipeline. When a market closes, you need per-outcome results for bet grading and a final score for reconciliation.

The settlement endpoint delivers both:

import requests

# Settlement for a closed fixture
r = requests.get(
    "https://api.oddspapi.io/v4/fixtures/settlement",
    params={
        "apiKey": "YOUR_KEY",
        "fixtureId": "id1000001234567890"
    }
)
settlement = r.json()

# settlement["outcomes"] — dict of outcomeId -> {result: "won"|"lost"|"void", score, margin}
# settlement["scores"]   — final score per period
# settlement["status"]   — "Finished" when grading is final

for outcome_id, result in settlement["outcomes"].items():
    grade_bet(outcome_id, result["result"])

This covers fixture markets. Futures settlement is listed as in development in the current documentation — outright markets are priced live but require a separate grading flow for now.

CLV Analytics: Measuring Your Execution Quality

Closing Line Value (CLV) is the benchmark that separates informed line movement from noise. For trading desks and market makers, CLV tells you whether your lines were tighter or looser than the market consensus at close — which is the most accurate forward-looking signal of whether your pricing model is capturing value.

The CLV endpoint returns opening line value (OLV) and closing line value (CLV) for any completed fixture:

r = requests.get(
    "https://api.oddspapi.io/v4/fixtures/odds/clv",
    params={
        "apiKey": "YOUR_KEY",
        "fixtureId": "id1000001234567890",
        "bookmakers": "pinnacle"
    }
)
clv_data = r.json()

# Per outcome: opening price, closing price, implied probability shift
# Use Pinnacle as the sharp benchmark for no-vig CLV calculation

Pair this with your historical trade log and you can measure, by market and sport, whether your book was consistently ahead of or behind the closing line. For more on building this kind of analytical layer, see the CLV and EV benchmarking guide and the historical odds export tutorial.

The Full Operator Pipeline

The B2B feed is designed to carry data from price discovery through to market settlement without requiring you to stitch together separate services:

  1. Pre-match: Subscribe to fixtures and odds channels. Receive opening lines from 200+ bookmakers. Use the Pinnacle or sharp-book anchor for no-vig pricing. Set your opening line.
  2. In-play: Add clocks and scores channels. React to match-state changes. Monitor bookmakers channel for staleOdds — suspend automated strategies on any stale source. Check participantsRotated before updating any outcome mapping.
  3. Post-match: Call /fixtures/settlement for per-outcome results and final scores. Grade bets. Run CLV audit against /fixtures/odds/clv to benchmark your line’s execution quality.

The WebSocket overview for developers covers the real-time delivery concepts in detail. The white-label vs API vs turnkey decision guide is worth reading if you are still evaluating whether a full B2B data integration is the right architecture for your stage. For a broader comparison of data providers, see the 2026 odds API buyer’s guide.

Bookmaker Coverage and Futures

The B2B feed covers the same bookmaker catalog as the rest of the OddsPapi network — Sharps (Pinnacle, SBOBet, Singbet), US operators (DraftKings, FanDuel, BetMGM), global softs, crypto books (1xBet, Stake, BC.Game), and exchanges (Betfair, Polymarket, Kalshi). For exchanges, the odds channel delivers depth-of-book ladder data — back and lay as ordered lists of price levels — not a single scalar price.

Futures markets (outrights, season winners, elections, prediction-market topics) are delivered on separate futures and oddsFutures channels, with CLV available via /futures/odds/clv.

Access and Status

The B2B feed is available to licensed operators, trading firms, and enterprise platforms. Access is tiered by API key — access.live for in-play data, access.pregame for pre-match. Full documentation and connection specs are at docs.oddspapi.io. Feed status and uptime history are tracked at the OddsPapi status page.

For technical integration questions: [email protected]. For access and commercial terms: [email protected].

Frequently Asked Questions

What is the difference between the OddsPapi B2B feed and the v4 developer API?

The v4 API (api.oddspapi.io/v4) is a REST API designed for individual developers and analysts — hobbyist scripts, data exploration, smaller-scale applications. The B2B feed (docs.oddspapi.io) is a WebSocket-first architecture built for operators who need real-time delivery, stale detection, resume/replay cursors, compression, and settlement integration. Different product, different access tier, different SLA.

How does staleOdds work in practice?

The staleOdds flag is delivered on the bookmakers WebSocket channel. When OddsPapi detects that a bookmaker’s feed has gone silent, it sets staleOdds: true. Your client should suppress prices from that bookmaker in automated strategies until the flag clears to false.

What happens if my WebSocket connection drops?

Send your last entryId and serverEpoch cursor on reconnect. If within the resume window (default 60 seconds), the server replays missed events with no data loss. Beyond the window, fetch one REST snapshot to rebuild state before resuming.

Is compression mandatory?

No. The default is json. Switch to zstd-dict (7-9x size reduction vs JSON) when throughput or bandwidth becomes a constraint. The receive type is set in the login frame per connection.

Does the feed cover futures and outright markets?

Yes. Season-long outrights and prediction market topics (elections, economics, crypto) are delivered on futures and oddsFutures channels. CLV for futures is available via /futures/odds/clv.