Event sources

Every source feeds the same server core (create → settle) behind a generic fixtures abstraction. The core never knows whether an event came from a real API or from your imagination. By default odds are generated by HZ-Bets (pool-priced) — or, with the optional the-odds-api source below, imported as real bookmaker lines (fixed odds).


ESPN — all sports, keyless

Config.Sources.espn pulls ESPN's public scoreboard for every configured league: NBA, WNBA, MLB, NHL, NFL, UFC, and worldwide football (Premier League, La Liga, Ligue 1, Bundesliga, Serie A, MLS, Brazil, Mexico…). Football becomes a 1/X/2 market; every other sport a 2-way Winner.

It auto-creates upcoming fixtures, streams the live score, and auto-settles on the real result. Each league is one config line:

Leagues = {
    { sport = 'basketball', league = 'nba' },
    { sport = 'baseball',   league = 'mlb' },
    { sport = 'hockey',     league = 'nhl' },
    { sport = 'football',   league = 'nfl' },     -- American football
    { sport = 'mma',        league = 'ufc' },     -- per-fight on a card
    { sport = 'soccer',     league = 'eng.1' },   -- Premier League
    -- … add / remove freely
}

Off-season leagues simply return nothing; in-season ones fill the board automatically.

Unofficial endpoint. ESPN's scoreboard is public and keyless but undocumented — ESPN gives no guarantee and could change it. HZ-Bets degrades gracefully: a bad / empty / unexpected response does nothing (it keeps serving the last-known board and never settles on bad data). If ESPN ever changes its format, live updates pause until a script update — bets are never corrupted. It is opt-in by design (Config.Sources.espn.Enabled).

How it settles: the score is the source of truth (the winner flag only ever vetoes a disagreement), and an event only settles on a clean, played final — never on a postponed / abandoned game.


the-odds-api — real bookmaker odds (optional)

ESPN gives you fixtures but no odds — so a fresh board opens at symmetric pool prices until players bet. Config.Sources.oddsapi fills events with real, data-driven odds instead: the same market lines the big betting apps show, via the-odds-api.com. It prices the sports ESPN can't, including NRL and AFL, plus soccer, NBA, NFL, MLB, NHL and MMA. These events use fixed odds (a consensus line averaged across bookmakers) and settle on the real final score.

Server-side key — never exposed to a client. Grab a free key at the-odds-api.com and set it in your server.cfg (it is never shipped inside the resource and never sent to the NUI):

set hz_bets_oddsapi_key "your_key_here"

Then enable the sports you want (keys from the-odds-api.com/sports):

oddsapi = {
    Enabled = true,
    Regions = 'au',                  -- 1 region = 1 quota credit; 'au' for Aussie books
    Sports  = { 'rugbyleague_nrl' }, -- e.g. add 'aussierules_afl', 'soccer_epl', 'basketball_nba'
    PollIntervalMin = 180,           -- odds refresh (pre-match lines barely move)
}

House risk. Real odds are fixed odds — the house carries the risk like an actual bookmaker (a heavily-backed winner pays out). It stays bounded by Config.Bet.MaxPayoutPerSelection and Config.Odds.MaxDecimal. If you want the house to never lose, keep that sport on the pool model instead.
Free-tier quota. the-odds-api's free plan is 500 requests / month. HZ-Bets is frugal by default — one region, odds polled every ~3 h, and scores polled only while a game is pending — which fits a single sport comfortably. More sports or faster refresh need a paid tier. The remaining quota is logged on every poll (enable Config.Debug).
Don't double up. If you price a sport with the-odds-api, remove it from Config.Sources.espn (and vice-versa), or both sources will create the same fixtures twice. Everything downstream — settlement, ledger, payouts — is identical to any other source.

OpenLigaDB — football, ODbL

Config.Sources.openligadb is a keyless, no-auth, open football feed (https://api.openligadb.de). List leagues as shortcut or shortcut/season (wm26/2026 for the World Cup, bl1/2025, dfb…). It auto-creates the configured markets with real team crests, auto-settles on the final score, and publishes the league's top scorers ("Top des Buteurs").

Attribution (ODbL). When OpenLigaDB is enabled the UI shows a "Données de match : OpenLigaDB · ODbL 1.0" credit. Keep it — it is required by the Open Database License.

In-play fixtures are polled on a faster cadence for live scores and fast settlement.


RP — admin-created events

The RP source has no external dependency: you create events by hand from the in-game admin screen — races, fights, fictional matches, anything — for any sport, with your own outcomes and odds. This is also how you create a bettable scorer (Buteur) market (admin picks who scored). See Markets & odds.


Graceful degradation

All API work is server-side only and cached; the client never calls an API. A source that returns garbage or goes down can never crash the resource, create a malformed event, or mis-settle a bet — it simply stops updating until it recovers. Already-created events stay visible (last-known board) the whole time.