Odds Comparison and Line Shopping API

Every bookmaker's price for the same market, side by side, from one request.

An odds comparison API returns the same market priced by many bookmakers at once, so your tool can show every number side by side and point to the best one. Line shopping is the habit behind it: checking several bookmakers for the same bet before you place it. SockOdds v1 is built around that comparison. One request for a game returns each bookmaker's markets in one shape, and an outcome carries the same id at every bookmaker, so lining prices up is a lookup, not a matching job.

Why SockOdds

  • One request, every bookmaker. GET /events/{event_id}/odds returns every bookmaker your plan includes for one game, and GET /odds?league= does the same for a league's games. Narrow either with bookmakers=, regions= and markets=.
  • Shared ids line prices up. Market and outcome ids are the same at every bookmaker, so Australia to win at Sportsbet and at TAB is one oc_ id. See identifiers.
  • Prices as the bookmaker showed them. decimal_odds is the decimal price exactly as published, with implied_probability beside it and an observed_at time on every quote.
  • Stale quotes stay out. Quotes older than 10 minutes are withheld from current responses, so a comparison grid never shows a price that has gone quiet. A missing price means no fresh quote, never a price of zero.
  • Readable keys. Bookmakers, leagues and markets have plain keys such as sportsbet, rlwc and handicap. The markets catalogue lists them all.

What you can build

A comparison grid

Rows are outcomes and columns are bookmakers. Each outcome already lists every bookmaker's price in prices: place each decimal_odds in its bookmaker's column, and highlight the highest in each row.

A best-price finder

For each outcome, the first entry in prices is the highest decimal_odds and the bookmaker offering it. Show observed_at next to it so users can see how recent the number is.

A margin table

Add up implied_probability across one bookmaker's outcomes in a market. Whatever sits above 1 is that bookmaker's margin, which shows users who prices a league most tightly.

Lines and alternates

Handicap and total outcomes carry a line. Compare prices only where the lines match, and add alternates=true to include alternate lines as well.

Try it

This request asks for the Rugby League World Cup opener's winner market from Sportsbet and TAB.

curl -sS "https://api.sockodds.com/v1/events/ev_000ckk0zrx33/odds?markets=winner&bookmakers=sportsbet,tab" \
  -H "Authorization: Bearer $SOCKODDS_API_KEY"
const response = await fetch("https://api.sockodds.com/v1/events/ev_000ckk0zrx33/odds?markets=winner&bookmakers=sportsbet,tab", {
  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/events/ev_000ckk0zrx33/odds?markets=winner&bookmakers=sportsbet,tab",
    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": {
    "id": "ev_000ckk0zrx33",
    "name": "Australia v New Zealand",
    "league": {
      "key": "rlwc",
      "name": "Rugby League World Cup"
    },
    "scheduled_start": "2026-10-15T09:05:00.000Z",
    "status": "scheduled",
    "participants": [
      {
        "role": "away",
        "identity": {
          "key": "new_zealand_rugby_league",
          "name": "New Zealand"
        }
      },
      {
        "role": "home",
        "identity": {
          "key": "australia_rugby_league",
          "name": "Australia"
        }
      }
    ],
    "markets": [
      {
        "id": "mk_pz0msgze2rqwwktb",
        "key": "winner",
        "name": "Winner",
        "period": "full",
        "subject": null,
        "alternate": false,
        "outcomes": [
          {
            "id": "oc_nncgcssmzjhyt5pe",
            "name": "Australia",
            "side": "home",
            "line": null,
            "prices": [
              {
                "bookmaker": "tab",
                "decimal_odds": 1.77,
                "implied_probability": 0.564972,
                "available": true,
                "observed_at": "2026-10-15T07:58:00.000Z"
              },
              {
                "bookmaker": "sportsbet",
                "decimal_odds": 1.72,
                "implied_probability": 0.581395,
                "available": true,
                "observed_at": "2026-10-15T07:58:00.000Z"
              }
            ]
          },
          {
            "id": "oc_cwsr1gda0qcgf03j",
            "name": "New Zealand",
            "side": "away",
            "line": null,
            "prices": [
              {
                "bookmaker": "tab",
                "decimal_odds": 2.18,
                "implied_probability": 0.458716,
                "available": true,
                "observed_at": "2026-10-15T07:58:00.000Z"
              },
              {
                "bookmaker": "sportsbet",
                "decimal_odds": 2.12,
                "implied_probability": 0.471698,
                "available": true,
                "observed_at": "2026-10-15T07:58:00.000Z"
              }
            ]
          }
        ]
      }
    ]
  },
  "meta": {
    "count": 1,
    "cursor": null
  },
  "links": {
    "next": null
  }
}

Each outcome appears once, with both bookmakers' prices under it in prices, best first, so the comparison needs no join: prices[0] is the best price for that outcome. In this response TAB has the higher price on both teams, so a best-price finder would point to TAB for either side. The odds comparison example builds the full grid.

Search across the SockOdds documentation and catalogue.