Skip to content
Product Documentation

CLI

Install the CLI with uv tool install betflux for automatic updates on Linux and macOS; see the installation guide. pip install betflux also installs the CLI, without automatic updates. Run betflux login to save a key for the CLI and Python SDK, or supply BETFLUX_API_KEY. --api-key overrides the environment; --base-url overrides the API host.

On verified Linux and macOS uv tool install betflux installations, BetFlux checks for updates before data commands about once per day and installs an eligible stable release automatically. This may occasionally delay command startup. The updater does not mutate project or pip installations, temporary uvx runs, or installations it cannot verify. Use uv to install and own the CLI environment. It preserves the installation’s version constraints and package source; uv may also change dependency versions within those constraints. Pinned installations update only when a compatible release is available. uv upgrades are not atomic and do not roll back automatically. If an upgrade leaves the tool unusable, repair it with uv tool upgrade betflux --reinstall.

Set BETFLUX_NO_AUTO_UPDATE=1 to disable automatic updates for one process, including in CI or scripts. Persistent preference and manual update commands are available:

Terminal window
betflux auto-update status
betflux auto-update off
betflux auto-update on
betflux update # check and install now, even if auto-update is off
betflux update --check # check only

These controls, --help, and --version do not trigger an automatic network check. Automatic update progress is written to stderr; an unsuccessful automatic check lets the requested command continue. Explicit update failures return a nonzero status. Coordination applies to BetFlux launches in the same verified tool installation; external package-manager operations and older pre-updater processes are outside that coordination.

Only the CLI launcher performs these checks. Importing betflux or using the Python SDK never triggers an update.

Complete onboarding and activate API access on the website first, then run:

Terminal window
betflux login
  1. The CLI opens your browser. If it doesn’t open automatically, navigate to the URL printed in your terminal.
  2. Sign in to your BetFlux account if prompted.
  3. The link fills in the code automatically, including after signing in. Confirm it matches your terminal and select Approve access. If you open the activation page without the link, enter the code manually.
  4. When the website shows App access approved, return to your terminal. Wait for Signed in. API key saved. CLI commands and Python clients will now automatically use it, unless you supply another key explicitly.

Verify your connection:

Terminal window
betflux keys check

Codes expire after ten minutes. If a code is invalid, expired, or already used, run betflux login again to get a new one. Each login uses an account API key slot; you don’t need to log in before every command.

The key is saved in your system keychain. On a headless machine, explicitly choose protected file storage with --credential-store file; add --no-browser to print the link without launching a browser. The key uses the CLI’s default name; use --name when starting login to choose a different name.

CLI credential priority is --api-key, BETFLUX_API_KEY, --api-key-file, then saved login. Saved keys are isolated by API URL. Custom API URLs require an explicit website origin through login --auth-url or BETFLUX_AUTH_URL.

Terminal window
betflux logout # revoke the saved key and remove local login
betflux logout --local-only # remove local login without server revocation

Logout operates only on the saved key. It retains the credential if revocation cannot be confirmed, so you can retry. Revoked keys can remain cached at the API edge for up to five minutes.

If saved login is unreadable, unlock your keychain and retry. To reset broken metadata or switch away from an unavailable keychain, run betflux logout --local-only, then betflux login --credential-store file. For a custom API, pass the same --base-url before both commands and provide --auth-url for login. Local-only logout does not revoke the server key; revoke it from your account keys separately. If the CLI warns that a keychain entry may remain, remove it when the keychain is accessible.

Terminal window
betflux keys check # plan, limits and the period's games via GET /v1/me
betflux usage # the same standing; `betflux usage games` lists the counted games
betflux datasets
betflux leagues
betflux teams --league NBA
betflux players --league NBA --team-id <team-uuid>
betflux games --league NBA --date-from 2026-05-01 --date-to 2026-05-07 --cost
betflux games --id NBA_ORL_DET_20260503 --format record
betflux get closing-lines --league NBA --date-from 2026-05-01 --date-to 2026-05-07 --dry-run
betflux get closing-lines --league NBA --date-from 2026-05-01 --date-to 2026-05-07
betflux get market-results --game MLB_BOS_NYY_20260715 --outcome WON
betflux get sportsbook-lines --game MLB_BOS_NYY_20260715 --output lines.parquet
betflux get game-state-timeline --game NBA_ORL_DET_20260503

betflux get <dataset> queries one of the four datasets. The payloads are per-game Parquet files; the CLI downloads them and evaluates filters and rendering locally.

Dataset Addressing
closing-lines, market-results Date range (--league --date-from --date-to) or --game
game-state-timeline, sportsbook-lines --game only

sportsbook-lines is --game-only by policy, not shape: one game’s file is the full change-only line history and runs to tens of megabytes, so a range pull would download that for every game in the window. The CLI says so if you try. Cost is per game, the same for every dataset: once a game is counted, all of its datasets are free for the rest of the period.

Option Meaning
--league, --date-from, --date-to Range query (ET game_date, inclusive); the CLI discovers games via /v1/games, previews what they would cost, and fetches each game’s file
--game <id> One game by id
--dry-run Range queries: print the preview — how many games are new, already counted, exempt, outside the free sample or invalid, and whether they fit — and stop without downloading (JSON with --format json)
--allow-partial Range queries: when the pull would exceed the allowance, read the games that fit instead of aborting
--quiet Silence the games usage line printed to stderr after a read
--operator, --market-type, --team, --player-id, --side Local filters — applied after download, so they don’t change what a game costs
--outcome market-results only: WON, LOST, PUSH, INDETERMINATE
--limit N Range queries: stop after N rows — no further game files are fetched, so no further games are counted
--output PATH With --game: save the raw Parquet file instead of rendering rows
--no-progress Suppress the progress display (also BETFLUX_NO_PROGRESS=1)

A date-range get previews its cost first and aborts before downloading anything when the pull would go over the allowance, naming how many games are over and how many fit. After get, live-board and live-tail, one stderr line reports what the read cost and what is left, in the form games: N new, M already counted · X of Y left · resets YYYY-MM-DD (--quiet silences it).

--player-id matches either player-ID list on closing-lines, market-results, and sportsbook-lines. Rows that match both lists are returned once.

A filter the dataset has no column for is rejected up front, and flag combinations the request would ignore (e.g. --output with filters) are errors rather than silent no-ops.

While a get runs interactively, progress renders to stderr: game discovery, a per-game bar for range pulls, per-file byte progress, and any retry waits (rate limits, transient server errors). stdout carries only the result, so piping or redirecting jsonl/csv output stays byte-clean; when stderr is not a terminal the display turns off automatically.

Terminal window
$ betflux get sportsbook-lines --game MLB_BOS_NYY_20260715 --output lines.parquet
wrote lines.parquet — sportsbook-lines for MLB_BOS_NYY_20260715: <rows> rows, <bytes> bytes

The bytes are written untouched — the same artifact curl would save — so the file is immediately queryable with DuckDB, pyarrow, pandas, or polars.

Rendering is entirely client-side. The default is a compact table showing a curated column subset (the datasets are wide). Reshape it:

Flag Effect
--wide Table with every column
--columns game_date,operator,side,closing_odds Pick exact columns
--format record Vertical key: value blocks — ideal for one wide row
--format json|jsonl|csv Machine formats, always full-fidelity

Table and record views are display projections only; json, jsonl, and csv always carry every column. With --format jsonl|csv on a range query, rows stream as each game’s file arrives instead of waiting for the whole window. Timestamps render as ISO 8601 in every format.

Terminal window
betflux get closing-lines --game NBA_ORL_DET_20260503 --format jsonl > lines.jsonl

Reference data: games, leagues, teams, players

Section titled “Reference data: games, leagues, teams, players”

The JSON reference data that the datasets key on. All four render through the same --format / --columns controls as get; json, jsonl, and csv always carry every field.

Terminal window
betflux games --league NBA --date-from 2026-05-01 --date-to 2026-05-07
betflux games --league NFL --status STARTED --columns id,away_score,home_score,current_period
betflux games --id NBA_ORL_DET_20260503 --format record
Command Options
betflux games --league, --date-from / --date-to (ET game date, inclusive, paired), --team (canonical name, home or away), --status; or --id <game_id> alone. --wide shows every column; --cost adds a free_to_read column (true for a game already counted or exempt this period) at the price of one preview call
betflux leagues none
betflux teams --league
betflux players --league and/or --team-id <team-uuid>

A game row is the full record — schedule, teams, score, venue, weather. The default table is a curated subset (id, date, start, status, teams, score, venue, weather type); --wide, --columns, or --format record show the rest.

betflux keys check validates the key against GET /v1/me and prints your standing — the plan, the period’s games (used, allowance, left, reset) and the plan’s limits (recent-game window, live, league datasets) — and it works even when the allowance is spent. Every number comes from the key at runtime; --json prints the raw /v1/me body for scripts and agents to parse.

Terminal window
betflux usage # the same standing
betflux usage games # games counted or exempt this period, newest read first
betflux usage games --league NFL --from 2026-09-01 --to 2026-09-30 --json

Every game usage games lists is free to read again, in any dataset, until the period resets, and listing them counts nothing. See Rate limits & quotas for the counting rules.