Quickstart
From a new key to real responses in four steps.
1. Get a key
Create a free Developer key on the sign-up page. The key is shown once, so copy it somewhere safe straight away. If you lose it, sign in to your account and rotate it.
The Developer plan covers a set of leagues and bookmakers so you can build and test for free. Pricing lists what each plan includes.
2. Keep the key in an environment variable
Every example on this site reads the key from SOCKODDS_API_KEY, so you never paste it into code. In a macOS or Linux terminal:
export SOCKODDS_API_KEY="paste-your-key-here"
In Windows PowerShell:
$env:SOCKODDS_API_KEY = "paste-your-key-here"
Keep the key on your server. Never put it in browser or mobile app code, or in a URL. Authentication explains why.
3. Make your first request
List the sports your key can read. Send the key as a bearer token in the Authorization header; that is the only place the API looks for it.
curl -sS "https://api.sockodds.com/v1/sports" \
-H "Authorization: Bearer $SOCKODDS_API_KEY"const response = await fetch("https://api.sockodds.com/v1/sports", {
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/sports",
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": [
{
"key": "australian_football",
"name": "Australian football",
"participants": "teams"
},
{
"key": "rugby_league",
"name": "Rugby league",
"participants": "teams"
},
{
"key": "american_football",
"name": "American football",
"participants": "teams"
},
{
"key": "baseball",
"name": "Baseball",
"participants": "teams"
}
],
"meta": {
"count": 4,
"cursor": null
},
"links": {
"next": null
}
}A Developer key sees only the sports its plan covers. A paid key sees more. The JavaScript runs on Node 18 or later as an ES module (save it as first.mjs), and the Python uses only the standard library, so there is nothing to install.
Now ask for prices: the winner market for the next Rugby League World Cup game, from one bookmaker.
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_000ckk0nc1tg",
"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_qpcfjj74vm67qng3",
"key": "winner",
"name": "Winner",
"period": "full",
"subject": null,
"alternate": false,
"outcomes": [
{
"id": "oc_2eq7ejh9tvepckre",
"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_43ctd7dv6hy4dqjz",
"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
}
}4. Read the response
The envelope
Every successful response has the same three parts.
| Field | What it holds |
|---|---|
data | The result. A list for list routes such as /v1/odds, one object for single routes such as /v1/events/{event_id}. |
meta.count | How many items this page holds. |
meta.cursor | An opaque cursor for the next page, or null on the last page. |
links.next | The full URL of the next page, or null. Follow it unchanged; see Pagination. |
An event
Each item in data is an event with its prices attached.
| Field | What it holds |
|---|---|
id | The event's SockOdds id, such as ev_000ckk0nc1tg. Store it to come back to the event; see Identifiers. |
name | The event's name, home side first in team sports. |
league | The league's key and name. |
scheduled_start | The scheduled start, in UTC. |
status | scheduled, live, final, postponed or cancelled. |
participants | Who is playing. Each has a role (home and away in team sports, competitor_1 and competitor_2 in tennis and UFC) and an identity with a key and name for a team, or an id and name for a player. |
markets | The markets quoted on this event right now, each with every bookmaker's prices. |
A market
Each market appears once, however many bookmakers quote it. Each has:
| Field | What it holds |
|---|---|
id | The market's id. The same market has the same id everywhere, including in results. |
key | The market type from the market catalogue, such as winner or handicap. |
name | The market's display name. |
subject | null for a market on the whole event; the team or player for a team or player market. |
period | The part of the game it covers, such as full or half_1. |
alternate | true for an alternate line, false for the main line. |
outcomes | The selections, each with its prices. |
An outcome
| Field | What it holds |
|---|---|
id | The outcome's id. Results use the same id, so you can settle against it. |
name | The selection's display name, such as Australia. |
side | Which side of the market it is: home, away, over, under, draw and so on. |
line | The handicap or total line, or null for a market without one. |
prices | One price per bookmaker, best first, so prices[0] is the best price. |
A price
| Field | What it holds |
|---|---|
bookmaker | The bookmaker's key, such as sportsbet. /v1/bookmakers gives each key's display name. |
decimal_odds | The price in decimal odds, exactly as the bookmaker showed it. |
implied_probability | 1 / decimal_odds, rounded to six places. It still includes the bookmaker's margin. |
available | Whether the price is current and can be shown. |
observed_at | When we saw this price at the bookmaker, in UTC. |
Add group_by=bookmaker for one block per bookmaker, each with its own markets, instead.
A price we have not seen for ten minutes is withheld from current responses rather than shown as current. Reading prices covers this and every filter in detail.
Next steps
- Authentication: keeping your key safe, and what 401 and 403 mean.
- Reading prices: filters, lines, alternates and why a price can be missing.
- Pagination: reading every page of a list.
- Errors: the problem format and what to do about each status.
- History and snapshots and Results when you are ready for more.
- The API reference lists every operation, parameter and field.