Krok Odds API
Real-time arbitrage, positive EV, middle, and racing edge data for Australian sports markets — updated every 60 seconds across 100+ bookmakers.
⚡ Quick Start (5 Minutes)
Get Your API Key
Visit /api-dashboard and click "Create API Key". Copy the key — you'll need it for authentication.
Make Your First Request
curl https://krokodds.com.au/api/v1/opportunities/arbitrage?limit=5 \ -H "X-API-Key: YOUR_API_KEY_HERE"
Parse the Response
You'll receive a JSON response with arbitrage opportunities:
{
"success": true,
"data": [
{
"id": "arb_abc123",
"sport": "NBA",
"event": "Lakers vs Warriors",
"value": 2.3,
"bookmaker1": "Bet365",
"odds1": 2.10,
"bookmaker2": "Sportsbet",
"odds2": 2.05
}
],
"meta": {
"count": 1,
"timestamp": "2026-03-02T10:30:00Z"
}
}Build Your App!
You now have access to real-time betting opportunities. Build an arb alert bot, value betting dashboard, or integrate into your existing tools.
Postman Collection
Import our pre-configured Postman collection to test all endpoints instantly. Includes all query parameters and example responses.
Overview
Krok Odds scans 100+ bookmakers every 30 seconds across 135 sports. It identifies three types of edge:
- Arbitrage (arbs):Two bookmakers price the same event so differently that you can bet both sides and guarantee profit regardless of the result. ROI is typically 1–8%.
- Positive EV (snaps):One bookmaker's odds are higher than the mathematically "fair" price derived from the sharp exchange line. Over a large sample, these bets return profit.
- Middles:Totals or spreads lines differ enough across books that you can cover both sides. If the result lands in the window between lines, both legs win.
- Racing edge (dashboard only):Best fixed-odds across AU books vs the licensed exchange lay price. Available in the web dashboard. Dedicated API endpoints are coming soon.
All data is computed server-side by our proprietary scanning engine. Once prices are collected, the sharpest available exchange line is used as the fair-price benchmark — if a bookie beats that implied fair price after commission, that's a snap. If two bookies combined imply <100% probability, that's an arb.
Bookmaker Coverage
Every book Krok Odds prices, across all feeds — The Odds API, RapidOdds, Betfair and the major AU aggregator platforms. Clone brands on a white-label platform share one odds line (coverage breadth, not extra prices), so the API dedupes them to a single priced line. Expand a platform row to see every brand it covers.
Named bookmakers
Aggregator platforms
Each platform powers many white-label betting sites that all publish the same odds line. Expand a row to see every brand it covers.
Authentication
All API requests require an API key. You can pass it as a query parameter or as an HTTP header. Headers are preferred — they don't show up in server logs or browser history.
GET /api/v1/opportunities?type=arbs X-API-Key: krok_live_xxxxxxxxxxxxxxxx
GET /api/v1/opportunities?type=arbs&apikey=krok_live_xxxxxxxxxxxxxxxx
sport (human label like AFL) or sport_key (internal sport key like aussierules_afl). Use GET /v1/sports to see all active sport keys.Rate Limit Headers
Every response includes these headers:
| Header | Description |
|---|---|
| X-RateLimit-Tier | Your plan tier (hobby / pro / enterprise) |
| X-RateLimit-Limit | Max results per request for your tier |
| X-RateLimit-Remaining | Requests remaining this month |
| X-RateLimit-Reset | Date your monthly quota resets |
GET /api/v1/opportunities
The main endpoint. Returns arbs, EV snaps, middles, low holds, racing edges, and player props — all filtered and sorted by value. Results are cached server-side per tier: Hobby 60s · Pro 30s · Enterprise 15s.
GET https://krokodds.com.au/api/v1/opportunities
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| type | string | required | all | Which opportunity type to return. One of: all · arbs · snipes · middles · low_holds · racing · playerprops. positive-ev is accepted as an alias for snipes. |
| sport | string | optional | (all sports) | Filter by sport label (e.g. AFL, NBA, NRL, EPL). Case-insensitive. |
| sport_key | string | optional | (none) | Filter by internal sport key (e.g. aussierules_afl, basketball_nba). More precise than sport — use this when targeting a specific league. |
| minvalue | number | optional | 0 | Minimum edge / ROI % to include. e.g. 2.0 returns only arbs ≥2% ROI. |
| limit | integer | optional | 100 | Max results per type. Capped by your tier: Hobby=100, Pro=500, Enterprise=10,000. |
| apikey | string | optional | — | Your API key. Prefer X-API-Key header instead. |
Quick start
curl -G "https://krokodds.com.au/api/v1/opportunities" \ -H "X-API-Key: YOUR_API_KEY" \ --data-urlencode "type=arbs" \ --data-urlencode "minvalue=2.0" \ --data-urlencode "limit=20"
Dedicated Opportunity Endpoints
Each opportunity type also has a dedicated endpoint. They return the same object fields as the aggregated /opportunities?type=… call, but the wrapper is a flat {"data":[...]} array (cursor-paginated, fields= projection supported) instead of the keyed {"data":{"<type>":[...]}} map.
| Endpoint | Aggregated equivalent | Tier · Cache |
|---|---|---|
| /api/v1/opportunities/arbitrage | ?type=arbs | Hobby+ · 60/30/15s |
| /api/v1/opportunities/low-holds | ?type=low_holds | Hobby+ · 60/30/15s |
| /api/v1/opportunities/positive-ev | ?type=snipes | Pro+ · 300s |
| /api/v1/opportunities/middles | ?type=middles | Pro+ · 300s |
| /api/v1/opportunities/player-props | ?type=playerprops | Pro+ · see below |
Racing
Australian thoroughbred (T), harness (H), and greyhound (G) coverage. Three live endpoints: arbs, movers, and meetings.
GET /api/v1/racing/arbsEnterprise
Two-leg racing arbitrage records. Filter by venue, race type, and minimum edge.
GET /api/v1/racing/arbs?race_type=T&venue=randwick&minedge=2&limit=20
Params: venue (substring), race_type (T|H|G), minedge (number, default 0), limit (tier-capped: 100 / 500 / 10000).
{
"success": true,
"data": [
{
"id": "flemington_r4_horse_7",
"venue": "Flemington",
"race_number": 4,
"race_name": "TAB Handicap",
"race_type": "T",
"jump_time": "2026-03-01T05:10:00Z",
"runner": "Gatwick",
"arb_type": "each-way-arb",
"leg1_bookmaker": "Sportsbet",
"leg1_odds": 6.5,
"leg2_bookmaker": "Bet365",
"leg2_odds": 1.68,
"edge": 2.41,
"stake1_pct": 20.52,
"stake2_pct": 79.48,
"all_legs": null,
"detected_at": "2026-03-01T04:59:10Z"
}
],
"meta": {
"count": 1,
"tier": "pro",
"limit": 50,
"requested_limit": 50,
"timestamp": "2026-03-01T05:00:00Z"
}
}arb_type: win-arb (two AU bookmakers on the win market) or each-way-arb (win at one book vs place at another). all_legs is populated only for multi-leg constructions and is null for the two-leg default.
GET /api/v1/racing/moversEnterprise
Steamers (shortening) and drifters (lengthening) merged into a single response.
GET /api/v1/racing/movers?movement_type=steamer&race_type=T&min_movement=10&limit=20
Params: venue, race_type (T|H|G), movement_type (steamer|drifter), min_movement (%, default 0), limit (tier-capped: 100 / 500 / 10000).
GET /api/v1/racing/meetingsEnterprise
Today's meetings + full race cards. Each meeting includes BOM weather observation, BOM 7-day forecast, track condition hint, races[] with runner-level fields (barrier, jockey, trainer, weight, form, scratchings, top-of-book win/place, and a per-bookmaker odds[] grid).
GET /api/v1/racing/meetings?race_type=T&venue=flemington&limit=50
Params: race_type (T|H|G), venue (substring), limit (tier-capped: 50 / 200 / 1000). Cache TTL 120 / 60 / 30 seconds. See Racing meeting object below for the full field reference.
GET /api/v1/tips
ML-driven game picks. Active (gameday) by default; pass include_settled=true to read historical settled tips for accuracy audits.
GET /api/v1/tips?sport_key=basketball_nba&min_confidence=3&limit=20
Params: sport_key, min_confidence (1–5), include_settled (boolean), limit (tier-capped: 50 / 200 / 1000). Cache TTL 120 / 60 / 30 seconds.
{
"success": true,
"data": [
{
"id": "tip_abc",
"event_id": "...",
"sport_key": "basketball_nba",
"home_team": "Boston Celtics",
"away_team": "LA Lakers",
"commence_time": "...",
"pick": "Boston Celtics",
"pick_side": "home",
"confidence": 4,
"confidence_label": "Strong",
"consensus_prob_home": 0.62,
"consensus_prob_away": 0.38,
"predicted_margin": 7.5,
"predicted_margin_side": "home",
"resolution": "pending",
"actual_winner": null
}
]
}GET /api/v1/results
Final scores for completed games. winner is derived server-side as home, away, or draw.
GET /api/v1/results?sport_key=basketball_nba&since=2026-05-01&limit=100
Params: sport_key, since (ISO 8601 date — filters commence_time ≥), limit (tier-capped: 100 / 500 / 5000). Cache TTL 300 / 120 / 60 seconds.
GET /api/v1/injuries
Current injury status feed. Ordered most-recently-updated first.
GET /api/v1/injuries?sport_key=basketball_nba&team=lakers&limit=100
Params: sport_key, team (substring), limit (tier-capped: 100 / 500 / 5000). Cache TTL 600 / 300 / 120 seconds.
{
"success": true,
"data": [
{
"id": "inj_abc",
"sport_key": "basketball_nba",
"player_name": "LeBron James",
"player_slug": "lebron-james",
"team": "Los Angeles Lakers",
"status": "day-to-day",
"reason": "ankle",
"date": "2026-05-17",
"season": "2025-26",
"source": "krok-odds",
"updated_at": "..."
}
]
}GET /api/v1/historical/player-game-log
Per-player game log archive. Requires sport_key. Returns each player's recent_games[] sorted most-recent first. Substring filter on player or team applies in-memory after the indexed query.
GET /api/v1/historical/player-game-log?sport_key=basketball_nba&player=lebron&limit=50
Params: sport_key (required), player (substring), team (substring), season, limit (tier-capped: 50 / 200 / 2000). Cache TTL 600 / 300 / 120 seconds.
GET /api/v1/historical/team-game-log
Team-level game log archive. Requires sport_key. Returns final score, period splits, league, country, and status per game.
GET /api/v1/historical/team-game-log?sport_key=basketball_nba&team=lakers&limit=100
Params: sport_key (required), team (substring matches home OR away), since (ISO date), until (ISO date), limit (tier-capped: 100 / 500 / 5000). Cache TTL 600 / 300 / 120 seconds.
GET /api/v1/gameday/h2h
Head-to-head record snapshot for upcoming fixtures. Returns aggregate summary (total meetings, home/away wins, draws, win %) plus last_meetings[] ordered most recent first.
GET /api/v1/gameday/h2h?sport_key=aussierules_afl&limit=50
Params: sport_key, home_team (substring), away_team (substring), event_id, limit (tier-capped: 50 / 200 / 2000). Cache TTL 300 / 120 / 60 seconds.
GET /api/v1/gameday/best-prices
Top-of-book per market and selection for upcoming fixtures, with the offering bookmaker and how many books currently list that selection.
GET /api/v1/gameday/best-prices?sport_key=basketball_nba&market=h2h&limit=50
Params: sport_key, event_id, market (h2h|spreads|totals or player prop key), limit (tier-capped: 50 / 200 / 2000). Cache TTL 120 / 60 / 30 seconds.
GET /api/v1/odds-history
Open/latest/movement summary per event-market-selection. direction is one of drift, shorten, flat. Set include_snapshots=true to also return raw tick history (much larger payload).
GET /api/v1/odds-history?sport_key=basketball_nba&market=h2h&include_snapshots=false&limit=25
Params: sport_key, event_id, market, selection (substring), include_snapshots (boolean), limit (tier-capped: 25 / 100 / 1000). Cache TTL 300 / 120 / 60 seconds.
GET /api/v1/steam-movesPro+
Sharp money signal feed: outcomes where multiple AU books shifted at the same time. direction is shortening or drifting; move_pct is the signed % change. Most recent first, server caps at 250 to keep latency tight.
GET /api/v1/steam-moves?sport_key=basketball_nba&direction=shortening&min_move_pct=5&limit=50
Params: sport_key, event_id, direction (shortening|drifting), min_move_pct (number), limit (tier-capped: 50 / 200 / 1000). Cache TTL 120 / 60 / 30 seconds.
GET /api/v1/tips/accuracy
Model track record. Returns wins / losses / pushes / decided / hit_rate rolled up per sport, with a by_confidence[] breakdown.
GET /api/v1/tips/accuracy?sport_key=basketball_nba
Params: sport_key (optional — omit to list all sports ordered by sample size), limit (tier-capped: 50 / 200 / 1000). Cache TTL 600 / 300 / 120 seconds.
GET /api/v1/racing/resultsEnterprise
Historical AU race results with BSPs. Each item has the winning runner plus the full sorted runners[] list (finish position, win/place results, jockey, trainer).
GET /api/v1/racing/results?race_type=T&track_slug=randwick&since=2026-04-01&limit=50
Params: race_type (T|H|G), track_slug, track (substring), runner_slug, since, until, limit (tier-capped: 50 / 200 / 2000). Cache TTL 600 / 300 / 120 seconds.
GET /api/v1/teams/canonical
Canonical team registry — the lookup table behind slug-based filtering across the rest of the API. Slow-changing, aggressively cached.
GET /api/v1/teams/canonical?sport_key=basketball_nba&limit=100
Params: sport_key, slug, name (substring), limit (tier-capped: 100 / 500 / 5000). Cache TTL 3600 / 1800 / 600 seconds.
GET /api/v1/sports
Returns all sports supported by the Krok Odds engine. Optional filter by category.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| apikey | string | Required. Your API key (or X-API-Key header) |
| category | string | Filter by category (e.g. Soccer, Cricket, Tennis) |
Example Response
{
"success": true,
"data": [
{
"key": "aussierules_afl",
"label": "AFL",
"category": "AU Sports",
"au_coverage": "high",
"refresh_interval_seconds": 60
}
],
"meta": { "total": 76, "timestamp": "..." }
}GET /api/v1/status
Public endpoint. No API key required. Returns sync engine health and last update time.
{
"status": "operational",
"sync": {
"healthy": true,
"last_sync_seconds_ago": 18,
"cycle_count": 4821,
"remaining_api_credits": 4821
},
"timestamp": "..."
}GET /api/v1/bookmakers
Machine-readable bookmaker coverage registry — every book + exchange + aggregator feed Krok ingests (The Odds API, RapidOdds, Betfair, TAB and more), with region and provider metadata. All tiers (rate-limited, no feature gate). Filter by region (au/us/uk/eu), provider, include_aggregators (true/false), and fields projection. Tier caps 100/500/10000.
GET /api/v1/gameday/props
Pre-computed player-prop snapshots used by the gameday board. One row per event with props denormalised inside. Filter by sport_key, event_id, market, or player_slug. Tier caps 50/200/2000. Cache 300/120/60s.
GET /api/v1/gameday/summaries
Editorial summaries (headline + storylines + best price snapshot) keyed by event. Filter by sport_key or event_id. Tier caps 50/200/2000. Cache 600/300/120s.
GET /api/v1/gameday/alt-lines
Alternative-line ladders for spread + total markets. best_by_line keyed {market}|{line}. Tier caps 50/200/2000. Cache 300/120/60s.
GET /api/v1/extended-markets
Net-new derivative markets sourced beyond The Odds API — half / period / inning splits, soccer corners + cards, NHL per-period lines, MLB inning lines + total hits, AFL / NRL team-totals + tries, alt-totals. Mirrors the v4 bookmakers → markets → outcomes shape. Filter by sport_key, event_id, market (substring match on market key). Pro+. Tier caps 50/200/2000. Cache 300/120/60s.
GET /api/v1/gameday/live
In-play score + status snapshot. Filter by status (pre/live/final). Fastest TTL on the platform — cache 60/30/15s. Tier caps 50/200/2000.
GET /api/v1/gameday/event/{id}
Bulk endpoint. One call replaces seven — fans out across summary, h2h, best_prices, alt_lines, props, odds_history, live in parallel. Failed parts return null; never 5xx the whole bundle. sport_key required when parts includes h2h or live. Use parts=summary,best_prices to slim payloads. Cache 300/120/60s.
GET /api/v1/player-props-stats
Long-run hit/miss/push counters for player-prop lines. Filter by sport_key, player_slug, player_canonical, market_key, side (over/under). hit_rate is 0–1, 4dp. Tier caps 50/200/2000. Cache 600/300/120s.
GET /api/v1/player-props-results
Per-event resolved player-prop outcomes. outcomes[] is denormalised inside the doc; filter by player_name (substring) or market. event_id does a direct doc fetch (id slug-safe, /→_, ≤1500ch). Tier caps 50/200/2000. Cache 600/300/120s.
GET /api/v1/racing/runner-formEnterprise
Per-runner historical race form (sub-collection runner_historical_stats/{sport}__{slug}/recent_races). runner_slug required. Sport optional — when omitted, scans all three (racing_T/racing_H/racing_G). Tier caps 50/200/2000. Cache 600/300/120s.
GET /api/v1/sport-activity
Per-sport "is this active right now" flag with has_outrights. Filter by sport_key, group, or active=true. Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/ev-hit-rates
Roll-up CLV / EV / hit-rate stats per opportunity category (arb, ev, middles, low_holds, player_props). Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/opportunity-history
Read-side archive of expired opportunities. type filter (arb/ev), sport_key, since. Records cleaned up after 24h — backtest only. Tier caps 50/200/2000. Cache 300/120/60s.
GET /api/v1/closing-linesPro+
Closing-line snapshots for settled events — the consensus price at market close, for CLV backtesting. Filter by sport_key, event_id (direct doc fetch), or since. Tier caps 50/200/2000. Cache 600/300/120s.
GET /api/v1/weatherPro+
Per-event venue weather: temp, wind speed/direction, precipitation, conditions. Filter by event_id or sport_key. Outdoor sports only (NFL/AFL/MLB/soccer/racing); indoor returns null. Tier caps 100/500/5000. Cache 1800/600/300s.
GET /api/v1/stream/opportunitiesPro+
Server-Sent Events (SSE) live push of new arb/EV/middle/low-hold opportunities as they land — no polling. Content-Type: text/event-stream; each data: frame is one opportunity JSON. Filter by type, sport_key. Connection held open; reconnect with Last-Event-ID. Streaming is Pro+.
GET /api/v1/leaderboards/soccer
Soccer top-scorers / top-assists tables. kind (topscorers/topassists), league_id, season all required. Returns a single object with players[] truncated by limit. Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/mma/fights
Upcoming + completed MMA fight cards (UFC, Bellator, PFL). Filter by fight_id or since. Tier caps 50/200/2000. Cache 1800/600/300s.
GET /api/v1/f1/races
F1 race calendar with weather + circuit metadata. Filter by race_id, season, since. Tier caps 50/200/2000. Cache 1800/600/300s.
GET /api/v1/historical/player-statsPro+
Full player historical profiles: season averages, splits, coverage windows, market lines. sport_key required; slug (single player) and team (in-memory filter) optional. Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/historical/aflPro+
AFL archive (akareen + AFL Tables). kind=player (player game logs) or kind=match (results). Optional year; round (player only, in-memory). Matches 2010-2017 served from AFL Tables backfill (pass year), 2018+ from akareen. Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/historical/nrlPro+
NRL archive. kind=player / match (uselessnrlstats, 2010-2023) or kind=modern (NRL Match Centre, 2024+). Optional season. Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/soccer/closing-oddsPro+
Soccer match results with opening + closing odds across 6 leagues. league_code and/or season (string, e.g. 2021-2022). Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/advanced-statsPro+
Advanced / model-grade metrics by source: mlb_advanced (exit velo, barrel%, xwOBA — filter team/playerType), nhl_skaters (Corsi/Fenwick/PDO), ncaab_schools, soccer_xg, ncaaf_player_games, nfl_ngs (player tracking), nfl_snaps, nfl_depth, soccer_fbref (FBref per-season xG/npxG/xA + progressive carries — filter league/compId/sportKey/squad; attribution: “Data Provided by Sports Reference, LLC”), nrl_player_games (per-match NRL player stat lines — filter round/teamNickname/playerSlug), afl_matches (AFL match results w/ quarter-by-quarter goals/behinds — season maps to year, filter team1/team2/venue), tennis_closing_odds (Bet365 + Pinnacle closing odds per ATP/WTA match — season maps to year, filter tour/surface/round), nhl_moneypuck_skaters (MoneyPuck xG/Corsi/high-danger per skater season — filter team/position/playerSlug), nhl_moneypuck_goalies (MoneyPuck GSAx + danger-state goals against — filter team/playerSlug). season equality + source-specific in-memory filters (team/opponent/flavor/league/playerType/squad/round/tour/surface/venue). Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/cricket/inningsPro+
Ball-by-ball derived player innings (batting + bowling). sport_key, match_type (T20/ODI/Test), or season (string) — at least one required. Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/tennis/matchesPro+
ATP + WTA singles results. season (number); tour + surface narrow in-memory. Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/f1/resultsPro+
F1 driver race results (distinct from /f1/races schedule). season (number) + round (in-memory). Tier caps 100/500/5000. Cache 3600/1800/600s.
GET /api/v1/exchangePro+
Exchange pricing suite, one endpoint multiplexed by source: bsp (settled Starting Price — the sharpest AU racing closing price, filter raceKey/venueSlug/marketType), results (winners/losers/removed, filter raceKey), match_odds (exchange-implied h2h probs, equality sport + eventId), scorer_props (equality sport + eventId/marketType), snapshots (live pre-jump back/lay, equality sport + eventId). Tier caps 100/500/5000. Cache 600/300/120s.
GET /api/v1/exchange?source=bsp&venueSlug=randwick&limit=50
GET /api/v1/bulkEnterprise
Cursor-paginated whole-collection dumps of the historical archive. Omit dataset for the manifest; then pass dataset (e.g. team_game_logs, player_history, mlb_advanced, exchange_bsp) and walk pages via next_cursor until it is null. Tier caps 1000/1000/5000 per page. Cache 1800s.
GET /api/v1/bulk?dataset=player_history&limit=5000 GET /api/v1/bulk?dataset=player_history&cursor=<next_cursor>&limit=5000
GET /api/v1/reference/headshots
Static player headshot URLs (all tiers incl. Hobby). sport_key required; slug optional (single player). Returns name/slug/photo_url/source. Tier caps 200/1000/5000. Cache 86400/43200/21600s.
GET /api/v1/reference/team-logos
Static team logo URLs + name aliases (all tiers incl. Hobby). sport_key required. Returns names/logo/external_id/source. Tier caps 200/1000/5000. Cache 86400/43200/21600s.
GET /api/v1/predictionsPro+
api-sports prematch predictions cache. Single-doc mode (fixture_id) or list mode (sport_key, league_id, season, since filters). Soccer only at present. Fields: advice, winner, percent home/draw/away, under_over, goals avg, h2h_count. ai_overlay object adds Krok's AI-on-math layer: math_pick, ai_pick, final_pick, ai_confidence, alpha, ai_evidence, ai_agreed/ai_override, settler result. Math wins outright when top% ≥ 75; AI may override only with ≥ 0.5 confidence + ≥ 2 evidence tags + chosen side ≥ 22%. null until daily AI pass runs. Tier caps 100/500/5000. Cache 1800/600/300s.
GET /api/v1/me
Introspection endpoint. Returns the calling key's tier, monthly credit pool, sliding-window state, and a masked key preview. Never cached (Cache-Control: private, no-store) and never 429s — informational only.
{
"success": true,
"data": {
"tier": "pro",
"monthly_limit": 10000,
"current_usage": 1283,
"remaining": 8717,
"usage_pct": 12.83,
"reset_date": "2026-06-01",
"per_request_limit": 500,
"rate_limit_window": { "limit": 300, "remaining": 298, "reset": "2026-05-18T09:01:00.000Z" },
"api_key_preview": "krok...a4f9"
}
}Webhooks (Pro + Enterprise)
Receive real-time HTTP POST notifications when new opportunities are detected. Requires a Pro or Enterprise API plan.
Register a webhook
POST /api/v1/webhooks
Authorization: session cookie (logged in)
{
"url": "https://your-server.com/hook",
"events": ["arb", "ev", "middle"],
"minValue": 2.0
}Payload format
{
"event": "arb",
"timestamp": "2026-03-01T10:00:00Z",
"data": {
"id": "...",
"event": "Brisbane Lions v Melbourne Demons",
"sport": "aussierules_afl",
"value": 2.4,
"bookmaker1": "Sportsbet",
"bookmaker2": "TAB",
"odds1": 2.10,
"odds2": 2.05
}
}Verifying signatures
// Node.js
const sig = req.headers['x-krok-signature'] // "sha256=abc123..."
const expected = 'sha256=' + createHmac('sha256', YOUR_SECRET)
.update(rawBody).digest('hex')
if (sig !== expected) throw new Error('Invalid signature')
Response Objects
Arbitrage object type=arbs
Two bookmakers have diverging prices on the same event. Combined implied probability <100% = guaranteed profit. The value field is the ROI % on your total stake.
{
"success": true,
"data": {
"arbs": [
{
"id": "nrl_bulldogs_vs_broncos_tab_sportsbet",
"event": "Bulldogs vs Broncos",
"home_team": "Bulldogs",
"away_team": "Broncos",
"sport": "NRL",
"sport_key": "rugbyleague_nrl",
"market": "h2h",
"line": null,
"selection1": "Bulldogs",
"selection2": "Broncos",
"bookmaker1": "TAB",
"bookmaker2": "Sportsbet",
"odds1": 2.45,
"odds2": 1.80,
"value": 3.21,
"tool_type": "surebet",
"status": "upcoming",
"commence_time": "2026-03-02T10:30:00Z",
"updated_at": "2026-03-01T04:00:12Z",
"instructions": "Place $44.90 on Bulldogs @ TAB and $55.10 on Broncos @ Sportsbet"
}
]
},
"meta": {
"tier": "pro",
"limit": 500,
"requested_limit": 20,
"timestamp": "2026-03-01T04:00:15.234Z"
}
}| Field | Type | Description |
|---|---|---|
| id | string | Unique identifier for this opportunity. |
| event | string | Human-readable event name, format: "Home vs Away". |
| home_team | string | null | Home team parsed from event string. null if event format unexpected. |
| away_team | string | null | Away team parsed from event string. null if event format unexpected. |
| sport | string | Sport title, e.g. NRL, AFL, NBA. |
| sport_key | string | Sport key, e.g. rugbyleague_nrl. |
| market | string | Market type: h2h (moneyline), spreads, totals, or player prop key. |
| line | number | null | Spread/total line for spreads/totals/props markets. null for h2h. |
| selection1 | string | First outcome name, e.g. Bulldogs. |
| selection2 | string | Second outcome name, e.g. Broncos. |
| bookmaker1 | string | Bookmaker offering selection1 odds. |
| bookmaker2 | string | Bookmaker offering selection2 odds. |
| odds1 | number | Decimal odds for selection1. |
| odds2 | number | Decimal odds for selection2. |
| value | number | ROI % on total stake. e.g. 3.21 = 3.21% guaranteed profit. |
| tool_type | string | Always surebet for arbs. |
| status | string | upcoming · live · finished |
| commence_time | ISO 8601 | Event start time in UTC. |
| instructions | string | Plain English stake split, e.g. Bet $44.90 @ TAB and $55.10 @ Sportsbet. |
| updated_at | ISO 8601 | When this opportunity was last recalculated. |
EV Snap object type=snipes
One bookmaker is offering better-than-fair odds on a selection. Fair odds are derived from the sharp exchange back/lay benchmark (or market average if no exchange line is available). The value field is the EV % — how much you expect to return per $100 wagered, long-term.
{
"success": true,
"data": {
"snipes": [
{
"id": "afl_richmond_vs_geelong_sportsbet_geelong",
"event": "Richmond vs Geelong",
"home_team": "Richmond",
"away_team": "Geelong",
"sport": "AFL",
"sport_key": "aussierules_afl",
"market": "h2hev",
"line": null,
"selection1": "Geelong",
"bookmaker1": "Sportsbet",
"bookmaker2": "Exchange Fair",
"odds1": 2.10,
"odds2": 1.90,
"value": 4.72,
"confidence": "high",
"sharp_price": 1.90,
"tool_type": "positive_ev",
"status": "upcoming",
"commence_time": "2026-03-05T06:40:00Z",
"updated_at": "2026-03-01T04:00:12Z",
"instructions": "Bet $100 on Geelong @ Sportsbet (2.10). Fair price 1.90 → +4.72% EV."
}
]
},
"meta": {
"tier": "pro",
"limit": 500,
"timestamp": "2026-03-01T04:00:15.234Z"
}
}| Field | Type | Description |
|---|---|---|
| value | number | EV %. e.g. 4.72 = you expect +$4.72 per $100 bet over the long run. |
| sharp_price | number | The fair odds (no-vig exchange price or market average). This is your benchmark. |
| confidence | string | high = exchange-derived benchmark. lower = market average (less reliable). |
| home_team | string | null | Home team parsed from event string. |
| away_team | string | null | Away team parsed from event string. |
| line | number | null | Spread/total line for spreads/totals/props markets. null for h2h. |
| bookmaker2 | string | The sharp benchmark source: Exchange Fair or Market Avg. |
| market | string | h2hev for moneyline EV, or a player prop key e.g. playerpoints. |
| instructions | string | Plain English stake suggestion + fair-price benchmark. |
Racing meeting object /api/v1/racing/meetings
Full meeting + race + runner schema with BOM weather observation and 7-day forecast layered onto each meeting. Use races[].runners[].odds[] for the per-bookmaker price grid and best_win for the AU top of book.
{
"success": true,
"data": [
{
"id": "flemington_2026-03-01",
"venue": "Flemington",
"state": "VIC",
"type": "T",
"date": "2026-03-01",
"race_count": 9,
"next_jump": "2026-03-01T05:10:00Z",
"weather": {
"summary": "Partly cloudy",
"temp_c": 22.4,
"rain_24h_mm": 0.2,
"wind_kmh": 14,
"wind_dir": "SSW",
"station": "Melbourne Airport",
"observed_at": "2026-03-01T04:30:00Z"
},
"weather_forecast": {
"date": "2026-03-01",
"min_c": 14,
"max_c": 26,
"precis": "Mostly sunny.",
"rain_chance_pct": 10,
"rain_range_mm": "0",
"state": "VIC"
},
"track_hint": "Good 4",
"weather_updated_at": "2026-03-01T04:30:00Z",
"races": [
{
"id": "flemington_2026-03-01_r4",
"number": 4,
"jump_time": "2026-03-01T05:10:00Z",
"name": "TAB Handicap",
"distance": 1400,
"race_class": "BM78",
"status": "open",
"field_hold_pct": 104.2,
"runner_count": 12,
"runners": [
{
"id": "r7",
"number": 7,
"name": "Gatwick",
"barrier": 3,
"jockey": "J. McNeil",
"trainer": "C. Maher",
"weight": 57.5,
"form": "1-2-4",
"is_scratched": false,
"best_win": 6.50,
"best_win_bookmaker": "Sportsbet",
"implied_prob": 0.154,
"odds": [
{ "bookmaker": "Sportsbet", "win": 6.50, "place": 2.20 },
{ "bookmaker": "Bet365", "win": 6.00, "place": 2.10 }
]
}
]
}
]
}
],
"meta": {
"count": 1,
"tier": "pro",
"limit": 200,
"requested_limit": 50,
"timestamp": "2026-03-01T05:00:00Z"
}
}| Field | Type | Description |
|---|---|---|
| id | string | Meeting id, typically venue_date. |
| venue | string | Race venue, e.g. Flemington. |
| state | string | AU state code, e.g. VIC. |
| type | string | T = Thoroughbred, H = Harness, G = Greyhounds. |
| date | string | Meeting date YYYY-MM-DD. |
| race_count | number | Number of races on the card. |
| next_jump | ISO 8601 | null | Earliest future race jump time across the card. |
| weather | object | null | Latest BOM observation: summary, temp_c, rain_24h_mm, wind_kmh, wind_dir, station, observed_at. |
| weather_forecast | object | null | BOM 7-day forecast for the meeting date: min_c, max_c, precis, rain_chance_pct, rain_range_mm, state. |
| track_hint | string | null | Track condition hint (e.g. Good 4, Soft 6) when available. |
| weather_updated_at | ISO 8601 | null | When weather payload was last refreshed. |
| races[] | array | Race cards. Each entry has id, number, jump_time, name, distance, race_class, status, field_hold_pct, runner_count, runners[]. |
| races[].runners[] | array | Runners. Each: id, number, name, barrier, jockey, trainer, weight, form, is_scratched, best_win, best_win_bookmaker, implied_prob, odds[] (bookmaker/win/place). |
GET /api/stats/global
Live counts of all active opportunities in the system. Requires an active session (dashboard users only — not accessible via API key). Cached with 30-second stale-while-revalidate.
GET https://krokodds.com.au/api/stats/global
{
"totalCount": 847,
"arbCount": 124,
"snipeCount": 590,
"middleCount": 133,
"totalEv": 3.81,
"updatedAt": "2026-03-01T04:00:12.000Z"
}GET /api/trending
Returns the top 20 trending value picks (arbs, EV bets, middles) ranked by composite score across our tools. Requires an active session (dashboard users only — not accessible via API key). Refreshed by cron throughout the day.
GET https://krokodds.com.au/api/trending
{
"trending": [
{
"id": "trending_0",
"rank": 1,
"event": "Cowboys vs Knights",
"sport": "NRL",
"sportkey": "rugbyleague_nrl",
"market": "h2h",
"toolType": "arb",
"bookmaker1": "Sportsbet",
"bookmaker2": "TAB",
"selection1": "Cowboys",
"selection2": "Knights",
"odds1": 2.10,
"odds2": 2.05,
"value": 1.8,
"commencetime": "2026-03-01T08:00:00Z"
}
]
}Health & Status
GET /api/health
Returns server health. Use for uptime monitoring. No auth required.
{
"status": "healthy",
"timestamp": "2026-03-01T04:00:15.234Z",
"uptime": 86400.3,
"version": "1.0.0",
"environment": "production",
"checks": { "server": "ok" }
}GET /api/ready
Returns readiness check including Firestore connectivity. Returns 503 if not ready.
{
"ready": true,
"timestamp": "2026-03-01T04:00:15.234Z",
"checks": {
"firestore": "ok",
"environment": "ok"
}
}Supported Sports
Use the sport_key in the sport filter parameter. The sport_key is returned in every response object for use in your own filtering.
Krok Odds monitors 135 sports — live and upcoming markets refresh every ~60 seconds. Futures/outrights and preseason markets refresh every ~10 minutes.
AU Sports
aussierules_aflrugbyleague_nrlcricket_big_bashsoccer_australia_aleaguerugbyleague_nrl_state_of_originbasketball_nblrugbyunion_super_rugbyAmerican Football
americanfootball_nflamericanfootball_ncaafamericanfootball_cflamericanfootball_uflamericanfootball_nfl_preseasonamericanfootball_nfl_super_bowl_winneramericanfootball_ncaaf_championship_winnerBasketball
basketball_nbabasketball_ncaabbasketball_euroleaguebasketball_wnbabasketball_nba_preseasonBaseball
baseball_mlbbaseball_mlb_preseasonbaseball_kbobaseball_npbbaseball_ncaabaseball_mlb_world_series_winnerIce Hockey
icehockey_nhlicehockey_sweden_hockey_leagueicehockey_ahlicehockey_nhl_preseasonSoccer
soccer_eplsoccer_uefa_champs_leaguesoccer_germany_bundesligasoccer_italy_serie_asoccer_spain_la_ligasoccer_france_ligue_onesoccer_uefa_europa_leaguesoccer_usa_mlssoccer_conmebol_copa_libertadoressoccer_conmebol_copa_americasoccer_netherlands_eredivisiesoccer_portugal_primeira_ligasoccer_brazil_campeonatosoccer_mexico_ligamxsoccer_efl_champsoccer_fa_cupsoccer_uefa_europa_conference_leaguesoccer_fifa_world_cupsoccer_fifa_club_world_cupsoccer_england_league1soccer_england_league2soccer_scotland_premiershipsoccer_turkey_super_leaguesoccer_belgium_first_divsoccer_japan_j_leaguesoccer_korea_kleague1soccer_brazil_serie_bsoccer_chile_campeonatosoccer_china_superleaguesoccer_conmebol_copa_sudamericanasoccer_finland_veikkausliigasoccer_germany_dfb_pokalsoccer_league_of_irelandsoccer_norway_eliteseriensoccer_spain_segunda_divisionsoccer_sweden_allsvenskansoccer_sweden_superettansoccer_fifa_world_cup_winnerCombat Sports
mma_mixed_martial_artsboxing_boxingRugby Union
rugbyunion_six_nationsrugbyunion_world_cuprugbyunion_epcr_champions_cupCricket
cricket_iplcricket_test_matchcricket_international_t20cricket_t20_world_cupcricket_icc_world_cupcricket_odicricket_pslcricket_caribbean_premier_leaguecricket_t20_blastcricket_the_hundredcricket_t20_world_cup_womensTennis
tennis_atp_aus_open_singlestennis_atp_wimbledontennis_atp_us_opentennis_atp_french_opentennis_wta_aus_open_singlestennis_wta_wimbledontennis_wta_us_opentennis_wta_french_opentennis_atp_indian_wellstennis_atp_miami_opentennis_atp_madrid_opentennis_atp_canadian_opentennis_atp_cincinnati_opentennis_wta_indian_wellstennis_wta_miami_opentennis_wta_madrid_opentennis_wta_canadian_opentennis_atp_monte_carlo_masterstennis_atp_shanghai_masterstennis_atp_paris_masterstennis_atp_rome_opentennis_wta_rome_opentennis_atp_hamburg_opentennis_wta_strasbourg_opentennis_atp_geneva_opentennis_atp_halle_opentennis_atp_queens_club_champtennis_wta_german_openGolf
golf_masters_tournament_winnergolf_pga_championship_winnergolf_the_open_championship_winnergolf_us_open_winnergolf_pga_tour_winnerDarts
darts_betpt_dartsdarts_dartsSnooker
snooker_worldchampssnooker_snookerEsports
esports_lol_worldsesports_csgoesports_csgo_esl_pro_leagueesports_valorantesports_valorant_vct_championsesports_dota2esports_lolMotorsport
motorsport_formula_1_winnermotorsport_nascar_cup_seriesCycling
cycling_tour_de_france_winnercycling_vuelta_espana_winnercycling_giro_ditalia_winnerHandball
handball_germany_bundesligaVolleyball
volleyball_brazil_superligaLacrosse
lacrosse_pll🟢 High AU coverage = 10+ bookmakers price this regularly. 🟡 Medium = 4–9 bookmakers. 🔴 Low = 1–3 bookmakers.
Australian Bookmakers
All prices are collected from the au region. These are the bookmaker keys returned in API responses. The exchange price appears as betfairexau in raw data and is used as a sharp benchmark for fair-price calculation.
/api/v1/opportunities/player-propsReturns one-sided player prop opportunities (+EV over/under entries as separate records), with optional historical hit rate data. Covers NBA, NFL, AFL, NRL, MLB, NHL, and all major sports.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| sport | string | No | Filter by sport key (basketball_nba, aussierules_afl, rugbyleague_nrl, etc.) |
| market | string | No | Prop market (player_points, player_rebounds, player_assists, player_disposals, player_tackles, etc.) |
| player | string | No | Filter by player name (partial match supported) |
| min_ev | number | No | Minimum EV percentage (e.g., 3.0 for +3% EV or better) |
| include_stats | boolean | No | Include historical hit rates and player statistics (Pro tier and above only) |
| limit | number | No | Results per page (max based on your tier) |
Response Schema
| Field | Type | Description |
|---|---|---|
| id | string | Unique prop identifier |
| sport | string | Sport name (e.g. "NBA") |
| sport_key | string | Sport key for filtering |
| event | string | Event description |
| player_name | string | Player name |
| market_key | string | Prop market key |
| line | number | Over/Under line |
| side | string | "over" or "under" for this record |
| odds | number | Decimal odds for this side |
| bookmaker | string | Bookmaker for this side |
| ev_percentage | number | Expected value percentage for this side |
| commence_time | ISO 8601 | When the event starts |
| historical_stats | object | Historical performance data (if include_stats=true) |
Example Request
GET /api/v1/opportunities/player-props?sport=basketball_nba&min_ev=3&include_stats=true&limit=10 Headers: X-API-Key: YOUR_API_KEY_HERE
Example Response
{
"success": true,
"data": [
{
"id": "prop_xyz789",
"sport": "NBA",
"sport_key": "basketball_nba",
"event": "Lakers vs Warriors",
"player_name": "LeBron James",
"market_key": "player_points",
"line": 25.5,
"side": "over",
"odds": 1.90,
"bookmaker": "Bet365",
"ev_percentage": 4.2,
"commence_time": "2026-03-03T19:00:00Z",
"historical_stats": {
"hit_rate_over": 70,
"hit_rate_under": 30,
"last_10_games": [28, 31, 19, 33, 28, 24, 30, 22, 35, 26],
"streak": "over_3",
"home_rate": 75,
"away_rate": 58
}
}
],
"meta": {
"count": 147,
"timestamp": "2026-03-02T10:30:00Z",
"rate_limit": {
"limit": 100,
"remaining": 95,
"reset": "2026-03-02T11:00:00Z"
}
}
}💡 Pro Tip: Use include_stats=true (Pro tier+) to get historical hit rates, last 10 game results, current streaks, and home/away splits for better betting decisions.
/api/v1/opportunities/sgm-picksPro+Upcoming data-backed same-game multi suggestions (safe / value / longshot tiers), with legs, fair odds, minimum acceptable price, and confidence. Only events with commence_time in the future are returned.
Query Parameters
sport/sport_key— filter by sport keytier—safe,value, orlongshotmin_confidence— 1–5 (default 1)limit— max rows (tier caps: hobby 50, pro 200, enterprise 1000; default 20)
GET /api/v1/opportunities/sgm-picks?sport_key=aussierules_afl&tier=safe&min_confidence=3&limit=20 X-API-Key: YOUR_API_KEY
Tiers & Rate Limits
Response headers always include your current tier and request limit so you can track usage programmatically.
Arbitrage + low-hold only, plus reference data (team logos + player headshots). 100+ AU corporate bookmakers (no exchange pricing). 500 API requests per month. 100 results per request max.
Everything in Hobby + EV, middles, player props, steam moves, predictions, webhooks, gameday analysis, injury feed, plus the full exchange pricing suite (BSP, match-odds, scorer props, live snapshots, results) and full historical + advanced/modeling-stats + multi-sport archives (player stats, AFL/NRL, soccer closing odds, MLB advanced batted-ball, NHL/NFL/NCAA advanced, NFL player tracking, cricket, tennis, F1). 10,000 API requests per month. 500 results per request max.
Everything in Pro + AU racing (thoroughbred, harness, greyhound arbs/movers/form) and bulk dataset export (cursor-paginated whole-collection archive dumps for model training), 100,000 API requests per month, 10,000 results per request, priority support.
X-RateLimit-Tier: pro X-RateLimit-Limit: 300
📛 Error Codes
The API uses standard HTTP status codes to indicate success or failure. All error responses include a { success: false, error: "message" } body.
| Code | Meaning | Common Causes | Solution |
|---|---|---|---|
| 200 | Success | Request completed successfully | Parse the response data |
| 400 | Bad Request | Invalid parameters, malformed query | Check parameter names and values match documentation |
| 401 | Unauthorized | Missing or invalid API key | Ensure X-API-Key header is set correctly |
| 403 | Forbidden | API key doesn't have permission | Verify your subscription tier includes this endpoint |
| 429 | Too Many Requests | Rate limit exceeded | Wait until X-RateLimit-Reset time, or upgrade tier |
| 500 | Internal Server Error | Server-side issue | Retry request; contact support if persists |
| 503 | Service Unavailable | Maintenance or temporary outage | Check status page, retry with exponential backoff |
All errors return a consistent JSON shape:
{
"success": false,
"error": "Monthly request limit exceeded"
}💻 Code Examples
💻 Code Examples
Fetching Arbitrage Opportunities
These examples use the dedicated endpoint /opportunities/arbitrage, which returns a flat array in data. If you use /opportunities?type=arbs, read from data.arbs instead.
import requests
API_KEY = "your_api_key_here"
BASE_URL = "https://krokodds.com.au/api/v1"
headers = {
"X-API-Key": API_KEY
}
response = requests.get(
f"{BASE_URL}/opportunities/arbitrage",
headers=headers,
params={
"sport": "basketball_nba",
"min_value": 2.0,
"limit": 20
}
)
if response.status_code == 200:
data = response.json()
for arb in data["data"]:
print(f"Event: {arb['event']}")
print(f"Value: {arb['value']}% profit")
print(f"{arb['bookmaker1']}: {arb['odds1']}")
print(f"{arb['bookmaker2']}: {arb['odds2']}")
print("---")
else:
print(f"Error: {response.status_code} - {response.json()['error']}")Fetching Player Props with Statistics
import requests
r = requests.get("https://krokodds.com.au/api/v1/opportunities/player-props",
headers={"X-API-Key": API_KEY},
params={"sport": "basketball_nba", "player": "LeBron", "min_ev": 3, "include_stats": True, "limit": 10})
for prop in r.json()["data"]:
print(prop["player_name"], prop["market_key"], prop["side"], prop["ev_percentage"])Pro and Enterprise API keys support webhooks. Contact contact@krokodds.com.au to configure.
// Express.js webhook example
app.post('/webhook/krok', (req, res) => {
const { type, event, value, bookmaker1, bookmaker2, odds1, odds2 } = req.body
if (type === 'arb_alert' && value >= 3.5) {
console.log(`ARB: ${event} — ${bookmaker1} vs ${bookmaker2} — ROI: ${value.toFixed(2)}%`)
// your bet placement logic here
}
res.sendStatus(200)
})📋 Changelog
📋 Changelog
- ✨NEW:
/v1/exchange— full exchange pricing suite (Pro+) multiplexed bysource: settledbsp,results,match_odds,scorer_props, livesnapshots - ✨NEW:
/v1/bulk— Enterprise cursor-paginated whole-collection archive export for model training (manifest + 13 datasets) - 📈IMPROVED:
/v1/advanced-statsaddsmlb_advancedsource (exit velo, barrel%, xwOBA); injury feed now its owninjuriesentitlement
- ✨NEW:
/v1/tips— daily ML game picks with confidence 1–5, consensus probabilities, predicted margin; flips to settled tips viainclude_settled=true - ✨NEW:
/v1/results— final scores with server-derived winner (home/away/draw); filter bysport_key+since - ✨NEW:
/v1/injuries— current player injury feed with status, reason, season; updated-at sorted - ✨NEW:
/v1/racing/meetings— today's T/H/G meetings + race cards withnext_jumpand per-race runner counts - 🎯LIVE:
/v1/racing/arbsand/v1/racing/moversare now connected to the live racing feed (no longer “coming soon”) - 📈IMPROVED: SGM picks pre-filter pool now tier-aware (hobby 300, pro 1000, enterprise 3000) so high-tier callers no longer miss top-confidence picks beyond the legacy 300 cap
- ✨NEW: Player props endpoint with historical hit rates, last 10 games, streaks, and home/away splits
- 🎯IMPROVED: Response times reduced by 40% across all endpoints through optimized queries
- 📈IMPROVED: Uniform ~60-second refresh across all 135 sports for live and upcoming markets (futures/preseason every ~10 min)
- 🐛FIX: Odds formatting now consistent (always 2 decimal places) across all endpoints
- ✨NEW: Rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset)
- 🎯IMPROVED: Better error messages with specific guidance on how to resolve issues
- 🐛FIX: Timestamp format now consistent (ISO 8601) across all responses
- ✨NEW: Initial API launch with arbitrage, positive EV, middles, and low holds endpoints
- ✨NEW: Support for 12+ major sports including NBA, NFL, AFL, NRL, EPL, and more
Questions? contact@krokodds.com.au · View API Plans