Skip to content

BlogMatched betting data

The data behind each-way and extra-place matched betting

OddsRelay · · Updated · 4 min read

Matching an each-way offer takes the bookmaker's place terms and two exchange lays, one on the win market and one on a place market. That is more than a single back/lay pair can hold, so each-way and extra-place have boards of their own.

An each-way bet is two bets

A standard qualifying bet is one back price against one exchange lay price. An each-way bet is staked as two equal halves. The win half pays only if the selection wins. The place half pays if it finishes in one of the paying places, at a fraction of the win odds. So each half needs its own lay: the win half on the exchange win market, the place half on an exchange place market, which pays its own number of places.

The piece a standard board never carries is the place terms: how many places pay and the fraction of the odds the place half gets. A race might pay three places at a fifth of the odds, or four at a quarter. Those two values set the place odds, and without them there is no way to size the place lay.

What is an extra-place offer?

An extra-place offer is a bookmaker paying more places on a race than the exchange place market does: five places where the place market pays four, say. The finishing positions in between are the extra places. If the horse finishes in one, the bookmaker's place half wins and the place lay wins too, because the exchange market did not pay that position. Any other finish settles like an ordinary each-way qualifier.

So an extra-place row needs two places counts for the same runner: the bookmaker's and the place market's. Bookmakers set each-way terms race by race, so both have to arrive with the prices.

Read the terms from the row, every time

A tool that hardcodes "three places at a fifth" gets the place odds wrong the moment a bookmaker changes its terms, and never sees an extra place at all. Take places and the fraction from each offer.

What does an each-way row look like?

Racing events carry a venue instead of teams. Each back offer adds the bookmaker's terms, and lay becomes an object with a win list and a place list. Here is one runner from the each-way board, trimmed to one offer per list:

GET /v2/odds/each-way · example, trimmed

{
  "meta": {
    "region": "uk",
    "odds_format": "decimal",
    "processed_at": "2026-09-17T11:42:10.512Z",
    "last_seen": { "betfred": { "horse_racing": "2026-09-17T11:42:04Z" } },
    "count": 1,
    "version": "v2",
    "next_cursor": null
  },
  "data": [{
    "event_id": "or_evt_c7ced4ea628e",
    "sport_key": "horse_racing",
    "sport_title": "Horse Racing",
    "commence_time": "2026-09-17T13:00:00Z",
    "venue": "Ayr",
    "markets": [{
      "key": "each_way",
      "outcomes": [{
        "name": "Oriental Prince",
        "back": [
          { "bookmaker": "betfred", "price": 4.0, "places": 4, "place_fraction": 0.2, "link": null }
        ],
        "lay": {
          "win":   [{ "exchange": "smarkets", "price": 4.3, "available": 38.74, "link": null }],
          "place": [{ "exchange": "betfair_exchange", "price": 2.18, "available": 17.94, "places": 4, "link": null }]
        }
      }]
    }]
  }]
}

back[].places is how many positions the bookmaker pays, and back[].place_fraction is its terms as a decimal, so 0.2 is 1/5. lay.win and lay.place each list exchange offers lowest price first, with available, the money on offer at that price. The two can sit on different exchanges. lay.place[].places is the places that exchange market pays. Where back[].places is higher, the row is an extra-place opportunity.

There is no rating in the row. The boards are paired against exchange lay and liquidity-gated. The rating and qualifying loss are simple arithmetic on the pair at your own commission rate, and the oddsmatcher widget shows them. For each-way the arithmetic starts from the place odds:

Working the row · example, your code

const outcome = event.markets[0].outcomes[0];
const back = outcome.back[0];
const winLay = outcome.lay.win[0];
const placeLay = outcome.lay.place[0];

// Place odds from the bookmaker's terms: 4.0 at 1/5 gives 1.6
const placeOdds = 1 + (back.price - 1) * back.place_fraction;

// Above zero: the bookmaker pays places the exchange place market does not
const extraPlaces = back.places - placeLay.places;

From there, each half is sized like a standard lay: the win half against winLay.price, the place half against placeLay.price with placeOdds as its back price. The each-way calculator and the extra-place calculator take one row's terms and both lay prices and show the result on every finish.

Each-way and extra-place share a shape

The extra-place board has the each-way shape, cut to the runners where back[].places is higher than lay.place[].places. Code written for one reads the other. Both are among the six matched boards on every plan, with the lay side drawn from Betfair, Smarkets, Matchbook and BETDAQ. The each-way feed and extra-place feed pages each show a recorded reply from the live feed.

Check a row's age before you act

An extra place is worth something only while the bookmaker still offers those terms, so the age of a row matters. Matched offers carry no timestamp of their own. meta.processed_at is when the board was built, and meta.last_seen gives each venue's last read per sport, here horse_racing. Now minus last_seen is an upper bound on how old that bookmaker's price is. The freshness guide covers both fields.

Call both boards

The API reference documents the full each-way response, place terms and the split lay included. See live coverage for which bookmakers and exchanges are live for racing, or request access to call both boards on your own key.