owls-insight-ts
v0.23.0
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,
});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
// 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",
});
Real-Time Odds
Sub-second sharp Pinnacle odds via dedicated real-time pipeline. Available for all sports.
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 }The freshness object indicates data age. Data is considered stale after 30 seconds.
Odds History
// Line movement history
const history = await client.rest.getOddsHistory({
eventId: "event_123",
book: "pinnacle",
market: "spreads",
side: "home",
hours: 24,
});Historical Archive
// 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 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 cs2Players = await client.rest.getCS2Players({
playerName: "s1mple",
minRating: 1.3,
});
// Closing odds per sportsbook (9 books, 2016-present)
const closing = await client.rest.getClosingOdds({
sport: "nba",
startDate: "2026-03-01",
endDate: "2026-03-10",
});
// Historical player props (4 books, 2022-present)
const histProps = await client.rest.getHistoricalPlayerProps({
sport: "nba",
player: "LeBron James",
propType: "points",
});
// Public betting percentages (2019-present)
const publicBetting = await client.rest.getPublicBetting({
sport: "nba",
limit: 50,
});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");Betting Splits
const splits = await client.rest.getSplits("nba");WebSocket Streaming
Real-time odds updates via WebSocket.
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 Subscription
// Update an existing subscription
client.ws.updateSubscription({ sports: ["nba", "nhl", "soccer"] });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
Pushed automatically — no subscription needed.
client.ws.on("pinnacle-realtime", (data) => {
// data is keyed by sport: { nba: [...], tennis: [...], timestamp: "..." }
for (const [sport, events] of Object.entries(data)) {
if (sport === "timestamp" || !Array.isArray(events)) continue;
console.log(`${sport}: ${events.length} events`);
for (const event of events) {
console.log(` ${event.away_team} @ ${event.home_team}`);
const pinnacle = event.bookmakers.find((b: any) => 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}`);
});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 required for this endpoint");
} 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 | Scores |
|-------|-----|-------|--------|
| NBA | nba | Yes | Yes |
| NCAAB | ncaab | Yes | Yes |
| NFL | nfl | Yes | Yes |
| NHL | nhl | Yes | Yes |
| NCAAF | ncaaf | Yes | Yes |
| MLB | mlb | - | Yes |
| Soccer | soccer | - | Yes |
| Tennis | tennis | - | Yes |
| MMA | mma | - | - |
| CS2 | cs2 | - | Yes |
| Valorant | valorant | - | Yes |
| LoL | lol | - | Yes |
Sportsbooks & Coverage
| Book | Game Odds | Player Props | Notes | |------|-----------|-------------|-------| | Pinnacle | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer, Tennis | NBA, NCAAB, NFL, NHL, NCAAF | Sharp/reference line | | FanDuel | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer | NBA, NCAAB, NFL, NHL, NCAAF | | | DraftKings | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer | NBA, NCAAB, NFL, NHL, NCAAF | | | BetMGM | NBA, NCAAB, NFL, NHL, NCAAF, MLB | NBA, NCAAB, NFL, NHL, NCAAF | | | Bet365 | NBA, NCAAB, NFL, NHL, NCAAF, Soccer | 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, MLB | - | Esports + soccer + MLB | | 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 | | Novig | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer, Tennis | - | Peer-to-peer exchange |
Pricing
See owlsinsight.com for current plans and pricing.
License
MIT
