Krok Odds

Tips & Predictions API endpoints

AI-generated betting tips with confidence scores and historical accuracy tracking.

4 of 4 endpoints · all categories · get a free API key

GET/api/v1/predictions→ alias of /api/v1/tipsFree tier

Deprecated alias of /api/v1/tips.

QUIRK: the file's own doc-comment claims it "proxies to tips with a sport_key=soccer filter for backwards compatibility", but the actual code is a bare re-export (`export { GET, OPTIONS } from '../tips/route'`) — NO soccer filter is applied; it is byte-identical behaviour to /api/v1/tips, all sports included. Comment is stale/misleading. Marked deprecated 2026-08-06, "will be removed in a future version" (no removal date set as of 2026-09-03). Same params/response/tier as /api/v1/tips.

Query parameters
NameTypeRequiredDefaultDescription
sport_keystringNo–Same as /api/v1/tips — filters by sport key despite the doc-comment implying a fixed soccer filter (that filter does not actually exist in code).
min_confidenceintegerNo1Same as /api/v1/tips.
limitintegerNo50Same as /api/v1/tips.
include_settledbooleanNofalseSame as /api/v1/tips.
Example request
curl \
  -H "X-API-Key: YOUR_KEY" \
  "https://krokodds.com.au/api/v1/predictions?sport_key=aussierules_afl"
Example response
"identical shape to /api/v1/tips — see that entry"
GET/api/v1/predictions/confidenceFree tier

Model confidence breakdown across racing, sports, and player props, plus 30-day historical accuracy by confidence bucket.

Gates on the 'tips' feature (tierAllowsFeature(tier,'tips')) even though the path is under /predictions. `force-dynamic`/`revalidate=0` — NOT cached via unstable_cache (response header still claims `Cache-Control: public, max-age=300` which is misleading given no server cache). Sports and props predictions are ONLY loaded if `sport`/`event_id` params are respectively provided — with type=all and neither param, only racing predictions populate. `summary.breakdown` is always `{}` in the current code (allBreakdowns is declared but never populated — dead aggregation). historicalAccuracy tries the primary store the settled-tips store first, falls back to the secondary store. A read that fails is never served as "no predictions": the three feeds report failure two ways (`available:false` from the loader's own swallow, or a thrown read) and both are named in `meta.failed_sources`; if every requested feed failed the route answers 503 + Retry-After: 30 with Cache-Control: no-store instead of a 200 with an empty list, and a partial failure is answered 200 but switched to `private, no-store` so a thin payload is never cached as a complete one; the historical-accuracy arm is additive and is named rather than fatal. An ENRICHMENT read inside a feed is named the same way and does not drop that feed's predictions: the sports arm reports the injury feed it could not read (`injury_data`) through `failedSources` while still serving the predictions it did read, so a scored prediction is never served as if the input it was scored on had been neutral.

Query parameters
NameTypeRequiredDefaultDescription
typestringNoall"racing" | "sports" | "props" | "all". Lowercased.
sportstringNo–Sport key — required for the sports branch to run (ignored if type excludes sports).
datestringNotoday (AU)YYYY-MM-DD — racing branch only.
event_idstringNo–Specific event id — required for the props branch to run.
limitintegerNo50Max predictions per type-branch; capped 20 (free) / 200 (api).
Example request
curl \
  -H "X-API-Key: YOUR_KEY" \
  "https://krokodds.com.au/api/v1/predictions/confidence?type=all"
Example response
{
  "success": true,
  "meta": {
    "type": "racing",
    "sport": null,
    "date": "2026-09-03",
    "eventId": null,
    "generatedAt": "2026-09-03T04:00:00.000Z",
    "cacheTtl": 300
  },
  "summary": {
    "overallConfidence": 0.74,
    "breakdown": {},
    "dataSources": [
      "racing_form",
      "sectionals",
      "barrier_trial",
      "weather"
    ],
    "historicalAccuracy": {
      "totalPredictions": 812,
      "correctPredictions": 471,
      "accuracyRate": 0.58,
      "byConfidenceBucket": {
        "high": {
          "total": 210,
          "correct": 148,
          "rate": 0.7
        },
        "medium": {
          "total": 380,
          "correct": 218,
          "rate": 0.57
        },
        "low": {
          "total": 222,
          "correct": 105,
          "rate": 0.47
        }
      }
    }
  },
  "predictions": [
    {
      "id": "racing-Written By-R6",
      "type": "racing",
      "confidence": 0.81,
      "dataSources": [
        "racing_form",
        "sectionals",
        "barrier_trial"
      ],
      "breakdown": {
        "weather": 0.6,
        "barrier": 0.75,
        "sectionals": 0.88,
        "pedigree": 0.55,
        "ensemble": 0.81
      },
      "reasoning": "Strong recent sectionals and barrier draw at Flemington R6."
    }
  ]
}
GET/api/v1/tipsFree tier

In-house model tips/predictions across all covered sports (active by default, or settled history with include_settled=true).

Uses the OLDER hand-rolled auth preamble (not the standard auth guard/the standard v1 route factory) — no explicit credit-cost debit in this file, API-key verification called with default cost. Merges canonical the tips engine engine picks over legacy the legacy tips engine (canonical wins on conflicting fixtures; legacy only fills 7 leagues the engine doesn't cover) — active-tips path only, not for include_settled=true which reads the settled-tips store directly. Free tier cache 120s, api tier 60s (the declared 30s api window is raised to the 60s v1Revalidate floor). Free tier capped at 50 rows/request, api tier 1000.

Query parameters
NameTypeRequiredDefaultDescription
sport_keystringNo–Filter by sport key. Alias: `sport`. Lowercased.
min_confidenceintegerNo1Minimum confidence 1-5, clamped.
limitintegerNo50Max rows; capped 50 (free) / 1000 (api) by getMaxLimit().
include_settledbooleanNofalse"true" to return the settled-tips store history (with resolution/actual_winner) instead of pending active tips.
Example request
curl \
  -H "X-API-Key: YOUR_KEY" \
  "https://krokodds.com.au/api/v1/tips?sport_key=aussierules_afl"
Example response
{
  "success": true,
  "data": [
    {
      "id": "aussierules_afl-geelong-carlton-20260906t0740",
      "event_id": "e_afl_20260906_gee_car",
      "sport_key": "aussierules_afl",
      "sport": "AFL",
      "home_team": "Geelong Cats",
      "away_team": "Carlton Blues",
      "commence_time": "2026-09-06T07:40:00.000Z",
      "pick": "Geelong Cats -12.5",
      "pick_side": "home",
      "confidence": 4,
      "confidence_label": "High",
      "consensus_prob_home": 0.71,
      "consensus_prob_away": 0.29,
      "predicted_margin": 18.4,
      "predicted_margin_side": "home",
      "resolution": "pending",
      "actual_winner": null
    }
  ],
  "meta": {
    "count": 1,
    "tier": "free",
    "limit": 50,
    "requested_limit": 50,
    "include_settled": false,
    "timestamp": "2026-09-03T04:00:00.000Z",
    "rate_limit": {
      "limit": 50,
      "remaining": 949,
      "reset": "2026-10-01T00:00:00.000Z"
    }
  }
}
GET/api/v1/tips/accuracyFree tier

Historical hit-rate / track-record for the tips model, overall and broken down by confidence bucket, optionally scoped to one sport.

Reads model_track_record. Per-sport lookup filters on the `sport_key` column (indexed); the unscoped (all-sport) query has no column for `total` (lives in JSONB) so it sorts in memory after fetching up to `scanSize` (min(limit,100)) rows — an all-sports call is NOT a true global ranking beyond that scan window. Same free/api cache tiers as /tips (300s/120s, both above the 60s floor).

Query parameters
NameTypeRequiredDefaultDescription
sport_keystringNo–Filter to one sport. Alias: `sport`. Lowercased.
limitintegerNo50Max rows; capped 50 (free) / 1000 (api).
Example request
curl \
  -H "X-API-Key: YOUR_KEY" \
  "https://krokodds.com.au/api/v1/tips/accuracy?sport_key=aussierules_afl"
Example response
{
  "success": true,
  "data": [
    {
      "sport_key": "rugbyleague_nrl",
      "wins": 142,
      "losses": 88,
      "pushes": 3,
      "total": 233,
      "decided": 230,
      "hit_rate": 0.6174,
      "by_confidence": [
        {
          "confidence": "3",
          "wins": 51,
          "losses": 44,
          "pushes": 1,
          "total": 96,
          "hit_rate": 0.5368
        },
        {
          "confidence": "4",
          "wins": 63,
          "losses": 32,
          "pushes": 1,
          "total": 96,
          "hit_rate": 0.6632
        },
        {
          "confidence": "5",
          "wins": 28,
          "losses": 12,
          "pushes": 1,
          "total": 41,
          "hit_rate": 0.7
        }
      ],
      "last_settled_at": "2026-09-02T22:30:00.000Z",
      "updated_at": "2026-09-02T22:31:00.000Z"
    }
  ],
  "meta": {
    "count": 1,
    "tier": "free",
    "limit": 50,
    "requested_limit": 50,
    "sport_key": "rugbyleague_nrl",
    "timestamp": "2026-09-03T04:00:00.000Z",
    "rate_limit": {
      "limit": 50,
      "remaining": 949,
      "reset": "2026-10-01T00:00:00.000Z"
    }
  }
}

Other categories

Gameday8 endpoints

Per-event head-to-head odds, alternate lines, best prices across books, player props, live state and AI-generated summaries.

Opportunities7 endpoints

Krok's built-in scanners — arbitrage, positive EV, middles, low-holds, player props and same-game multi (SGM) picks, already devigged against a blended sharp baseline.

Racing23 endpoints

The full Australian racing stack — thoroughbred, harness and greyhound. Meetings and runner fields, form, sectionals, ratings, market movers, exchange arbs, tote pools and results.

Odds Feed16 endpoints

Raw per-bookmaker prices as scraped, before any analysis layer. `/scraped-odds/*` paths are aliases of the equivalent `/odds-feed/*` route.

Sports8 endpoints

Sport reference data, team form guides, league standings, injury reports and weather-impact analysis.

Insights1 endpoint

Ranked leaderboards built on top of the stat feeds — per-sport player leaders for a chosen stat, season and view.

Tennis5 endpoints

ATP/WTA rankings, upcoming fixtures, match results, Elo ratings and surface-specific stats.

Historical7 endpoints

Deep archives — player and team game logs, shot charts, AFL/NRL historical data. Paid API plan only.

Reference7 endpoints

Static lookup data for building your own UI — players, venues, headshots, team logos and sport/league metadata.

Other Sports22 endpoints

Cricket, cycling, esports, Formula 1, golf, MMA, boxing, NFL and soccer coverage beyond the AU staples.

Infrastructure15 endpoints

Account and billing endpoints, bulk export, SSE streaming, webhook management and API health.

Additional Data19 endpoints

Odds history, steam-move detection, player prop stats/results, injuries, weather and other supporting feeds.

Prediction Markets3 endpoints

Polymarket and Kalshi sentiment plus a universal prediction-market catalogue and resolutions feed.