# Sports Odds API: BetRivers, Unibet, Paf, Svenska Spel, ATG (`publicrecords/sports-odds-api`) Actor

Live odds from 24 Kambi-powered sportsbooks in one call: BetRivers (12 US states + Ontario), Unibet (7 countries), Paf, Svenska Spel and ATG. One row per game with every book's price and the best price per outcome.

- **URL**: https://apify.com/publicrecords/sports-odds-api.md
- **Developed by:** [Public Records](https://apify.com/publicrecords) (community)
- **Categories:** Sports, Developer tools
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Sports Odds API: BetRivers, Unibet, Paf, Svenska Spel, ATG

Live odds from every open Kambi-powered sportsbook in one call. You get one row per game with each book's price for every outcome and the best price across the books you chose.

**Books covered (24 books, verified open on 2026-10-21):** BetRivers in 12 US states (NJ, NY, PA, IL, IN, CO, MI, AZ, LA, MD, OH, WV) and Ontario; Unibet in GB, Ontario, Sweden, Denmark, Belgium, Netherlands and Romania; Paf (Finland, Spain); Svenska Spel; ATG.

Not covered: DraftKings, FanDuel, BetMGM, Caesars and other books that do not run on Kambi. LeoVegas, Norsk Tipping, Napoleon and Bally Bet run on Kambi but refuse these requests, so they are not offered.

### What you get

| Mode | What each game row contains |
|---|---|
| `main` | The headline markets each book lists for the game (NBA: moneyline, point spread, total points) |
| `all` | The game's full board, often 500+ markets on an NBA game, including player props and alternate lines |

Each outcome carries every book's price (decimal, American, fractional, status, last change time) and `bestPrice` (highest decimal price among open prices, with every book tied at that price). American odds are the book's own published price, not a conversion.

### Input

```json
{
  "leagues": ["basketball/nba", "american_football/nfl"],
  "operators": ["rsiusnj", "rsiusny", "ubuk", "paf"],
  "markets": "main",
  "includeLive": true,
  "startsWithinHours": 24,
  "maxEvents": 50
}
```

`leagues` takes Kambi paths at league or sport level: `basketball/nba`, `american_football/nfl`, `ice_hockey/nhl`, `baseball/mlb`, `football/england/premier_league`, `basketball/ncaab`, `american_football/ncaaf`, or a whole sport such as `tennis` or `ufc_mma`. A mistyped path returns suggestions (`basketball/nbaa` → `basketball/nba`) and is not charged.

### Output (one game, trimmed)

```json
{
  "eventId": 1028754195,
  "name": "ATL Hawks @ ORL Magic",
  "start": "2026-10-21T23:00:00Z",
  "state": "NOT_STARTED",
  "league": "NBA",
  "path": "basketball/nba",
  "operators": { "requested": ["rsiusnj", "ubuk"], "served": ["rsiusnj", "ubuk"], "missing": [] },
  "markets": [{
    "market": "Point Spread - Including Overtime",
    "mainLine": true,
    "outcomes": [{
      "label": "Orlando Magic", "line": -1.5,
      "prices": [
        { "operator": "rsiusnj", "oddsDecimal": 1.85, "oddsAmerican": -118, "status": "OPEN", "changedAt": "2026-10-21T17:33:37Z" },
        { "operator": "ubuk", "oddsDecimal": 1.86, "oddsAmerican": -117, "status": "OPEN", "changedAt": "2026-10-21T17:33:37Z" }
      ],
      "bestPrice": { "oddsDecimal": 1.86, "oddsAmerican": -117, "operators": ["ubuk"], "brands": ["Unibet"] }
    }]
  }]
}
```

When a book does not price a game, `operators.missing` says why: `event_not_offered`, `denied`, `unavailable`, or `contract_drift`. A missing book is never shown as a price.

### Pricing

| Event | Price |
|---|---|
| Run started | $0.005 |
| Game with main-line odds (all selected books) | $0.01 |
| Game with every market (all selected books) | $0.03 |

You pay only for games returned with at least one priced market. Errors, unknown leagues and empty results are free.

### Speed

Requests are paced to what Kambi serves reliably (about two per second). A run of 5 leagues × 9 books in `main` mode takes about 25 seconds. In `all` mode each game costs one request per book: 50 games × 9 books ≈ 5 minutes. `all` mode allows up to 12 books per run, because a game's full board from more books exceeds Apify's row size.

### FAQ

**Are these live in-play prices?** Yes, when `includeLive` is on: games already started are returned with the prices open at the moment of the run.

**Do Kambi books really price differently?** Often by a few cents. On 2026-10-21, three books disagreed on 178 of 818 outcomes on one NBA game's full board.

**Do I need a proxy?** It is on by default. Kambi limits how often one IP may ask, so your run switches to a fresh Apify Proxy IP whenever it is slowed down. If your account has no proxy access the run continues without one.

**What if a run is slow?** The run stops fetching 45 seconds before your run timeout and returns the games it has priced, each listing any book it did not reach. You are charged only for games returned.

**Is this affiliated with Kambi or any sportsbook?** No. It reads the public odds feeds the books' own websites load. Bet responsibly and only where legal.

# Actor input Schema

## `leagues` (type: `array`):

Kambi paths, sport or league level: "basketball/nba", "american_football/nfl", "ice_hockey/nhl", "baseball/mlb", "football/england/premier_league", or a whole sport such as "tennis". Unknown paths are answered with suggestions and are never charged.

## `operators` (type: `array`):

Kambi-powered books to price. Each book is a separate brand/jurisdiction feed; prices can differ between them. The list contains only books verified open on the date in the README.

## `markets` (type: `string`):

"main" returns the headline markets per game. "all" returns each game's full board (often 300–500 markets) and is priced higher.

## `includeLive` (type: `boolean`):

Include games already started (live prices at the moment of the run).

## `startsWithinHours` (type: `integer`):

0 = no limit. Live games are kept when "Include in-play games" is on.

## `maxEvents` (type: `integer`):

Soonest games first. You pay per game returned.

## `proxyConfiguration` (type: `object`):

On by default. Kambi limits how often one IP may ask; your run moves to a fresh Apify Proxy IP whenever it is slowed down. Turn off only to test without a proxy.

## Actor input object example

```json
{
  "leagues": [
    "basketball/nba",
    "american_football/nfl",
    "ice_hockey/nhl",
    "baseball/mlb",
    "football/england/premier_league"
  ],
  "operators": [
    "rsiusnj",
    "rsiusny",
    "rsiuspa",
    "rsicaon",
    "ubuk",
    "ubca",
    "paf",
    "svenskaspel",
    "atg"
  ],
  "markets": "main",
  "includeLive": true,
  "startsWithinHours": 0,
  "maxEvents": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "leagues": [
        "basketball/nba",
        "american_football/nfl",
        "ice_hockey/nhl",
        "baseball/mlb",
        "football/england/premier_league"
    ],
    "maxEvents": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("publicrecords/sports-odds-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "leagues": [
        "basketball/nba",
        "american_football/nfl",
        "ice_hockey/nhl",
        "baseball/mlb",
        "football/england/premier_league",
    ],
    "maxEvents": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("publicrecords/sports-odds-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "leagues": [
    "basketball/nba",
    "american_football/nfl",
    "ice_hockey/nhl",
    "baseball/mlb",
    "football/england/premier_league"
  ],
  "maxEvents": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call publicrecords/sports-odds-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,publicrecords/sports-odds-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/aeNdZpKsIz0M7IQfb/builds/Oc1jcLktcEl70Yw96/openapi.json
