Odds API for Bet Tracking and Settlement

The price at bet time and the graded outcome afterwards, joined by one outcome id.

A bet tracker needs the price when the bet went on and the outcome afterwards, joined without guesswork. In SockOdds v1 both carry the same outcome id: the oc_ id on a quote is the id on the graded result. Store it when the bet is placed, read /results once the game is over, and settle.

Why SockOdds

  • One id joins price and result. An outcome has the same id at every bookmaker and in the results, so a ticket from any bookmaker settles the same way. See identifiers.
  • Clear verdicts. Each outcome is won, lost, void (stake returned) or dead_heat, and a dead heat carries dead_heat_factor: the share of the stake paid at the quoted price. A split Asian quarter line is half_won or half_lost.
  • Graded from official sources. Results come from official result sources. Outcomes the evidence cannot settle are left out, never guessed.
  • Results as markets settle. Each market settles on its own. While any market is open, settlement is partial and pending_markets counts them; later results add outcomes without changing a verdict already published.
  • Find games by official id. GET /events/lookup turns an official event id into our event, which helps when you import tickets from somewhere else.

What you can build

A bet tracker

At bet time, save the event id, the outcome id, the bookmaker, decimal_odds and line. After the game, read /results?event_id= and match on outcome id.

Auto-settlement

A win returns stake × price, a void returns the stake, a loss returns nothing, and a dead heat returns dead_heat_factor × stake × price. A half_won returns half the stake × price plus half the stake, and a half_lost returns half the stake. Leave a bet open while its outcome is missing from the results: a missing outcome is still pending, not lost.

A closing line value report

On Pro, request the game's odds with snapshots=closing and compare each ticket's price with the last price recorded before the start. Over many bets, beating the closing price is a useful sign of good timing.

Try it

This request asks for the graded results of a finished NFL game.

curl -sS "https://api.sockodds.com/v1/results?event_id=ev_000ckk0h3n6r" \
  -H "Authorization: Bearer $SOCKODDS_API_KEY"
const response = await fetch("https://api.sockodds.com/v1/results?event_id=ev_000ckk0h3n6r", {
  headers: { Authorization: `Bearer ${process.env.SOCKODDS_API_KEY}` },
});
console.log(JSON.stringify(await response.json(), null, 2));
import json, os, urllib.request

request = urllib.request.Request(
    "https://api.sockodds.com/v1/results?event_id=ev_000ckk0h3n6r",
    headers={"Authorization": "Bearer " + os.environ["SOCKODDS_API_KEY"]},
)
with urllib.request.urlopen(request) as response:
    print(json.dumps(json.load(response), indent=2))

Response from a local copy of the API with invented test prices

{
  "data": [
    {
      "event": {
        "id": "ev_000ckk0h3n6r",
        "name": "Arizona Cardinals v Atlanta Falcons",
        "league": {
          "key": "nfl",
          "name": "NFL"
        },
        "scheduled_start": "2026-10-12T08:00:00.000Z",
        "status": "final",
        "participants": [
          {
            "role": "away",
            "identity": {
              "key": "atlanta_falcons",
              "name": "Atlanta Falcons"
            }
          },
          {
            "role": "home",
            "identity": {
              "key": "arizona_cardinals",
              "name": "Arizona Cardinals"
            }
          }
        ]
      },
      "status": "final",
      "settlement": "partial",
      "pending_markets": 1,
      "settled_at": "2026-10-12T12:00:00.000Z",
      "outcomes": [
        {
          "id": "oc_1xh21t2rzp7ss665",
          "name": "Atlanta Falcons",
          "verdict": "lost",
          "market": {
            "id": "mk_s4fv79z47rbkwev7",
            "key": "winner",
            "name": "Winner",
            "period": "full",
            "subject": null
          },
          "side": "away",
          "line": null
        },
        {
          "id": "oc_53f4yzaqeyex1xhg",
          "name": "Arizona Cardinals",
          "verdict": "won",
          "market": {
            "id": "mk_s4fv79z47rbkwev7",
            "key": "winner",
            "name": "Winner",
            "period": "full",
            "subject": null
          },
          "side": "home",
          "line": null
        },
        {
          "id": "oc_7txwsxyatthp1bqb",
          "name": "Arizona Cardinals",
          "verdict": "won",
          "market": {
            "id": "mk_5tz5q3wkht6h0pme",
            "key": "handicap",
            "name": "Handicap",
            "period": "full",
            "subject": null
          },
          "side": "home",
          "line": -3.5
        },
        {
          "id": "oc_yxchy92ev1h1abxs",
          "name": "Atlanta Falcons",
          "verdict": "lost",
          "market": {
            "id": "mk_5tz5q3wkht6h0pme",
            "key": "handicap",
            "name": "Handicap",
            "period": "full",
            "subject": null
          },
          "side": "away",
          "line": 3.5
        }
      ]
    }
  ],
  "meta": {
    "count": 1,
    "cursor": null
  },
  "links": {
    "next": null
  }
}

Start with settlement and pending_markets: this game is partial, with one market still waiting on official evidence. Each outcome has its verdict, market and line, and its id is the outcome id the odds routes returned before the game. The settle bets example turns this into a settlement loop.

Search across the SockOdds documentation and catalogue.