Every season (39: 1991/1992 to 2029/2030) with its opaque id and the sdv END year.
Endpoint: GET https://api.kzs.si/api/v1/public/seasons/
Value
A hoopR_data tibble: Every season (39: 1991/1992 to 2029/2030) with its opaque id and the sdv END year. An empty
valid answer raises hoopR_no_data; the columns are always these, in this order (sportsdataverse-py kzs_seasons):
| col_name | type | description |
| season_id | integer | Season id: OPAQUE, not a year (1 = 2000/2001 ... 27 = 2026/2027, 31 = 1991/1992). The season name is 'START/END'; the sdv season is the END year (the second half of name). |
| name | character | Season, 'START/END' (2025/2026); the sdv season is the END year. |
| is_active | logical | True for the current season only (2026/2027 on 2026-10-12). |
| active | logical | Same as isActive. |
| season | integer | Season END year (2026/2027 = 2027), from the row's own season name or id, else from the request. |
Details
Unofficial and unsupported: these wrappers read the public read API (Java/Spring, built by OnixWeb) that the kzs.si site itself calls. No terms of use were located (unverified), api.kzs.si/robots.txt answers 401 and www.kzs.si/robots.txt 404, so no policy or Crawl-delay is published. The runtime waits at least 1 s before every request, retries included.
Personal data: the API serves officials' and coaches' emails, phones and home towns, and clubs' bank accounts and addresses, publicly. The parsers never output them (officials appear by name only; club addresses, personnel and the commissioner report are dropped). Do not add them back.
Seasons are END years (2027 = 2026/2027); KZS' own season ids are opaque (27 = 2026/2027) and the runtime maps them. Competition ids are per season. Three team keys are never interchangeable: the match-team id (per match and side), team_id (one club team in one season) and club_id (across seasons). player_id is the registry id, person_id the person behind it.
Errors are HTTP 400 for everything (an unknown id and a bad parameter alike), so the runtime raises
hoopR_asset_fetchfor it, neverhoopR_bad_requestor an empty frame. List routes default to 150 rows with no truncation signal: every list wrapper asks for a large limit and refuses a full page. The play-by-play and box-score wrappers, the leaderboards, teams, rounds and playing days each make one extra, cached request (the match header or the competition) to prove the answer is the one asked for and the game is final.Coverage: scores from 2007/08; box scores and play-by-play from 2015/16. Some 2020/21 men's games have a box score but no play-by-play (
hoopR_no_data): the Genius data.json (genius_match_id in kzs_matches) is the fallback. Shot x/y are Genius court percent; side (LEFT/RIGHT) names the basket end and teams switch ends at half time, so normalise with side before stacking shots. Advanced box-score fields are 0 in every observed game.Errors are classed conditions, all inheriting
hoopR_error:hoopR_no_data(an empty answer or list, a competition without standings, a final game with no play-by-play or box score, HTTP 404),hoopR_asset_fetch(HTTP 400, the API's only error status for an unknown id and a bad parameter alike; any other non-2xx; a non-JSON or empty body; an envelope whose status is not OK; a full list page; a game that is not final; a body for another competition, match, team, player or season than the one asked for) andhoopR_bad_request(a bad argument, before any request). HTTP 500 is retried. Wrappers raise; they never return an empty frame for a failed fetch.
See also
Other KZS Functions:
kzs_box_score(),
kzs_competition(),
kzs_competitions(),
kzs_match(),
kzs_matches(),
kzs_pbp(),
kzs_pbp_players(),
kzs_period_scores(),
kzs_phases(),
kzs_player(),
kzs_player_leaderboard(),
kzs_player_stats(),
kzs_playing_days(),
kzs_roster(),
kzs_rounds(),
kzs_score_changes(),
kzs_standings(),
kzs_team(),
kzs_team_box_score(),
kzs_team_general(),
kzs_team_leaderboard(),
kzs_teams()
Examples
# \donttest{
try(kzs_seasons())
#> ── KZS Seasons from api.kzs.si ────────────────────────────────── hoopR 3.2.0 ──
#> ℹ Data updated: 2026-10-31 21:31:24 UTC
#> # A tibble: 39 × 5
#> season_id name is_active active season
#> <int> <chr> <lgl> <lgl> <int>
#> 1 1 2000/2001 FALSE FALSE 2001
#> 2 2 2001/2002 FALSE FALSE 2002
#> 3 3 2002/2003 FALSE FALSE 2003
#> 4 4 2003/2004 FALSE FALSE 2004
#> 5 5 2004/2005 FALSE FALSE 2005
#> 6 6 2005/2006 FALSE FALSE 2006
#> 7 7 2006/2007 FALSE FALSE 2007
#> 8 8 2007/2008 FALSE FALSE 2008
#> 9 9 2008/2009 FALSE FALSE 2009
#> 10 10 2009/2010 FALSE FALSE 2010
#> # ℹ 29 more rows
# }
