# Changelog of Betano Odds API — Live and Pre-Match Odds, 14 Countries (`blackfalcondata/betano-odds-api`) Actor

- **URL**: https://apify.com/blackfalcondata/betano-odds-api/changelog.md
- **Full Actor documentation**: https://apify.com/blackfalcondata/betano-odds-api.md

## Changelog

All notable changes to betano-odds-api are recorded here.

### 0.1.3 - 2026-08-31

- A match that has already kicked off returns the markets the book prices for it on every route, not just `/live`. A running match keeps only a remnant on its pre-match page; measured on the batch sibling, in-play rows enriched from that page carried 33 markets between 34 of them against the 736 the book advertised, one of them none at all, and none of them a score. Those rows now carry the score, the clock, the period and the suspension flag too.
- Every record carries `fetchedAt`, when THAT event's odds were read. `scrapedAt` is when the request started, and a `markets=all` request over many events spans tens of seconds.
- `compareCountries` compares the SAME market across books. Some books lead with an enhanced-odds variant of the match result ("SuperOdds", "MegaCote"); taking each book's first few markets put a promotional price beside a standard one, and 3 of 44 comparisons measured shared no market at all. A book with nothing comparable now returns nothing for that book.
- An outright no longer reports a home and an away side. 11 of 48 outright rows carried one, naming the first two entrants of a field — or, on one race, the two halves of its own title.
- In-play markets carry `qualifier` and `instance`, the fields that tell markets of one type apart: 66 of 804 markets on a single match were otherwise indistinguishable.

### 0.1.2 - 2026-08-31

- `/live?markets=all` returns every market the book prices for a running match, not the two or three its in-play list summarises. Measured on the twelve deepest matches running at the time: 47 markets before, 561 after, against the 569 the book advertises. The lookup behind it had been answering with an empty stub because it stopped reading its query parameters and now reads two headers instead.

### 0.1.1 — 2026-08-31

- Fractional prices are the ones a board prints. 1.67 is 4/6, not 67/100; 2.5 is 6/4, not 3/2. Measured over 14,543 live selections from five country books, 560 of them (3.9%) carried a reduced fraction no bookmaker shows, and six prices just over evens came back empty.
- A live match now reports its SET score. `liveScore` on tennis, table tennis and volleyball is the score of the game being played, so a match standing at 2-1 in sets read "1 / 2". The new `liveSets` and `liveSetsWon` carry the match itself.
- A market, or a whole event, that the book has pulled is flagged `suspended`, so a price that cannot be taken is no longer indistinguishable from one that can. Pre-match rows report `null` there, because those pages publish no such flag at all.
- `/live?markets=all` reads the match page as well as the in-play feed. It used to fetch that page and then discard it whenever the feed answered with nothing, which is what the feed does for almost every running match.
- A finished match still sitting in the in-play list is no longer reported as running.
- A table column that carries only a rendering hint no longer arrives as a market type: 216 selections reported `columnType: "market"`, which is not a Betano market code.
- Flat selection rows carry `participantId`, `teamId` and `playerId`, so a player row can be joined on an id rather than on a name.

### 0.1.0 — 2026-08-28

First version. The standby (always-on HTTP) sibling of `betano-scraper`: the same odds, asked
for one request at a time instead of one batch run at a time.

#### Endpoints

- `GET /health` and `GET /sports` — free. Version, and the 19 sports with their keys and ids.
- `GET /leagues` — the league catalogue of one country book and sport, with the ids `/league`
  takes.
- `GET /coupon` — matches starting in the next 3, 12 or 24 hours. When the book does not
  publish the window asked for, the next larger one it does publish is served.
- `GET /league/{leagueId}` and `GET /league?name=` — one league's remaining fixture list, by id
  or by name resolved against the book's own catalogue.
- `GET /event/{eventId}` — one match. `markets=all` returns every market the book prices
  (measured: 637 markets and 3,882 selections on a Premier League match).
- `GET /live` — every match in play right now, with score, clock and period.
- `GET /search?term=` — Betano's own site search, resolved to full event records.
- `GET /team?url=` and `GET /player?url=` — a team's or player's page, taken as the address the
  caller pasted. A player's page carries their prop markets inline.
- `GET /day-pass` and `POST /day-pass` — status and purchase.

Every priced endpoint takes `country`, `markets`, `odds`, `compare` and `logos`; the fixture-list
endpoints also take `max`, `daysAhead` and `includeLive`.

#### Pricing

- `api-call` $0.002, charged once per successful request to a priced endpoint whatever it
  returns. A request that fails validation, 404s or times out is not charged.
- `day-pass` $3.00, charged once by `POST /day-pass`; for 24 hours no `api-call` is charged,
  across every run of that account.
- `apify-actor-start` $0.0005. Platform usage is billed by Apify at the caller's plan rates.

#### Notes

- The parsing, transport and normalisation layers are vendored byte-identical from
  `betano-scraper`, so both actors emit the same `EventRecord`.
- `changeType` is present on every row and always null: change classification needs state
  between runs, which a single request does not have. Compare `priceHash` instead.
