# SDK Guide - TypeScript, Python, Ruby, Go, Java
URL: https://sockodds.com/docs/sdk/

# SDK Guide - TypeScript, Python, Ruby, Go, Java [#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](https://github.com/SportsGameOdds) 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 [#installation]

**TypeScript** · **Python** · **Ruby** · **Go** · **Java**

```bash
# npm
npm install sports-odds-api
# yarn
yarn add sports-odds-api
# pnpm
pnpm add sports-odds-api
```

```bash
pip install sports-odds-api
# poetry
poetry add sports-odds-api
```

```bash
bundle add sports-odds-api
# or in the Gemfile
gem "sports-odds-api", "~> 1.0"
```

```bash
go get github.com/SportsGameOdds/sports-odds-api-go
```

```groovy
// 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 [#quick-start]

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

**TypeScript** · **Python** · **Ruby** · **Go** · **Java**

```typescript
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}`);
```

```python
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}")
```

```ruby
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}"
```

```go
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))
}
```

```java
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 [#pagination]

### Auto-pagination [#auto-pagination]

The clients iterate `nextCursor` for you:

**TypeScript** · **Python** · **Ruby** · **Go** · **Java**

```typescript
for await (const event of client.events.get({ leagueID: ["NRL"], finalized: false, limit: 100 })) console.log(event.eventID);
```

```python
for event in client.events.get(league_id=["NRL"], finalized=False, limit=100):
    print(event.event_id)
```

```ruby
client.events.get(league_id: ["NRL"], finalized: false, limit: 100).auto_paging_each { |e| puts e.event_id }
```

```go
iter := client.Events.GetAutoPaging(ctx, params)
for iter.Next() { fmt.Println(iter.Current().EventID) }
```

```java
client.events().get(params).autoPager().forEach(e -> System.out.println(e.eventID()));
```

### Manual pagination [#manual-pagination]

**TypeScript** · **Python**

```typescript
let page = await client.events.get({ leagueID: ["NRL"], limit: 100 });
while (page) { handle(page.data); page = page.hasNextPage() ? await page.getNextPage() : null; }
```

```python
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 [#filtering-and-query-parameters]

**TypeScript** · **Python** · **Ruby** · **Go** · **Java**

```typescript
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);
```

```python
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)
```

```ruby
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
```

```go
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)
```

```java
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](https://sockodds.com/docs/endpoints/getEvents/): `leagueID`, `sportID`, `eventID(s)`, `oddID`, `bookmakerID`, `teamID`, `playerID`, `oddsAvailable`, `live`, `started`, `ended`, `finalized`, `startsAfter`, `startsBefore`, `includeAltLines`, `includeOpposingOdds`, `limit`, `cursor`.

## Error handling [#error-handling]

**TypeScript** · **Python**

```typescript
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;
}
```

```python
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 types`AuthenticationError` (401 missing/unknown key, 403 deactivated), `RateLimitError` (429), `NotImplemented` (501 on `/stream/events`), `InternalServerError` (5xx).

## Timeout and retry configuration [#timeout-and-retry-configuration]

**TypeScript** · **Python** · **Go** · **Java**

```typescript
const client = new SportsGameOdds({ apiKeyHeader: KEY, baseURL: "https://api.sockodds.com/v2", timeout: 30_000, maxRetries: 2 });
```

```python
client = SportsGameOdds(api_key_header=KEY, base_url="https://api.sockodds.com/v2", timeout=30.0, max_retries=2)
```

```go
client := sportsoddsapi.NewClient(option.WithAPIKeyHeader(KEY), option.WithBaseURL("https://api.sockodds.com/v2"), option.WithMaxRetries(2), option.WithRequestTimeout(30*time.Second))
```

```java
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 [#working-with-odds-data]

**TypeScript** · **Python**

```typescript
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);
    }
  }
}
```

```python
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 [#real-time-streaming]

> Not availableSockOdds does not stream. The SDKs' `stream.events` helpers will receive a 501; use the [polling pattern](https://sockodds.com/docs/guides/realtime-streaming-api/) instead.

## Type safety and IDE support [#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 [#advanced-usage]

### Accessing raw response data [#accessing-raw-response-data]

**TypeScript** · **Python**

```typescript
const { data: body, response } = await client.events.get({ leagueID: ["AFL"] }).withResponse();
console.log(response.headers.get("x-ratelimit-remaining"));
```

```python
res = client.events.with_raw_response.get(league_id=["AFL"])
print(res.headers.get("x-ratelimit-remaining"))
```

> Need help?[FAQ](https://sockodds.com/docs/faq/) · [Email](mailto:api@sockodds.com) · [Contact](https://sockodds.com/contact-us/)
