# Football odds data, explained

> How football odds data is keyed, which markets it carries (h2h, totals, correct score) and how a matched feed sets each back price beside an exchange lay.

Published 1 July 2026 · updated 5 November 2026

**Football odds data is every bookmaker's price for every outcome of a fixture, filed under a sport key, a market key and an outcome name.** In the OddsRelay feed, football sits under `soccer_*` sport keys, and the matched boards set each back price beside the exchange lay for the same outcome.

## What are the main football betting markets?

The main football betting markets are the match result, over/under goals, both teams to score and correct score. A single fixture carries dozens of markets, and they differ in shape. Some have two outcomes, some three, some one per scoreline. The common ones:

- **Match result** (`h2h`): three outcomes, the home side, `Draw` and the away side.
- **Over/under goals** (`totals`): an over and an under on a line, with the line itself in the outcome's `point` field. One venue often prices several lines on the same fixture, so the line is part of the outcome's identity.
- **Both teams to score**: two outcomes, yes and no.
- **Correct score** (`correct_score`): one outcome per scoreline, so it is the widest of the common markets.
- **The long tail**: draw no bet, double chance, half-time/full-time and the [Asian handicap](https://oddsrelay.io/glossary/asian-handicap-term) lines.

Don't hardcode that list. Every row of `GET /v2/sports` carries `markets`, the market keys seen under that competition on the matched boards, and the `markets` filter takes the same keys. Name a key the catalogue doesn't know and the reply is a free `400 unknown_market` with the valid keys listed.

## Every competition has a competition key

Each football event carries two keys: `sport_key` and `competition_key`. `sport_key` starts `soccer_` and follows the league name its venues give it, with the readable name in `sport_title`. Venues name leagues their own way, so one competition's matches can carry different `sport_key` values. `competition_key` names the competition itself, also under `soccer_`: one key per competition, the same on every live board and never changed once served. On the live boards it is `null` only when no venue's league name identifies one competition. Past boards in historical odds always carry it as `null`.

The `sports` filter takes either key, or a prefix: `sports=soccer` asks for every football competition on the board, and an event's `competition_key` returns its whole competition. `GET /v2/sports` lists both. The [matched-board filters guide](https://oddsrelay.io/docs/guides/matched-board-filters) covers the rest of the grammar.

One place uses the prefix instead of the full key. `meta.last_seen`, the time each venue's prices were last read, is keyed by the sport's key base, so every football competition shares the `soccer` entry. The [freshness guide](https://oddsrelay.io/docs/guides/freshness) shows the lookup.

## Where football sits on the boards

| Product | What it carries for football |
| --- | --- |
| `standard` | Bookmaker back prices beside exchange lay prices, market by market. |
| `2up` | Each bookmaker's own [2Up](https://oddsrelay.io/glossary/2up) price on the match result, paired to the exchange lay for the same team. |
| `dutching` | Back prices only, one leg per outcome at different venues, grouped by `dutch_id`. |
| `raw` | Each venue's markets and outcomes as that venue labels them, with a `last_update` per market. |

All six matched boards and raw are on every plan, so one key reads every board in the table above. On a self-serve plan the same key reads [historical odds](https://oddsrelay.io/products/historical-odds) too: the bookmakers' and exchanges' past football prices, and the bookmakers' closing lines, since 17 October 2026. The [2Up board](https://oddsrelay.io/products/2up-feed) is the one built for football alone: its back side is the bookmaker's 2Up price, which can differ from the same bookmaker's ordinary match odds. The [dutching walkthrough](https://oddsrelay.io/blog/dutching-data-explained) covers that board.

## What a matched football row looks like

Here is one Premier League fixture on the standard board, asked for with `sports=soccer&markets=h2h` and trimmed to the match result, with `sport_key`, `sport_title` and `competition_key` left out (`GET /v2/sports` lists the keys):

GET /v2/odds/standard (trimmed) · example:

```json
{
  "meta": {
    "feed_type": "standard",
    "region": "uk",
    "odds_format": "decimal",
    "processed_at": "2026-09-20T12:20:57.271Z",
    "last_seen": {
      "bet365": { "soccer": "2026-09-20T12:20:51Z" },
      "william_hill": { "soccer": "2026-09-20T12:20:55Z" },
      "matchbook": { "soccer": "2026-09-20T12:20:56Z" },
      "smarkets": { "soccer": "2026-09-20T12:20:54Z" }
    },
    "count": 1,
    "version": "v2",
    "next_cursor": null
  },
  "data": [{
    "event_id": "or_evt_917dd44bce05",
    "commence_time": "2026-09-20T14:00:00Z",
    "home_team": "Arsenal",
    "away_team": "Chelsea",
    "markets": [{
      "key": "h2h",
      "outcomes": [
        {
          "name": "Arsenal",
          "back": [
            { "bookmaker": "bet365", "price": 2.9, "link": null },
            { "bookmaker": "william_hill", "price": 2.8, "link": null }
          ],
          "lay": [
            { "exchange": "matchbook", "price": 3.0, "available": 175, "link": null }
          ]
        },
        {
          "name": "Draw",
          "back": [{ "bookmaker": "william_hill", "price": 3.5, "link": null }],
          "lay": [{ "exchange": "smarkets", "price": 3.6, "available": 42, "link": null }]
        }
      ]
    }]
  }]
}
```

Each outcome carries `back` offers, best price first, and `lay` offers, lowest first. A lay offer's `available` is the money on offer at that price. No offer is timestamped on its own, so read its age from the envelope: now minus the venue's `meta.last_seen` entry is an upper bound on it, and `processed_at` is the board's time.

A back price reaches the board only when an exchange lay beside it has money behind it. The [oddsmatcher widget](https://oddsrelay.io/widgets/oddsmatcher) works out the rating and the qualifying loss on screen. In your own code it takes a few lines, at your own commission rate:

Your arithmetic on the Arsenal pair above · example:

```js
const back = 2.9, lay = 3.0, commission = 0.02, stake = 10;

const layStake = (back * stake) / (lay - commission);          // 9.73
const ifBackWins = stake * (back - 1) - layStake * (lay - 1);  // -0.46
const ifLayWins = layStake * (1 - commission) - stake;         // -0.46, the qualifying loss
const rating = (back / lay) * 100;                             // 96.7
```

The [ratings explainer](https://oddsrelay.io/blog/qualifying-loss-and-ratings-explained) walks the formulas, including free-bet stakes.

## Pairing is the hard part of football data

Prices are only half of a football feed. The other half is deciding that two venues are quoting the same fixture and the same outcome, when bookmakers spell teams their own way. One venue lists a club by its short name, another by its full name, and a third adds a suffix, on every fixture of every round. A football feed for matched betting should do that reconciliation once, for everyone, because every customer who does it alone rebuilds the same alias tables.

On the matched boards one fixture is one event with one `event_id` on every route. Treat that id as opaque. It never changes once served, so you can store it as the fixture's key. Raw keeps each venue's own outcome labels, which is the right trade when you want to run the matching yourself. [What an odds API returns](https://oddsrelay.io/blog/what-is-an-odds-api) sets raw and matched side by side. The lay side matters as much as the pairing, since a lay with little money behind it cannot hedge a real stake. [Why lay liquidity matters](https://oddsrelay.io/blog/why-lay-liquidity-matters) covers that part.

## Which football the feed covers

The feed serves one region, the UK & Ireland: 140+ bookmakers, 60+ of them live in the UK & Ireland, bet365 included, with the lay side from Betfair, Smarkets and Matchbook. `GET /v2/sports` lists every football competition on the boards now, and keyless `GET /v2/coverage` gives the live status per product, venue and sport.

The prices are pre-match unless you ask for in-play ones. Since 2 November 2026, `inPlay=only` on the standard and dutching boards, or `include` and `only` on raw, returns football in play, each event marked `in_play`, with no scores or match clock. Fewer bookmakers price football in play than before kick-off, and neither bet365 nor William Hill has in-play prices on the feed. [Live vs pre-match odds data](https://oddsrelay.io/blog/live-vs-pre-match-odds-data) sets out the difference.

## Price one competition first

Pick one competition key and one market, and add `quote=true` to the standard board call to see its token price before you spend any. The [quickstart](https://oddsrelay.io/docs/guides/quickstart) walks that call, and [the coverage page](https://oddsrelay.io/coverage) lists the bookmakers and sports the feed covers.

18+ · OddsRelay supplies odds data only and takes no bets. Please gamble responsibly.

Source: https://oddsrelay.io/blog/football-odds-data-explained
