---
title: Weight of Money API
description: How much money is actually matched on each football selection — volume, share of the book, and how both moved over time.
badge: addon
---

# Weight of Money API

Odds tell you the price a book is willing to offer. This API tells you something
different: how much money is actually sitting on each selection, and what share
of the market that is.

Every football fixture we cover returns its markets broken down by selection,
each with the money matched on it, its share of that market's total, the price
attached to it, and the previous price. Captures are stored as a series, so you
can also ask how the split got to where it is.

Base URL: `https://sports.bzzoiro.com/wom/api/`

In-play fixtures are refreshed **every 15 seconds** and prematch fixtures
**every 60 seconds** — the cadence the numbers actually move at source. The
long-tail markets (corners, cards, correct score) refresh hourly.

Football only today. Other sports will land on the same routes with a `sport`
parameter; existing responses will not change shape when they do.

## Access

Authentication is the standard BSD token from
[your dashboard](/dashboard/) — the same one the football, odds and WebSocket
products use. Send it on every request:

```bash
Authorization: Token YOUR_API_KEY
```

Access requires an active **Weight of Money** subscription — **$20/month**.
Accounts holding the **Founder badge** (granted once to every account that
existed before 2026-08-03) pay **$10/month** instead, and keep that price for as
long as the subscription stays active. The badge cannot be earned by
subscribing. This addon is separate from the Sports Addon and from the Odds API. Without a token you get **401**;
with a valid token but no subscription you get **402**:

```json
{"error": "active Weight of Money subscription required",
 "subscribe_url": "/wom/pricing/"}
```

`GET /wom/api/coverage/` is the exception: any authenticated token may call it,
so you can size the dataset before paying for it.

Subscribe at [/wom/](/wom/) or [/addons/](/addons/). Card subscriptions renew
automatically; PayPal and crypto are one-time payments that stack months onto
your expiry instead — pay a multiple of your monthly price to buy several at
once.

## Event identifiers

Every row is keyed to a **BSD event id** — the same id used by
`/api/v2/events/{id}/`, the odds API's `bsd_id` and the live WebSocket. There is
no second identifier space and no mapping table to maintain.

A fixture appears in this API only once it resolves to a BSD event. See
[Coverage and limits](#coverage-and-limits).

## Market codes

Markets follow the same code format as the odds API: `KIND[_LINE]_SELECTION_PERIOD`.

| Code | Meaning |
|---|---|
| `1X2_HOME_FT` | Home win, full time |
| `1X2_DRAW_FT` | Draw, full time |
| `1X2_AWAY_FT` | Away win, full time |
| `1X2_HOME_1H` | Home win, first half |
| `OU_2.5_OVER_FT` | Over 2.5 goals, full time |
| `OU_1.5_UNDER_1H` | Under 1.5 first-half goals |
| `BTTS_YES_FT` | Both teams to score |
| `DNB_HOME_FT` | Draw no bet, home |
| `CORNERS_10.5_OVER_FT` | Over 10.5 corners |
| `CARDS_3.5_UNDER_FT` | Under 3.5 cards |
| `CS_2-1_FT` | Correct score 2-1 |
| `HTFT_HOME-AWAY_FT` | Home at half time, away at full time |

`GET /wom/api/markets/` returns the live catalog.

## Endpoints

| Endpoint | Description |
|---|---|
| `GET /wom/api/coverage/` | Size and freshness of the dataset. Any token. |
| `GET /wom/api/events/` | Fixtures with their latest money split |
| `GET /wom/api/events/{id}/` | Every market for one fixture |
| `GET /wom/api/events/{id}/history/` | Volume and share over time |
| `GET /wom/api/movers/` | Where money share and implied probability disagree |
| `GET /wom/api/markets/` | Market catalog |

### GET /wom/api/events/

Fixtures with the latest capture for each of their markets.

| Param | Default | Description |
|---|---|---|
| `date` | — | `YYYY-MM-DD`. Omit for everything kicking off from 3 hours ago onward |
| `status` | — | `live`, `upcoming` or `finished` |
| `market` | — | A market code (`OU_2.5_OVER_FT`) or a kind (`OU`, `1X2`, `BTTS`) |
| `limit` | 20 | Max 50 |
| `offset` | 0 | Pagination offset |

```bash
curl -H "Authorization: Token $BSD_TOKEN" \
  "https://sports.bzzoiro.com/wom/api/events/?date=2026-08-04&market=1X2"
```

```json
{
  "count": 42,
  "next": "...",
  "results": [
    {
      "id": 35898868,
      "home_team": "Jeju SK",
      "away_team": "FC Bayern München",
      "league": "Elite Friendlies",
      "kickoff": "2026-08-04T11:00:00+00:00",
      "status": "inprogress",
      "total_volume": 143388.0,
      "money": [
        {
          "market": "1X2_AWAY_FT",
          "kind": "1X2",
          "line": null,
          "selection": "AWAY",
          "period": "FT",
          "name": "Match Odds 2",
          "volume": 135838.0,
          "market_volume": 143388.0,
          "share": 94.73,
          "league_avg_volume": null,
          "price": 1.11,
          "previous_price": 1.2,
          "implied_probability": 90.09,
          "is_live": true,
          "captured_at": "2026-08-04T11:42:07+00:00"
        }
      ]
    }
  ]
}
```

**Field notes**

| Field | Meaning |
|---|---|
| `volume` | Money matched on this selection, in EUR |
| `market_volume` | Money matched across every selection of this market |
| `share` | `volume / market_volume` as a percentage |
| `league_avg_volume` | Typical market volume for this competition, or `null` when there is too little history. Use it to tell a busy market from a quiet one |
| `price` / `previous_price` | Decimal odds now and at the previous capture |
| `implied_probability` | `100 / price`. Includes the book's margin — it does not sum to 100 across a market |
| `captured_at` | When this row was sampled. Not a live tick; see below |

### GET /wom/api/events/{id}/history/

The series behind a fixture. Ordered oldest first, ready to plot.

| Param | Description |
|---|---|
| `market` | Restrict to one market code. Omit for every market on the fixture |

```json
{
  "event_id": 35898868,
  "series": {
    "1X2_AWAY_FT": [
      {"captured_at": "2026-08-04T09:00:00+00:00", "volume": 40120.0, "share": 88.1, "price": 1.2,  "market_volume": 45540.0, "is_live": false},
      {"captured_at": "2026-08-04T11:42:07+00:00", "volume": 135838.0, "share": 94.73, "price": 1.11, "market_volume": 143388.0, "is_live": true}
    ]
  }
}
```

A row exists only where the numbers changed, so gaps between points are periods
when nothing moved, not missing data.

### GET /wom/api/movers/

Selections whose share of the money is furthest from what their price implies.

| Param | Default | Description |
|---|---|---|
| `min_volume` | 5000 | Skip markets thinner than this |
| `min_divergence` | 10 | Minimum absolute divergence, in points |
| `status` | — | `live`, `upcoming` or `finished` |
| `limit` | 25 | Max 100 |

```json
{
  "count": 1,
  "movers": [
    {
      "event": {"id": 35898868, "home_team": "Jeju SK", "away_team": "FC Bayern München"},
      "market": "1X2_AWAY_FT",
      "share": 94.73,
      "implied_probability": 90.09,
      "divergence": 4.64,
      "volume": 135838.0,
      "market_volume": 143388.0,
      "price": 1.11
    }
  ]
}
```

`divergence` is `share − implied_probability`, in points. Positive means more
money is on the selection than its price implies.

## Coverage and limits

Read this before you build against the data.

**It describes, it does not predict.** A selection holding 90% of the money is
not a selection that wins 90% of the time. We publish the split and the
divergence as measurements. We make no claim that either is an edge and we have
not back-tested them as a signal.

**`implied_probability` carries the margin.** It is a plain `100 / price`, so
across a full market it sums to more than 100. If you want a fair comparison
against `share`, de-vig the prices yourself first.

**Coverage follows BSD football coverage.** A fixture is stored only when it
resolves to a BSD event with confidence. Reserve teams, parts of the women's
game and smaller federations sit outside our football coverage and therefore
outside this dataset. `GET /wom/api/coverage/` reports what is actually there.

**Captures are periodic.** In-play fixtures are sampled every 15 seconds and
prematch fixtures every 60 seconds, which is as fast as the numbers change at
source. The long tail of markets — corners, cards, correct score — is refreshed
hourly. A row is written only when volume or price actually moved, so gaps in a
series mean "nothing changed", not "data missing", and `captured_at` always
tells you how old the state you are reading is.

This is a polling API, not a push stream. If you need to react within a second,
poll `/wom/api/events/?status=live` on your own clock; for tick-level odds use
the [WebSocket](/docs/websocket/).

**Volumes are in EUR** and reflect matched money on exchange-style markets, not
total turnover across the whole betting market.
