---
title: "Bare price ticks of the mapped match-winner market, newest first (PRO)"
method: GET
path: "/matches/{matchId}/prices"
---

# Bare price ticks of the mapped match-winner market, newest first (PRO)

`GET /matches/{matchId}/prices`

## Request

- Base URL: `https://api.livetennisapi.com/api/public/v1`
- URL: `https://api.livetennisapi.com/api/public/v1/matches/{matchId}/prices`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

Recent ticks only (no market wrapper). `limit` caps at 500; `minutes` bounds the lookback window; `cursor` pages an older match. 404 `no_market` when the match exists but has no mapped market (404 `not_found` for an unknown id). Retention (since 2026-09-15): in-play ticks of a match with a mapped market — from live to completion, plus a five-minute pad — are kept at full resolution and not deleted; pre-match / idle ticks and unmapped markets keep the tiers (every tick for an hour, ~1/minute to 24h, ~1/5 minutes after, deleted after 30 days). Ticks stamped before 2026-09-15 were already thinned under those tiers.

Ticks are kept for 30 days and then deleted, so a match older than that answers an empty `data` while its market stays mapped — that is retention, not a fault. Past 500 ticks, page with the cursor: read a page, and while `meta.has_more` is true pass `meta.next_cursor` back as `?cursor=` for the next (older) page. Pages never overlap or skip a tick (added 2026-09-09).

## Path parameters

- `matchId` integer, required

## Query parameters

- `limit` integer
- `minutes` integer
- `cursor` string

## Response `200`

Price ticks

- object
  - `data` Price[]
    - `side` integer, nullable: 1 = players.p1's outcome, 2 = players.p2's - decided by our name-verified match-market mapping, never by the venue's own display order (the venue lists roughly half of all pairings the other way round). Fixed 2026-09-09: ticks served before that date followed the venue's display order, so on those markets side was reversed; the mapping is stored, so re-reading any tick now returns the correct side.
    - `bid` number, nullable
    - `ask` number, nullable
    - `mid` number, nullable: The venue's observed midpoint at the instant we polled or streamed it - never a model estimate. Only mid is always real; see synthetic.
    - `spread` number, nullable
    - `price_source` string, nullable: Feed category, e.g. prediction_market
    - `synthetic` boolean, nullable: true = bid/ask are estimated from mid (mid +/- 0.005, not a live order book) - mid itself is the venue's observed midpoint, never a model estimate; false = real top-of-book from the live order-book stream; null = unknown (older ticks). The live stream attaches when a match goes live, so pre-match ticks are synthetic: true by design.
    - `timestamp` string, date-time, nullable: When we observed this quote (UTC) - our observation clock, not a venue publication time.
  - `meta` object
    - `match_id` integer
    - `count` integer
    - `has_more` boolean: The window was clipped at limit — older ticks exist. There is no offset here: pass `next_cursor` back as `?cursor=` for the next older page.
    - `next_cursor` string, nullable: Present (non-null) exactly when `has_more` is true — pass it back as `?cursor=` for the next older page (added 2026-09-09).
    - `limit` integer
    - `minutes` integer, nullable

## Other responses

- `400`: Bad query parameter
- `401`: Missing, unknown, or disabled credentials
- `403`: Your tier doesn't unlock this endpoint
- `404`: No such resource, or no data yet
- `410`: The match id existed and was merged into another match record (since 2026-09-05). The body is `MatchMerged`, not `Error`: it carries a forwarding address, which is the whole point of answering 410 rather than 404.
- `429`: Rate limit exceeded (Retry-After header present). Three body shapes, told apart by `error` and `scope`: the per-MINUTE limit (`rate_limited`, with `upgrade_url`, `tier` and `price` naming the next tier up); the per-DAY quota (`rate_limited` with `scope: "day"`, `limit_per_day`, and `resets_at` — the absolute ISO instant the daily window resets); and `abuse_throttled` with `retry_at_epoch` — a 24-hour block applied to clients that keep hammering far past their cap, which a well-behaved retry loop never sees. Fix the loop rather than retrying through it.

---

[API](https://skmtc.dev/livetennisapi/apis/live-tennis-api.md) · [All operations](https://skmtc.dev/livetennisapi/apis/live-tennis-api/llms.txt) · [OpenAPI document](https://skmtc.dev/livetennisapi/apis/live-tennis-api/revisions/7881947e8e43?raw)
