Documentation / Guides

Live odds

Best Betfair back and lay prices, when they arrive, how often they update, and what the numbers do and do not mean.

Every runner can carry a betfair block: the best available back and lay price from the Betfair exchange, captured in the minutes before the race goes off.

"betfair": {
  "selection_id": 84512233,
  "back_price":   3.55,
  "lay_price":    3.60,
  "last_update":  "2026-09-02T08:44:56Z"
}

back_price is the best price you could have backed at; lay_price is the best price you could have laid at. Both are decimal odds, and both are taken from the top of the order book at the moment of capture.

When prices arrive

Capture starts about three minutes before the scheduled off and refreshes every few seconds until shortly before the traps open. Before that window a race has no prices at all — the exchange market exists, but there is rarely enough money in it for a price to mean anything.

The practical consequence: betfair is null on a race that is more than a few minutes away, and populated on one that has just run. If you are polling a card in the morning, expect nulls; poll again near the off.

How current they are

last_update is the moment that price was read from the exchange, not the moment you called the API. Trust it over your own clock — it is the only honest measure of how stale a number is:

# how old is this price, in seconds?
curl -s -H "X-API-Key: $KEY" \
  https://api.greyhoundapi.com/v1/races/1541377233/market \
  | jq '.data.runners[] | {dog: .dog_name, back: .betfair.back_price,
      age_s: (now - (.betfair.last_update | fromdate))}'

Prices reach this API within a second or two of being read, so a few seconds of age is normal and expected. A price several minutes old means the race has already run — that is the final capture before the off, which is usually the number people want.

The last price before the off

Once a race has run, back_price and lay_price hold the last values captured, typically a handful of seconds before the traps opened. That makes them a useful companion to the official starting price in sp: one is the bookmaker return, the other is what the exchange was actually paying at the same moment. They frequently disagree, and the difference is the interesting part.

What these numbers are not

  • Not a full order book. You get the best price on each side, not the depth behind it, and not the size available at that price.
  • Not a price history. Each capture overwrites the last, so you get the most recent price, not how it moved. If you need drift, poll and store your own series.
  • Not a prediction. A short price reflects what other people are willing to bet, nothing more. This API reports market data; it does not rate runners, forecast results or suggest bets.
  • Not guaranteed present. Coverage depends on a market existing and having prices during the capture window. Withdrawn runners carry no price at all.

Where to find them

The betfair block appears wherever a runner does — race cards, results, and career form — so historical prices come back with the run they belong to. For a single race, GET /v1/races/{race_id}/market returns every runner\'s prices together with the exchange market id.

Always test for presence rather than assuming:

const bf = runner.betfair;
if (bf?.back_price) {
  // a real price, captured at bf.last_update
} else {
  // no market, outside the capture window, or a withdrawn runner
}