Searching by match ID
GET /tennis/v2/extend/api/historical-odds/movements?match_id=32703-29462-17157-5Providing only match_id returns the available movements across all markets, bookmakers, and lines for that match.
There is no default year restriction for this search. If supplied, player1, player2, and year do not affect match selection.
The response is grouped as:
result → market → bookmaker → movement recordsSearching by player names
GET /tennis/v2/extend/api/historical-odds/movements?player1=Gijs%20Brouwer&player2=Michael%20Geerts&year=2021When match_id is omitted:
- Both player names are required.
- Matching ignores capitalization and leading/trailing spaces in the supplied names.
- Either player order is accepted.
- Names must match the stored full names; partial-name searches are not supported.
- Omitting
yearsearches the current year. - Multiple matches are separated by their historical match identifiers.
The response gains one additional grouping level:
result → match_id → market → bookmaker → movement recordsThe year is based on the odds’ recorded timestamp, using January 1 at 00:00:00 UTC inclusive through the following January 1 exclusive. It is not based on the database import date.
Filtering markets and bookmakers
Request one market and bookmaker:
GET /tennis/v2/extend/api/historical-odds/movements?match_id=32703-29462-17157-5&market_id=2&bookmaker_id=20How movements are detected
Quotes are compared within each match, market, bookmaker, and line:
| Recorded time | od1 | od2 | Included by default? |
|---|---|---|---|
| 10:00 | "1.87" | "1.87" | Yes — initial quote |
| 10:01 | "1.87" | "1.87" | No — unchanged |
| 10:02 | "1.90" | "1.84" | Yes — prices changed |
| 10:03 | "1.900" | "1.840" | No — numerically equal |
| 10:04 | "1.87" | "1.87" | Yes — prices changed back |
A movement requires a change in either price, not necessarily both.
Returning to an earlier price still counts as a movement. Numeric formatting differences, such as "1.90" and "1.900", do not.
previousOd1, previousOd2, and previousAddTime refer to the immediately preceding stored quote in the same series. That quote may have been excluded from the response because its prices were unchanged.
Initial quotes
By default:
include_initial=trueThe first recorded quote for each series is returned with:
{
"previousOd1": null,
"previousOd2": null,
"previousAddTime": null,
"isInitial": true
}To return changes only:
GET /tennis/v2/extend/api/historical-odds/movements?match_id=32703-29462-17157-5&include_initial=falseAn initial quote means the first quote available in the stored data. It is not necessarily the bookmaker’s actual opening price.
Time-range filtering
GET /tennis/v2/extend/api/historical-odds/movements?match_id=32703-29462-17157-5&from=1624528991&to=1624532591Both bounds are inclusive:
from ≤ addTime ≤ toChange detection uses preceding quotes before applying the lower time bound. Therefore:
- A movement inside the range can reference a previous quote outside the range.
- The first quote inside the range is not automatically treated as an initial quote.
- An initial quote is returned only if its own timestamp falls inside the range.
- This endpoint does not add a snapshot of the price already in effect at
from.
For player-name searches, the time range also intersects with the selected year.