Guides · 7 September 2026 · updated 13 October 2026

Getting Started with the SockOdds API

From a free key to bookmaker prices in your code in four steps.

Whether you are building an odds comparison page, a model, a fantasy tool or an analytics dashboard, the SockOdds API gives you bookmaker prices as plain JSON. This post walks you from nothing to a price in your own code with API v1.

1. Get a key

Create a free Developer key on the sign-up page. No card is needed. The Developer plan allows 10 requests a minute and 2,500 objects a month on a small set of leagues and bookmakers; pricing lists exactly which.

Keep the key out of your code. Put it in an environment variable and read it from there:

export SOCKODDS_API_KEY="paste-your-key-here"

Every request sends it in one header, Authorization: Bearer <key>. See authentication for the details.

2. Make a request

Ask for the head-to-head (winner) prices on the next Rugby League World Cup game from one bookmaker. limit=1 keeps the response to one game.

curl -sS "https://api.sockodds.com/v1/odds?league=rlwc&markets=winner&bookmakers=sportsbet&limit=1&starts_after=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  -H "Authorization: Bearer $SOCKODDS_API_KEY"
const response = await fetch(`https://api.sockodds.com/v1/odds?league=rlwc&markets=winner&bookmakers=sportsbet&limit=1&starts_after=${new Date().toISOString().slice(0, 19)}Z`, {
  headers: { Authorization: `Bearer ${process.env.SOCKODDS_API_KEY}` },
});
console.log(JSON.stringify(await response.json(), null, 2));
import json, os, urllib.request
from datetime import datetime, timezone

request = urllib.request.Request(
    f"https://api.sockodds.com/v1/odds?league=rlwc&markets=winner&bookmakers=sportsbet&limit=1&starts_after={datetime.now(timezone.utc):%Y-%m-%dT%H:%M:%SZ}",
    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": "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": "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
  }
}

Every response has the same shape: data holds the results, meta holds the count and cursor, and links.next is the URL of the next page, or null when there is none.

3. Read one price

Inside each event, prices are grouped by market, then by outcome. Each outcome has a name and a side (home or away here; over, under, yes and the rest on other markets), and a prices list with one entry per bookmaker, best price first. Each price carries:

  • bookmaker: the bookmaker's key, such as sportsbet.
  • decimal_odds: the price exactly as the bookmaker showed it, in decimal.
  • implied_probability: one divided by that price.
  • observed_at: when SockOdds saw the price.

This short program walks that structure and prints one line per price:

const response = await fetch(`https://api.sockodds.com/v1/odds?league=rlwc&markets=winner&bookmakers=sportsbet&limit=1&starts_after=${new Date().toISOString().slice(0, 19)}Z`, {
  headers: { Authorization: `Bearer ${process.env.SOCKODDS_API_KEY}` },
});
const body = await response.json();
for (const event of body.data) {
  console.log(event.name);
  for (const market of event.markets) {
    for (const outcome of market.outcomes) {
      for (const price of outcome.prices) {
        console.log(`${price.bookmaker}: ${outcome.name} ${price.decimal_odds.toFixed(2)} (seen ${price.observed_at})`);
      }
    }
  }
}
import json, os, urllib.request
from datetime import datetime, timezone

request = urllib.request.Request(
    f"https://api.sockodds.com/v1/odds?league=rlwc&markets=winner&bookmakers=sportsbet&limit=1&starts_after={datetime.now(timezone.utc):%Y-%m-%dT%H:%M:%SZ}",
    headers={"Authorization": "Bearer " + os.environ["SOCKODDS_API_KEY"]},
)
with urllib.request.urlopen(request) as response:
    body = json.load(response)
for event in body["data"]:
    print(event["name"])
    for market in event["markets"]:
        for outcome in market["outcomes"]:
            for price in outcome["prices"]:
                print(f"{price['bookmaker']}: {outcome['name']} {price['decimal_odds']:.2f} (seen {price['observed_at']})")

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

Australia v New Zealand
sportsbet: Australia 1.72 (seen 2026-10-15T07:58:00.000Z)
sportsbet: New Zealand 2.12 (seen 2026-10-15T07:58:00.000Z)

A quote older than 10 minutes is left out of current responses, so a missing price means SockOdds has nothing fresh for it. It never means the price is zero.

4. Learn the identifiers once

Events, players, markets and outcomes each have a stable id (ev_, pl_, mk_, oc_), and leagues, bookmakers and markets have readable keys such as rlwc, sportsbet and winner. Read identifiers and markets once and you can read every sport the same way.

5. Build something

When you are ready for more leagues, bookmakers or history, compare the plans on pricing. The full list of routes is in the API reference.

Search across the SockOdds documentation and catalogue.