---
title: "Score bets against the closing line (CLV)"
method: POST
path: "/v1/racing/clv"
tags: ["Racing"]
---

# Score bets against the closing line (CLV)

`POST /v1/racing/clv`

## Request

- Base URL: `https://api.puntersedge.online`
- URL: `https://api.puntersedge.online/v1/racing/clv`
- Auth: API key in header `X-API-Key`

Cost: 5 credits per request, up to 200 bets. Score a list of bets you struck against the
closing line each race actually closed at, and get the record back as numbers: per bet the
closing price (the named book's, or the market's best or median), the closing-line value in
percent, whether it beat the close, the result and the flat-stake P&L; and across the list
the average and median CLV, the beat-the-close rate, the win rate and the ROI.

**Naming a race.** Send the `race_id` you already hold from next-to-go, events, results or
the archive; failing that, `venue` + `meeting_date` (AET) + `race_number`. **Naming a
runner.** `runner_ref` (the ra:/grv: registry id on results and the archive) is exact;
`runner_number` is the saddlecloth; `runner_name` is matched the way the feeds match names.

**What you are measured against.** A closing line is a book's last price within 300 s of
the jump. Name a `bookmaker` and `clv_pct` is against that book's close (`close_book`);
otherwise against the market `reference` — `best` (the highest close across books, the
strictest test) or `median`. `close_best` and `close_median` come back on every bet
either way, so you can re-cut the record yourself.

**Coverage.** The archive holds AU and NZ races from `archive_floor` onward; a bet before
that, or on a race no book priced at the close, resolves with a `reason` and is left out
of the averages rather than guessed. Results are settled only when `result_status` is
`final`; `won` and `pnl` are null until then. Betfair exchange prices are withheld.

Plus and above. Free and paid tiers below Plus receive a 403 and are not charged; the 403
carries a `sample`: five example bets on one recent race, scored the way yours would be.

## Headers

- `X-API-Key` string
- `X-RapidAPI-Proxy-Secret` string

## Request body

- ClvIn
  - `bets` ClvBetIn[], required: Up to 200 bets per request.
    - `ref` string, nullable: Your own id for this bet, echoed back unchanged.
    - `race_id` string, nullable: The race_id from /v1/racing/next-to-go, /events, /results or the archive. The most reliable way to name a race; use venue + meeting_date + race_number only when you do not hold it.
    - `venue` string, nullable: Venue name as our feeds spell it (case-insensitive). Needs meeting_date and race_number.
    - `race_number` integer, nullable
    - `meeting_date` string, date, nullable: AET meeting date, YYYY-MM-DD.
    - `runner_ref` string, nullable: Registry id as served on /results and the archive — ra:<horsecode> or grv:<dogId>. Exact match; the most reliable way to name a runner.
    - `runner_number` integer, nullable: Saddlecloth number.
    - `runner_name` string, nullable: Runner name; matched the same way the feeds match names (case, punctuation and country suffixes ignored).
    - `bookmaker` string, nullable: bookmaker_key the bet was struck with. When given, `clv_pct` is measured against THAT book's closing price and `close_book` is filled; when absent, against the market reference chosen by `reference`.
    - `price` number, required: Decimal odds you took.
    - `stake` number: Stake for the P&L line. Defaults to one flat unit.
  - `reference` string: The market close used when a bet names no bookmaker, and reported as close_best / close_median on every bet regardless: `best` is the highest closing win price across books, `median` the median.

## Response `200`

Successful Response

- ClvOut
  - `reference` string, required
  - `archive_floor` string, date, nullable: Earliest race day the archive holds; bets before it cannot resolve.
  - `summary` ClvSummaryOut, required
    - `bets` integer, required
    - `resolved` integer, required
    - `unresolved` integer, required
    - `scored` integer, required: Bets with a closing line to measure against.
    - `avg_clv_pct` number, nullable
    - `median_clv_pct` number, nullable
    - `beat_close` integer
    - `beat_close_rate_pct` number, nullable
    - `resulted` integer: Scored-or-resolved bets with a final result.
    - `wins` integer
    - `win_rate_pct` number, nullable
    - `staked` number, nullable
    - `pnl` number, nullable
    - `roi_pct` number, nullable
  - `bets` ClvBetOut[], required
    - `ref` string, nullable
    - `resolved` boolean, required: True when the race AND the runner were found in the archive. False rows carry `reason` and no numbers.
    - `reason` string, nullable: race_not_found · race_ambiguous · runner_not_found · runner_ambiguous · bookmaker_withheld · no_closing_line · no_closing_line_for_book.
    - `race_id` string, nullable
    - `venue` string, nullable
    - `race_number` integer, nullable
    - `runner_key` string, nullable
    - `runner_name` string, nullable
    - `runner_number` integer, nullable
    - `runner_ref` string, nullable
    - `bookmaker` string, nullable
    - `price_taken` number, required
    - `stake` number, required
    - `close_book` number, nullable: The named bookmaker's closing win price, when it recorded a closing line.
    - `close_best` number, nullable: Highest closing win price across books.
    - `close_median` number, nullable: Median closing win price across books.
    - `books_at_close` integer: Books with a closing line for this runner.
    - `close_reference` number, nullable: The close `clv_pct` is measured against: close_book when a bookmaker was named and priced the close, else the market reference.
    - `clv_pct` number, nullable: (price_taken / close_reference − 1) × 100. Positive means you beat the close.
    - `beat_close` boolean, nullable
    - `finish_position` integer, nullable
    - `result_status` string, nullable: final · interim · null (not yet resulted).
    - `won` boolean, nullable: On a final result: true for the winner, false for every other runner — including one with no published position, since results list placegetters only. Null until final, and null when the result records no winner.
    - `pnl` number, nullable: stake × (price − 1) on a win, −stake on a loss, null until the result is final.
  - `notes` string[]

## Other responses

- `401`: Missing or invalid API key. Send `X-API-Key`. See https://puntersedge.online/developers/errors
- `402`: Monthly credit allowance exhausted for this plan. Upgrade at https://puntersedge.online/api/pricing
- `403`: Closing-line value scoring is available on Plus, Business, Platform and Scale plans only. The refusal is free and carries a `sample`: five example bets on one recent race, scored.
- `422`: Validation Error
- `429`: Rate limit exceeded for this plan. Honour the `Retry-After` header (seconds) before retrying. See https://puntersedge.online/developers/rate-limits
- `500`: Unexpected server error. Safe to retry with backoff.

---

[API](https://skmtc.dev/puntersedge/apis/puntersedge-odds-api.md) · [All operations](https://skmtc.dev/puntersedge/apis/puntersedge-odds-api/llms.txt) · [OpenAPI document](https://skmtc.dev/puntersedge/apis/puntersedge-odds-api/revisions/f35b6aab1946?raw)
