SDK Guide — TypeScript, Python, Ruby, Go, Java

While you can always make requests to the API directly, the SDKs are an easy way to get started. Because SockOdds serves the SportsGameOdds v2 schema, the official SportsGameOdds SDKs work here unchanged — the only configuration is the base URL. This page shows install, configuration and use across the five languages.

These are SportsGameOdds' generated clients, not SockOdds's. Options and method names are theirs; SockOdds-only parameters (includeFinished) can be passed through the raw-request escape hatch each client provides.

Installation

# npm
npm install sports-odds-api
# yarn
yarn add sports-odds-api
# pnpm
pnpm add sports-odds-api
pip install sports-odds-api
# poetry
poetry add sports-odds-api
bundle add sports-odds-api
# or in the Gemfile
gem "sports-odds-api", "~> 1.0"
go get github.com/SportsGameOdds/sports-odds-api-go
// Maven
<dependency>
  <groupId>com.sportsgameodds.api</groupId>
  <artifactId>sports-odds-api</artifactId>
  <version>1.0.0</version>
</dependency>
// Gradle
implementation 'com.sportsgameodds.api:sports-odds-api:1.0.0'

Quick start

Configure the client with your key and the SockOdds base URL, then fetch a page of events:

import SportsGameOdds from "sports-odds-api";

const client = new SportsGameOdds({ apiKeyHeader: process.env.SOCKODDS_KEY, baseURL: "https://api.sockodds.com/v2" });
const page = await client.events.get({ leagueID: ["AFL"], oddsAvailable: true, limit: 5 });
console.log(`Found ${page.data.length} events`);
const event = page.data[0];
console.log(`Event: ${event.teams.away.names.medium} @ ${event.teams.home.names.medium}`);
import os
from sports_odds_api import SportsGameOdds

client = SportsGameOdds(api_key_header=os.environ["SOCKODDS_KEY"], base_url="https://api.sockodds.com/v2")
page = client.events.get(league_id=["AFL"], odds_available=True, limit=5)
print(f"Found {len(page.data)} events")
event = page.data[0]
print(f"Event: {event.teams.away.names.medium} @ {event.teams.home.names.medium}")
require "sports_odds_api"

client = SportsOddsAPI::Client.new(api_key_header: ENV["SOCKODDS_KEY"], base_url: "https://api.sockodds.com/v2")
page = client.events.get(league_id: ["AFL"], odds_available: true, limit: 5)
puts "Found #{page.data.length} events"
event = page.data[0]
puts "Event: #{event.teams.away.names.medium} @ #{event.teams.home.names.medium}"
package main

import (
	"context"
	"fmt"
	"os"
	sportsoddsapi "github.com/SportsGameOdds/sports-odds-api-go"
	"github.com/SportsGameOdds/sports-odds-api-go/option"
)

func main() {
	client := sportsoddsapi.NewClient(option.WithAPIKeyHeader(os.Getenv("SOCKODDS_KEY")), option.WithBaseURL("https://api.sockodds.com/v2"))
	page, err := client.Events.Get(context.Background(), sportsoddsapi.EventGetParams{LeagueID: sportsoddsapi.F([]string{"AFL"}), OddsAvailable: sportsoddsapi.F(true), Limit: sportsoddsapi.F(int64(5))})
	if err != nil { panic(err) }
	fmt.Printf("Found %d events\n", len(page.Data))
}
import com.sportsgameodds.api.client.SportsGameOddsClient;
import com.sportsgameodds.api.client.okhttp.SportsGameOddsOkHttpClient;

SportsGameOddsClient client = SportsGameOddsOkHttpClient.builder()
    .apiKeyHeader(System.getenv("SOCKODDS_KEY")).baseUrl("https://api.sockodds.com/v2").build();
var page = client.events().get(EventGetParams.builder().leagueID(List.of("AFL")).oddsAvailable(true).limit(5).build());
System.out.println("Found " + page.items().size() + " events");

Pagination

Auto-pagination

The clients iterate nextCursor for you:

for await (const event of client.events.get({ leagueID: ["NRL"], finalized: false, limit: 100 })) console.log(event.eventID);
for event in client.events.get(league_id=["NRL"], finalized=False, limit=100):
    print(event.event_id)
client.events.get(league_id: ["NRL"], finalized: false, limit: 100).auto_paging_each { |e| puts e.event_id }
iter := client.Events.GetAutoPaging(ctx, params)
for iter.Next() { fmt.Println(iter.Current().EventID) }
client.events().get(params).autoPager().forEach(e -> System.out.println(e.eventID()));

Manual pagination

let page = await client.events.get({ leagueID: ["NRL"], limit: 100 });
while (page) { handle(page.data); page = page.hasNextPage() ? await page.getNextPage() : null; }
page = client.events.get(league_id=["NRL"], limit=100)
while page:
    handle(page.data)
    page = page.get_next_page() if page.has_next_page() else None

Filtering and query parameters

import SportsGameOdds from "sports-odds-api";

const client = new SportsGameOdds({ apiKeyHeader: "YOUR_API_KEY", baseURL: "https://api.sockodds.com/v2" });
const res = await client.events.get({ leagueID: ["AFL", "NRL"], oddsAvailable: true, oddID: ["points-home-game-ml-home"], includeOpposingOdds: true, bookmakerID: ["sportsbet", "tab"] });
console.log(res.data);
from sports_odds_api import SportsGameOdds

client = SportsGameOdds(api_key_header="YOUR_API_KEY", base_url="https://api.sockodds.com/v2")
res = client.events.get({ league_id: ["afl", "nrl"], odds_available: true, odd_id: ["points-home-game-ml-home"], include_opposing_odds: true, bookmaker_id: ["sportsbet", "tab"] })
print(res.data)
require "sports_odds_api"

client = SportsOddsAPI::Client.new(api_key_header: "YOUR_API_KEY", base_url: "https://api.sockodds.com/v2")
res = client.events.get({ league_id: ["afl", "nrl"], odds_available: true, odd_id: ["points-home-game-ml-home"], include_opposing_odds: true, bookmaker_id: ["sportsbet", "tab"] })
puts res.data
client := sportsoddsapi.NewClient(option.WithAPIKeyHeader("YOUR_API_KEY"), option.WithBaseURL("https://api.sockodds.com/v2"))
res, err := client.Events.Get({ leagueID: ["AFL", "NRL"], oddsAvailable: true, oddID: ["points-home-game-ml-home"], includeOpposingOdds: true, bookmakerID: ["sportsbet", "tab"] })
if err != nil { log.Fatal(err) }
fmt.Println(res.Data)
SportsGameOddsClient client = SportsGameOddsOkHttpClient.builder()
    .apiKeyHeader("YOUR_API_KEY").baseUrl("https://api.sockodds.com/v2").build();
var res = client.events.get({ leagueID: ["AFL", "NRL"], oddsAvailable: true, oddID: ["points-home-game-ml-home"], includeOpposingOdds: true, bookmakerID: ["sportsbet", "tab"] });
System.out.println(res.items());
Available filtersAvailable filters mirror the events endpoint: leagueID, sportID, eventID(s), oddID, bookmakerID, teamID, playerID, oddsAvailable, live, started, ended, finalized, startsAfter, startsBefore, includeAltLines, includeOpposingOdds, limit, cursor.

Error handling

import SportsGameOdds, { APIError, RateLimitError, AuthenticationError } from "sports-odds-api";
try {
  await client.events.get({ leagueID: ["AFL"] });
} catch (e) {
  if (e instanceof RateLimitError) console.log("429 — wait for Retry-After");
  else if (e instanceof AuthenticationError) console.log("401/403 — check the key");
  else if (e instanceof APIError) console.log(e.status, e.message);
  else throw e;
}
from sports_odds_api import APIError, RateLimitError, AuthenticationError
try:
    client.events.get(league_id=["AFL"])
except RateLimitError:
    print("429 — wait for Retry-After")
except AuthenticationError:
    print("401/403 — check the key")
except APIError as e:
    print(e.status_code, e.message)
Common error typesAuthenticationError (401 missing/unknown key, 403 deactivated), RateLimitError (429), NotImplemented (501 on /stream/events), InternalServerError (5xx).

Timeout and retry configuration

const client = new SportsGameOdds({ apiKeyHeader: KEY, baseURL: "https://api.sockodds.com/v2", timeout: 30_000, maxRetries: 2 });
client = SportsGameOdds(api_key_header=KEY, base_url="https://api.sockodds.com/v2", timeout=30.0, max_retries=2)
client := sportsoddsapi.NewClient(option.WithAPIKeyHeader(KEY), option.WithBaseURL("https://api.sockodds.com/v2"), option.WithMaxRetries(2), option.WithRequestTimeout(30*time.Second))
SportsGameOddsOkHttpClient.builder().apiKeyHeader(KEY).baseUrl("https://api.sockodds.com/v2").maxRetries(2).timeout(Duration.ofSeconds(30)).build();
Best practicesRetries are safe on every endpoint (all GET). Keep them at 2 or fewer — a 429 retried immediately just burns quota.

Working with odds data

for (const event of page.data) {
  for (const [oddID, odd] of Object.entries(event.odds)) {
    for (const [book, q] of Object.entries(odd.byBookmaker)) {
      if (!q.available) continue;
      console.log(oddID, book, q.decimal, "fair:", odd.fairOdds);
    }
  }
}
for event in page.data:
    for odd_id, odd in event.odds.items():
        for book, q in odd.by_bookmaker.items():
            if not q.available: continue
            print(odd_id, book, q.decimal, "fair:", odd.fair_odds)

Real-time streaming

Not availableSockOdds does not stream. The SDKs' stream.events helpers will receive a 501; use the polling pattern instead.

Type safety and IDE support

The TypeScript, Python (typed), Go and Java clients carry the v2 types — Event, Odds, ByBookmakerOdds — which are the types SockOdds returns. SockOdds-only fields (decimal, info.stale, links.betslip) are present on the wire and reachable through each client's raw-response accessor.

Advanced usage

Accessing raw response data

const { data: body, response } = await client.events.get({ leagueID: ["AFL"] }).withResponse();
console.log(response.headers.get("x-ratelimit-remaining"));
res = client.events.with_raw_response.get(league_id=["AFL"])
print(res.headers.get("x-ratelimit-remaining"))
Need help?FAQ · Email · Contact