owls-insight-ts
v0.2.1
Published
Official TypeScript SDK for the Owls Insight real-time sports betting odds API
Maintainers
Readme
Owls Insight SDK
Official TypeScript/JavaScript SDK for the Owls Insight real-time sports betting odds API.
Features
- Full TypeScript types for all endpoints and events
- REST client for odds, scores, props, history, and stats
- WebSocket client for real-time streaming updates
- Works in Node.js, Bun, Deno, and modern browsers
- ESM and CommonJS support
Installation
npm install owls-insight-tsQuick Start
import { OwlsInsight } from "owls-insight-ts";
const client = new OwlsInsight({ apiKey: process.env.OWLS_INSIGHT_API_KEY! });
// Get NBA odds from all books
const odds = await client.rest.getOdds("nba");
// odds.data is keyed by book: { pinnacle: [...], fanduel: [...], ... }
for (const [book, events] of Object.entries(odds.data)) {
console.log(`${book}: ${events.length} events`);
}
// Get odds from specific books
const filtered = await client.rest.getOdds("nba", {
books: ["pinnacle", "fanduel"],
});REST API
Odds
// All markets (moneyline + spreads + totals)
const odds = await client.rest.getOdds("nba");
// Single market
const ml = await client.rest.getMoneyline("nba");
const spreads = await client.rest.getSpreads("nfl");
const totals = await client.rest.getTotals("nhl");
// With filters
const filtered = await client.rest.getOdds("soccer", {
books: ["pinnacle", "bet365"],
league: "England - Premier League",
alternates: true, // requires Rookie+ tier
});International Basketball
International basketball leagues (EuroLeague, Spanish ACB, etc.) are available under the basketball sport key, separate from NBA/NCAAB.
// All international basketball odds
const intlBball = await client.rest.getOdds("basketball");
// Filter by league
const euroleague = await client.rest.getOdds("basketball", {
league: "EuroLeague",
});
// Real-time Pinnacle odds (MVP+ tier)
const realtime = await client.rest.getRealtime("basketball");Available leagues include EuroLeague, Spanish ACB, Italian Serie A, Greek League, Lithuanian NBL, Argentine La Liga, Venezuelan Superliga, and more.
Esports (CS2, Valorant, LoL)
const cs2 = await client.rest.getOdds("cs2");
const valorant = await client.rest.getOdds("valorant");
const lol = await client.rest.getOdds("lol");CS2 odds from 1xBet. Valorant and LoL from both 1xBet and Pinnacle. Esports use a separate WebSocket event (esports-update).
Live Scores
// All sports
const allScores = await client.rest.getScores();
// Specific sport
const nbaScores = await client.rest.getScores("nba");Player Props
// All books
const props = await client.rest.getProps("nba");
// Filtered
const filtered = await client.rest.getProps("nba", {
player: "LeBron",
category: "points",
books: ["pinnacle", "fanduel"],
});
// Single book (typed per-book response)
const fdProps = await client.rest.getBookProps("nba", "fanduel");
const mgmProps = await client.rest.getBookProps("nba", "betmgm"); // BetMGMPropsResponse
const b365Props = await client.rest.getBookProps("nba", "bet365"); // Bet365PropsResponse
// Props line movement history
const propsHistory = await client.rest.getPropsHistory("nba", {
game_id: "game_123",
player: "LeBron James",
category: "points",
book: "pinnacle",
hours: 24,
});
// Props cache statistics
const propsStats = await client.rest.getPropsStats();
const bet365Stats = await client.rest.getBookPropsStats("bet365");Box Scores & Stats (Rookie+ tier)
// NBA box scores for today
const stats = await client.rest.getStats("nba");
// Filter by date and player
const filtered = await client.rest.getStats("nba", {
date: "2026-03-05",
player: "LeBron",
});
// Rolling averages (L5/L10/L20)
const averages = await client.rest.getStatsAverages("nba", {
playerName: "LeBron James",
opponent: "Lakers", // optional H2H filter
});Real-Time Odds (MVP+ tier)
Sub-second Pinnacle odds via dedicated real-time pipeline. Available for all sports including international basketball.
const realtime = await client.rest.getRealtime("nba");
console.log(realtime.meta.source); // "pinnacle"
console.log(realtime.meta.events); // number of events
console.log(realtime.meta.available); // true if data exists
console.log(realtime.meta.freshness); // { ageSeconds, stale, threshold: 30 }The freshness object indicates data age. Data is considered stale after 30 seconds.
Odds History (MVP+ tier)
// Line movement history
const history = await client.rest.getOddsHistory({
eventId: "event_123",
book: "pinnacle",
market: "spreads",
side: "home",
hours: 24,
});Historical Archive (MVP+ tier)
// List completed games
const games = await client.rest.getHistoryGames({
sport: "nba",
startDate: "2026-03-01",
endDate: "2026-03-06",
});
// Get archived odds snapshots
const snapshots = await client.rest.getHistoryOdds({
eventId: "event_123",
book: "pinnacle",
market: "spreads",
});
// Get archived props snapshots
const propsSnapshots = await client.rest.getHistoryProps({
eventId: "event_123",
playerName: "LeBron James",
propType: "points",
});
// Get archived player stats
const playerStats = await client.rest.getHistoryStats({
sport: "nba",
playerName: "LeBron James",
startDate: "2026-01-01",
endDate: "2026-03-01",
});
// Get historical rolling averages
const histAvg = await client.rest.getHistoryStatsAverages({
playerName: "LeBron James",
sport: "nba",
});
// Get archived tennis match stats
const tennisStats = await client.rest.getHistoryTennisStats("event_123");
// CS2 match history
const cs2Matches = await client.rest.getCS2Matches({
team: "Natus Vincere",
stars: 4,
});
// Full match detail with map scores and player stats
const matchDetail = await client.rest.getCS2Match(2374324);
// Player stats across matches
const playerStats = await client.rest.getCS2Players({
playerName: "s1mple",
minRating: 1.3,
});Kalshi Prediction Markets
const markets = await client.rest.getKalshiMarkets("nba", {
status: "open",
});
// Browse series (e.g., KXNBAGAME, KXNFLSBMVP)
const series = await client.rest.getKalshiSeries();
// Markets within a series
const nbaGame = await client.rest.getKalshiSeriesMarkets("KXNBAGAME");Polymarket
Polymarket odds are also included as a bookmaker in the standard /odds response.
const markets = await client.rest.getPolymarketMarkets("nba");WebSocket Streaming
Real-time odds updates via WebSocket (Rookie+ tier).
Connect & Subscribe
const client = new OwlsInsight({ apiKey: process.env.OWLS_INSIGHT_API_KEY! });
await client.ws.connect();
// Subscribe to sports and books
client.ws.subscribe({
sports: ["nba", "nfl"],
books: ["pinnacle", "fanduel", "draftkings"],
});
// Listen for odds updates
client.ws.on("odds-update", (data) => {
console.log(`Update at ${data.timestamp}`);
// data.last_odds_change — when prices actually changed (vs heartbeat)
for (const [sport, events] of Object.entries(data.sports)) {
console.log(`${sport}: ${events.length} events`);
for (const event of events) {
console.log(` ${event.away_team} @ ${event.home_team}`);
}
}
});Update & Query Subscription
// Update an existing subscription
client.ws.updateSubscription({ sports: ["nba", "nhl", "soccer"] });
// Query current subscription state
client.ws.getSubscription();
client.ws.on("subscription", (sub) => {
console.log("Current subscription:", sub.sports, sub.books);
});Props Streaming
// Subscribe to Pinnacle props for specific sports
client.ws.subscribeProps({ sports: ["nba", "nhl"] });
// Subscribe to a specific book's props
client.ws.subscribeProps({ sports: ["nba"] }, "fanduel");
// Filter by categories
client.ws.subscribeProps({
sports: ["nba"],
categories: ["points", "rebounds", "assists"],
});
// Subscribe to all books
client.ws.subscribeProps({ sports: ["nba"] }); // Pinnacle
client.ws.subscribeProps({ sports: ["nba"] }, "fanduel"); // FanDuel
client.ws.subscribeProps({ sports: ["nba"] }, "draftkings"); // DraftKings
client.ws.subscribeProps({ sports: ["nba"] }, "bet365"); // Bet365
client.ws.subscribeProps({ sports: ["nba"] }, "betmgm"); // BetMGM
client.ws.subscribeProps({ sports: ["nba"] }, "caesars"); // Caesars
client.ws.on("player-props-update", (data) => {
console.log("Pinnacle props:", data.sports);
});
client.ws.on("fanduel-props-update", (data) => {
console.log("FanDuel props:", data.sports);
});
// Confirmation events
client.ws.on("props-subscribed", (sub) => {
console.log("Pinnacle props active:", sub);
});
// Unsubscribe
client.ws.unsubscribeProps(); // Pinnacle
client.ws.unsubscribeProps("fanduel"); // FanDuelReal-Time Pinnacle (MVP+ tier)
Pushed automatically to all MVP+ clients — no subscription needed.
client.ws.on("pinnacle-realtime", (data) => {
// data contains per-sport arrays: nba, ncaab, nfl, nhl, ncaaf, mlb, tennis, soccer, basketball
for (const event of data.nba) {
console.log(`${event.away_team} @ ${event.home_team}`);
const pinnacle = event.bookmakers.find((b) => b.key === "pinnacle");
for (const market of pinnacle?.markets || []) {
console.log(` ${market.key}:`, market.outcomes);
}
}
});Esports Updates
// Opt in to all esports via subscribe
client.ws.subscribe({
sports: ["nba"],
books: ["pinnacle"],
esports: true,
});
// Or filter to specific esports
client.ws.subscribe({
sports: ["nba"],
esports: ["cs2", "valorant"],
});
client.ws.on("esports-update", (data) => {
console.log(`CS2: ${data.sports.cs2?.length}`);
console.log(`Valorant: ${data.sports.valorant?.length}`);
console.log(`LoL: ${data.sports.lol?.length}`);
});Game-Specific Updates
client.ws.subscribeGame("event_123");
client.ws.on("odds-update", (data) => {
// Will include targeted updates for subscribed games
});
client.ws.unsubscribeGame("event_123");Line History via WebSocket
// Request odds history
client.ws.requestHistory({
requestId: "req_1",
eventId: "event_123",
book: "pinnacle",
market: "spreads",
side: "home",
hours: 24,
});
client.ws.on("history-response", (data) => {
if (data.success && data.data) {
console.log(`${data.data.history.length} data points`);
}
});
// Request props history
client.ws.requestPropsHistory({
requestId: "req_2",
gameId: "game_123",
player: "LeBron James",
category: "points",
book: "pinnacle",
hours: 12,
});
client.ws.on("props-history-response", (data) => {
if (data.success && data.data) {
console.log(`${data.data.dataPoints} data points`);
}
});Promise-Based Waiting
// Wait for the next odds update
const update = await client.ws.waitFor("odds-update", 10_000);
// Wait for subscription confirmation
client.ws.subscribe({ sports: ["nba"], books: ["pinnacle"] });
const sub = await client.ws.waitFor("subscribed");
console.log("Subscribed to:", sub.sports);Error Handling
client.ws.on("error", (err) => {
console.error("WebSocket error:", err.message, err.code);
});
client.ws.on("disconnect", (reason) => {
console.log("Disconnected:", reason);
});Cleanup
// Disconnect WebSocket
client.ws.disconnect();
// Or destroy everything
client.destroy();Error Handling
The SDK throws typed errors for different failure modes:
import {
OwlsInsightError,
AuthenticationError,
ForbiddenError,
RateLimitError,
} from "owls-insight-ts";
try {
const odds = await client.rest.getOdds("nba");
} catch (err) {
if (err instanceof RateLimitError) {
console.log(`Rate limited. Retry in ${err.retryAfterMs}ms`);
} else if (err instanceof AuthenticationError) {
console.log("Invalid API key");
} else if (err instanceof ForbiddenError) {
console.log("Upgrade your subscription tier");
} else if (err instanceof OwlsInsightError) {
console.log(`API error ${err.status}: ${err.message}`);
}
}The API returns rate limit headers on every response:
X-RateLimit-Remaining-Minute— requests left this minuteX-RateLimit-Remaining-Month— requests left this monthX-RateLimit-Reset-Minute— Unix timestamp (ms) when the minute limit resetsX-RateLimit-Reset-Month— ISO 8601 timestamp when the month limit resets
Configuration
const client = new OwlsInsight({
apiKey: process.env.OWLS_INSIGHT_API_KEY!, // Required
baseUrl: "https://api.owlsinsight.com", // Optional (default)
wsUrl: "https://api.owlsinsight.com", // Optional (default, same as baseUrl)
timeout: 30000, // Optional request timeout in ms (default: 30s)
});Supported Sports
| Sport | Key | Props | Real-Time | Scores |
|-------|-----|-------|-----------|--------|
| NBA | nba | Yes | Yes | Yes |
| NCAAB | ncaab | Yes | Yes | Yes |
| NFL | nfl | Yes | Yes | Yes |
| NHL | nhl | Yes | Yes | Yes |
| NCAAF | ncaaf | Yes | Yes | Yes |
| MLB | mlb | Yes | Yes | Yes |
| Soccer | soccer | Yes | Yes | Yes |
| Tennis | tennis | - | Yes | Yes |
| MMA | mma | - | - | - |
| CS2 | cs2 | - | - | Yes |
| Valorant | valorant | - | - | Yes |
| LoL | lol | - | - | Yes |
| Intl Basketball | basketball | - | Yes | - |
Sportsbooks & Coverage
| Book | Game Odds | Player Props | Notes | |------|-----------|-------------|-------| | Pinnacle | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer, Tennis | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer | Sharp/reference line | | FanDuel | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer, Tennis | NBA, NCAAB, NFL, NHL, NCAAF | | | DraftKings | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer, Tennis | NBA, NCAAB, NFL, NHL, NCAAF | | | BetMGM | NBA, NCAAB, NFL, NHL, NCAAF, MLB | NBA, NCAAB, NFL, NHL, NCAAF | | | Bet365 | NBA, NCAAB, NFL, NHL, NCAAF, MLB | NBA, NCAAB, NFL, NHL, NCAAF | | | Caesars | NBA, NCAAB, NFL, NHL, NCAAF, MLB | NBA, NCAAB, NFL, NHL, NCAAF | | | BetOnline | MMA | - | UFC/MMA only | | 1xBet | CS2, Valorant, LoL, Soccer | - | Esports + soccer | | Circa Sports | NBA, NCAAB, NFL, NHL, NCAAF, MLB | - | Vegas sharp book | | South Point | NBA, NCAAB, NFL, NHL, NCAAF, MLB | - | Vegas | | Westgate SuperBook | NBA, NCAAB, NFL, NHL, NCAAF, MLB | - | Vegas | | Wynn | NBA, NCAAB, NFL, NHL, NCAAF, MLB | - | Vegas | | Stations Casinos | NBA, NCAAB, NFL, NHL, NCAAF, MLB | - | Vegas | | Kalshi | NBA, NCAAB, NFL, NHL, MLB | - | Prediction market | | Polymarket | NBA, NCAAB, NFL, NHL, MLB, Soccer | - | Decentralized exchange |
Pricing
See owlsinsight.com for current plans and pricing.
License
MIT
