API reference / Racing Archive
GET /v1/racing/price-pathsBulk export of the permanent price-movement archive
Every OBSERVED PRICE POINT in the permanent movement archive: one row per race, runner, bookmaker and captured price, from market open to the last pre-jump quote. **This is the bulk, downloadable form of `/v1/racing/price-history`.** That endpoint answers for one race; this one exports a date range as a flat table (CSV loads straight into pandas — `pd.read_csv(url)` with your key in the header; `format=parquet` returns the same table typed, `pd.read_parquet(BytesIO(r.content))`). The archive is permanent: nothing here ages out, and coverage runs from `archive_from` (capture began 2026-08-04) forward, forever. **The series is change-only.** Each row is a price MOVE, not a fixed-interval sample — a gap between two points means the price held. To build T-snapshots (T-60/30/15/5/2), take the last row at or before each mark per (race_id, runner_key, bookmaker_key). **Window guard.** Points run ~9x the series rows, so a request without `race_id` is capped at a 7-day `from`/`to` window per call — page a season week by week. A reversed or over-wide range is a free 422. **`runner_ref`** (last column, since 2026-09-05) is the stable registry id for the runner — `ra:<horsecode>` for thoroughbreds, `grv:<dogId>` for greyhounds — identical to the `runner_ref` on `/v1/racing/results` `runners[]` entries and on the live board, so every point in this export joins to its result and to `/v1/racing/horses/form` on one key. Null where no registry id is known: harness, rows archived before late August 2026, and a race whose result has not landed and whose acceptance list we did not hold. Betfair Exchange rows are withheld pending a data licence, so `lay_price` — which only an exchange quotes — is NULL for customers. BSP and traded volume are absent for the same reason; when a licence lands they will arrive as new columns, not a changed contract.
X-API-Key
5 credits (JSON) / 20 credits (CSV)
curl 'https://api.puntersedge.online/v1/racing/price-paths?date=2026-08-15&category=horse&format=csv' \
-H 'X-API-Key: YOUR_KEY'
| Name | In | Type | Required | Description |
|---|---|---|---|---|
from |
query | string | no | ISO date/time on the race start. |
to |
query | string | no | ISO date/time. |
date |
query | string | no | Single-day alias: date=YYYY-MM-DD is exactly from=YYYY-MM-DD&to=YYYY-MM-DD. Mutually exclusive with from/to. |
venue |
query | string | no | Venue name, case-insensitive, exact match. |
bookmakers |
query | string | no | Comma-separated bookmaker keys, case-insensitive. An unrecognised key is a free 422 naming the valid keys. |
category |
query | string | no | horse, harness or greyhound |
country |
query | string | no | Two-letter country code, e.g. AU, NZ |
race_id |
query | string | no | Single race. With race_id the window guard does not apply. |
include_flagged |
query | boolean | no | Include rows flagged venue_split_suspect or name_fragment_suspect. False by default. |
format |
query | string | no | csv streams a flat table with a stable column order — the bulk download this endpoint exists for. parquet returns the same table, same column order, as one Apache Parquet file with typed columns (UTC timestamps, a date, float64 prices) — pd.read_parquet(BytesIO(r.content)). Same credit cost and row cap as csv. |
limit |
query | integer | no | |
offset |
query | integer | no |
Status codes: 200, 401, 402, 422, 429, 500. Response bodies are JSON; the full schema is in /openapi.json.
200 application/json
— this call costs 5 credits (JSON) / 20 credits (CSV).
Field names and types are as the API returns them; values are a real sample, trimmed to a few items.
{
"rows_returned": 3,
"total_points": 41872,
"limit": 500,
"offset": 0,
"archive_from": "2026-08-04T09:22:00Z",
"rows": [
{
"race_id": "104702cc-8a42-4b14-88b0-1fb6de91e913",
"start_time": "2026-09-06T09:00:00Z",
"meeting_date_aet": "2026-09-06",
"venue": "Kalgoorlie",
"race_number": 8,
"category": "horse",
"country": "AU",
"runner_key": "vomo island",
"runner_name": "Vomo Island",
"runner_number": 8,
"bookmaker_key": "sportsbet",
"captured_at": "2026-09-06T08:00:12Z",
"secs_to_jump": 3588,
"win_price": 5.0,
"lay_price": null,
"venue_id": "kalgoorlie",
"venue_site": "kalgoorlie",
"runner_ref": "ra:NzkyMzc2NTE1MA"
},
{
"race_id": "104702cc-8a42-4b14-88b0-1fb6de91e913",
"start_time": "2026-09-06T09:00:00Z",
"meeting_date_aet": "2026-09-06",
"venue": "Kalgoorlie",
"race_number": 8,
"category": "horse",
"country": "AU",
"runner_key": "vomo island",
"runner_name": "Vomo Island",
"runner_number": 8,
"bookmaker_key": "sportsbet",
"captured_at": "2026-09-06T08:41:03Z",
"secs_to_jump": 1137,
"win_price": 4.8,
"lay_price": null,
"venue_id": "kalgoorlie",
"venue_site": "kalgoorlie",
"runner_ref": "ra:NzkyMzc2NTE1MA"
},
{
"race_id": "104702cc-8a42-4b14-88b0-1fb6de91e913",
"start_time": "2026-09-06T09:00:00Z",
"meeting_date_aet": "2026-09-06",
"venue": "Kalgoorlie",
"race_number": 8,
"category": "horse",
"country": "AU",
"runner_key": "vomo island",
"runner_name": "Vomo Island",
"runner_number": 8,
"bookmaker_key": "sportsbet",
"captured_at": "2026-09-06T08:59:21Z",
"secs_to_jump": 39,
"win_price": 4.6,
"lay_price": null,
"venue_id": "kalgoorlie",
"venue_site": "kalgoorlie",
"runner_ref": "ra:NzkyMzc2NTE1MA"
}
]
}
GET /v1/racing/closing-lines — Permanent closing-line and result archiveGET /v1/racing/closing-lines/coverage — What the closing-line archive actually holdsThe free tier needs no credit card, and the sandbox endpoints need no key at all.
Get a free API key Quickstart