The docs.
Your key is a private code that unlocks everything on your plan. Each product is a web address you can open in a browser, a spreadsheet or your software.
Your key
Your key arrives by email the minute your payment clears and lives on your account page, where you can swap it for a new one. Send it as &key= on the address, or as a header: Authorization: Bearer bbd_live_.... One key covers every product on your account. Keep it private: it is your licence.
GET https://betbetter.world/data/feed.aspx?b=nfl&f=board.json Authorization: Bearer bbd_live_...
Errors and limits
| Status | Meaning |
|---|---|
401 | No key, or a key we do not know. |
403 | Your plan does not cover this league, sport or product, or the account is on hold. |
404 | Nothing published for that league or week yet. |
429 | Over a limit. Wait (see Retry-After) or use a webhook. |
5xx | Our side; logged. Try again in a minute. |
Feeds: 60 requests a minute per key (240 on every-league plans). Line Moves: 60 a minute. Storylines: per plan, below. Every error body is JSON: {"ok":false,"error":"..."} or {"ok":false,"message":"..."}.
Predictions feed: addresses
One address with two settings: b= the league and f= the file. League codes: nfl, cfb, nba, cbb, wnba, nhl, mlb, afl, nrl, epl, laliga, bundesliga, seriea, ligue1, mls, eflchamp, brasileirao, aleague, worldcup, tennis, ufc, cricket.
| f= | Key | What it is |
|---|---|---|
board.csv · .json · .xlsx | yes | The week's games: our line, total, win chance and fair prices. The newest version unless you ask for one. |
props.csv · .json · .xlsx | yes | Player props: our projection, spread and over / under chance at the main line. |
markets.csv · .json · .xlsx | yes | Team totals, halves, quarters, first five innings, periods, corners, both teams to score, sets: main and alternate lines. |
fantasy.csv · .json · .xlsx | yes | Fantasy points and the stat line (NFL, AFL). |
history.csv · .json | yes | The last row before the start for every game this season. |
versions.json | no | Every version of a week: when it was published and how many games. |
free.csv · props-free.csv | no | Last completed week, final version: the free samples. |
Add &week=w05&version=2 to fetch exactly what existed at that version. Bookmaker prices are not part of the paid feed; the line is kept as the reference.
Board columns (one row per game)
| Column | Meaning |
|---|---|
game_id · kickoff_utc · away · home | Stable game id, start time (UTC) and teams. |
spread_home | Our line for the home side; negative = home favoured. |
total | Our total points (goals, runs). |
win_prob_home · win_prob_draw | Our win chance (soccer adds the draw). |
fair_ml_home · fair_ml_away · fair_spread_price · fair_total_price | Our chances as American prices with no margin. |
market_spread_home · market_total | The market's line at publish time, as the reference. |
h1_spread_home · h1_total · h1_win_prob_home | First-half numbers where we model them. |
sd_margin · sd_total | Our uncertainty, in points. |
published_utc · version · week_key · model_version | When the row was published, its version, its week and the name of the number in it. |
feed_ref | Your licence reference, on every row. |
Player props
| Column | Meaning |
|---|---|
player · team · market · market_label | Who and which stat, with its plain name. |
line | The main line most books quote (yes / no markets use 0.5). |
projection · sd | Our expected value for the stat and our uncertainty. |
prob_over · prob_under · fair_over_price · fair_under_price | Our over / under chance and those chances as prices with no margin. |
game_id · kickoff_utc · published_utc · version · model_version | As on the board file, so props join to games. |
Game markets
One row per market, side and line: market, market_label, period, side, team, line, is_alternate, model_prob, fair_price, projection, plus the game keys and version fields.
Fantasy
One row per player for the coming week or round: fpts, fpts_half_ppr, fpts_ppr, fpts_dk, fpts_fd and the stat line behind them (NFL); AFL Fantasy points in fpts (AFL). Replaced each model run; updated_utc is its time.
Versions
A week opens as version 1 and gets a new version each time the numbers move. Every version is kept. A game's last row before its start is the one in history.csv.
GET https://betbetter.world/data/feed.aspx?b=nfl&f=versions.json
Line Moves: calls
Sport codes: nfl, nba, soccer, mlb, nhl, tennis, or all for every sport on your plan. A sport is billed from its first live call.
GET https://betbetter.world/data/feed.aspx?b=soccer&f=moves.json upcoming calls, newest first GET https://betbetter.world/data/feed.aspx?b=all&f=moves.csv the same as CSV GET https://betbetter.world/data/feed.aspx?b=nfl&f=moves.json&graded=1 calls graded in the last 30 days
Calls arrive within 15 minutes of being made. Add a webhook and every new batch is pushed to you, signed (event moves.calls).
Call fields
| Field | Meaning |
|---|---|
id · sport · league · call_type | The call's id, sport, league code and which kind of call it is. |
game_id · kickoff_utc · home · away · player | The game (same id as the Predictions board) and player for props. |
market · market_label · side · line_now | What the call is about, and the line at the moment of the call. |
call · strength · strength_word | UP or DOWN by the start; HIGH / LEAN / LONG (strong / lean / weak). |
our_number · our_written_utc | Our own number the call rests on (a chance from 0 to 1 for soccer markets, our total for NFL game totals, our projection for player props) and when we wrote it, always before snapshot_utc. Blank when the call rests on the market's own lean. |
predicted_close · expected_move | Where we expect the line or chance to be at the start, and the size of the move in the same unit (points for a line, 0 to 1 for a chance). |
right_when_it_moves · moves_in_100 | For this kind of call at this strength: how often it was right when the line moved, and how often the line moved. |
slow_book · leaders_moved | Slow-book alerts: the book that has not moved yet and how far the leading books moved. |
snapshot_utc · issued_utc · model_version | The time of the price the call reads, when the call was issued, and which call this is. |
close_line · moved · right · graded_utc | After the start (with graded=1): the closing line, whether it moved and whether the call was right. |
Bets feed: the bets
Every bet that fits one of our bet types (the fields call a bet type a pocket), sent before the start. Needs the Bets feed. Nothing is charged until the first live bets are sent.
GET https://betbetter.world/data/feed.aspx?b=all&f=pockets.json open bets, newest first GET https://betbetter.world/data/feed.aspx?b=all&f=pockets.csv the same as CSV GET https://betbetter.world/data/feed.aspx?b=all&f=pockets.json&graded=1 bets graded in the last 30 days
Add a webhook and every new batch is pushed to you, signed (event pockets.bets).
Bet fields
| Field | Meaning |
|---|---|
id · sport · league · board | The bet's id (stable), sport, league and board code. |
game_id · kickoff_utc · home · away | The game (same id as the Predictions board) and its start time. |
market · player · side · line | What to bet: the market, the player for props, the side (Over / Under / a team) and the line. |
our_chance · confidence | Our chance the bet wins (0 to 1, our own number) and the word for it: HIGH, LEAN or LONG-SHOT. |
bet_at_or_above_decimal · bet_at_or_above_american | The lowest price worth taking, worked out from our chance and the bet type's rule. Below it, skip the bet. Never a bookmaker's price. Blank on bet types that say only which side to take. |
stake_units | The stake the rule bets, in units. Scale it to your own bank. |
pocket_code · pocket · pocket_stage | Which bet type the bet comes from: a short code, the bet type in plain words, and its stage. |
status · issued_utc | open or void, and when the bet was sent. |
result · units_result · graded_utc | After the game (with graded=1): won / lost / push / void and the units won or lost at the stake. |
Storylines API
One address, https://betbetter.world/data/story.ashx, with op=. Writes and facts only for competitions on sale (op=sale).
| Call | What it does |
|---|---|
GET ?op=usage | Your plan, credits used and left this month and today, facts API calls today. |
GET ?op=sale | Competitions on sale now (no key needed). |
GET ?op=slate&sport=nfl&date=2026-10-12 | Games and subjects for a day. |
GET ?op=points&sport=&kind=team&entity= | The facts for a player, team or match-up (kind=matchup&home=&away=); depth=pills|paragraph|table|page. Pro and Publisher. |
GET ?op=jobs | Your recent pieces. |
GET ?op=voices | The ready-made voices and your saved ones. |
POST ?op=write | Write a piece (JSON body below). |
POST ?op=voice_save · ?op=voice_delete | Save or delete a voice. |
Writing a piece
POST https://betbetter.world/data/story.ashx?op=write
Authorization: Bearer bbd_live_...
Content-Type: application/json
{ "sport": "nfl", "kind": "matchup", "home": "Los Angeles Rams", "away": "Buffalo Bills",
"format": "x_thread", "voice": "writer", "language": "English",
"note": "Lead with Buffalo.", "closing_line": "Full preview on our site.", "rg": "US" }
Soccer: send team= with a player so we can check the competition is on sale. voice is a ready-made voice key, a saved voice key (v12) or an object with name, description, spelling, emoji. Your closing line and the responsible gambling line (AU, US, UK) are added after the piece exactly as written.
| format | Credits |
|---|---|
x_post · caption · push · fact_sheet | 1 |
x_thread · video_script · podcast_script · newsletter · match_preview · email · podcast_rundown · youtube_video | 5 |
The reply: {"ok":true,"status":"ok","text":"...","credits_charged":5,"credits_left_this_month":895}. Every number in the text is checked against the facts; a piece that fails after one rewrite comes back "status":"held" and costs nothing.
Plan limits
| Plan | Credits a month | A day | Requests a minute | Facts API calls a day | Saved voices |
|---|---|---|---|---|---|
| Creator | 200 | 10 | 20 | none | 3 |
| Pro | 900 | 45 | 30 | 2,000 | 10 |
| Publisher | 3,500 | 175 | 120 | 20,000 | unlimited |
Credits reset on the 1st (UTC); daily caps at 00:00 UTC. No overage is ever billed.
Webhooks
A webhook means we send new data to your system the moment it is ready. Save an address on your account page. We POST JSON to it, signed: X-BB-Timestamp and X-BB-Signature = HMAC-SHA256 of timestamp + "." + body with your webhook secret. Check the signature and reject anything older than five minutes.
| event | When |
|---|---|
board.version | A league publishes a new version (Predictions feed). |
moves.calls | New Line Moves calls (a batch, every few minutes while calls are made). A failed delivery is retried on the next run. |
pockets.bets | New Bets feed bets (a batch, every few minutes while bets are sent). A failed delivery is retried on the next run. |
test | The "Send a test" button on your account page. |
Google Sheets and Excel
Sheets: in any cell, =IMPORTDATA("https://betbetter.world/data/feed.aspx?b=nfl&f=board.csv&key=..."). Excel: Data, From Web, paste the same address, Load, and set it to refresh every hour.
Help
Email data@betbetter.world; a person replies within one business day. Terms: one page. Live status: status page.