Handling Odds — Parse Results and Grade Bets

Overview

The SockOdds API carries odds and, where the source has them, results for every event. This guide shows how to fetch and parse the odds for a group of events and grade them.

The three prices

FieldMeaning
bookOddsConsensus book price as an American string ("-108", "+240"), present whenever any book prices the market
fairOddsThe de-vigged fair price from exchange/sharp consensus; null when it can't be computed and on Lite keys — fairOddsAvailable says which
byBookmaker[book]That book's own price: odds (American), decimal, available, lastUpdatedAt, and overUnder/spread where relevant

American to decimal

Every bookmaker entry already carries decimal; for the consensus fields:

def decimal(american: str) -> float:
    a = int(american)
    return 1 + (a / 100 if a > 0 else 100 / -a)

Two-sided markets

opposingOddID names the other side (…-over…-under, …-home…-away). Alt lines live under altLines keyed by line, each with its own byBookmaker, when you ask with includeAltLines=true.

Example: grading last week's NRL totals

let cursor = null, events = [];
do {
  const url = new URL("https://api.sockodds.com/v2/events");
  url.search = new URLSearchParams({ leagueID: "NRL", startsAfter: "2026-08-31", startsBefore: "2026-09-07", finalized: "true", ...(cursor ? { cursor } : {}) });
  const body = await (await fetch(url, { headers: { "x-api-key": KEY } })).json();
  events = events.concat(body.data); cursor = body.nextCursor;
} while (cursor);

for (const event of events) {
  for (const odd of Object.values(event.odds)) {
    if (odd.betTypeID !== "ou" || !odd.scoringSupported) continue;
    // the stat that settles this market lives at results.{periodID}.{statEntityID}.{statID}
    const actual = event.results?.[odd.periodID]?.[odd.statEntityID]?.[odd.statID];
    const line = parseFloat(odd.bookOverUnder);
    if (actual == null || Number.isNaN(line)) continue;
    console.log(odd.oddID, actual > line ? "Over wins" : actual === line ? "Push" : "Under wins");
  }
}
Two flags you must read. A book with available: false is listed but suspended. An event with info.stale: true has had no source write for 45 minutes — the prices are the last known, not current.
Need help?FAQ · Email · Contact