> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sportsapipro.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cycling races on V3

> Stage results and General Classification for the Tour de France and other stage races, via the V3 cycling feed

Cycling race content — stage results, General Classification, live standings — is served by **V3**.

## Base URL and auth

```
https://v3.cycling.sportsapipro.com/api/v1
```

```bash theme={null}
curl -H "x-api-key: YOUR_API_KEY" \
  "https://v3.cycling.sportsapipro.com/api/v1/cycling/today"
```

The canonical front door `https://api.sportsapipro.com/v3/cycling/...` maps to the same routes.

## Endpoints

```
GET /api/v1/cycling/today
GET /api/v1/cycling/live
GET /api/v1/cycling/yesterday
GET /api/v1/cycling/tomorrow
```

These four period windows are the supported cycling endpoints. `/api/v1/cycling/tournament/{id}` is not served, and `/api/v1/match/{eventId}` (plus `/standings`) returns an empty shell for cycling — all the cycling payload is in the period listings.

<Warning>
  **Rolling window only — no historical or date-addressable cycling.** `today`, `live`, `yesterday` and `tomorrow` are the complete set. There is no date parameter: `/api/v1/cycling/2026-07-15`, `/api/v1/cycling/date/2026-07-15` and `/api/v1/cycling/schedule/2026-07-15` all return **404**. Once a race finishes it leaves the window, so a Grand Tour that is not currently running cannot be queried, and multi-season backfill for modelling is not available on any version.

  If your product needs archived stage results, persist the `today` / `yesterday` payloads yourself day by day while a race is live.
</Warning>

## How to read the response

```json theme={null}
{
  "sport": { "slug": "cycling", "id": 34, "name": "Cycling" },
  "period": "today",
  "totalEvents": 563,
  "totalLeagues": 4,
  "leagues": [
    {
      "league": {
        "name": "TOURS: Tour de France Femmes (France) - Overall",
        "country": "France",
        "leagueId": "dMTCo1K8",
        "tournamentId": "tUEyQZzj",
        "hasStandings": false
      },
      "events": [
        {
          "id": "8xJY8q8bdMTCo1K8",
          "startTime": "2026-08-01T12:40:00.000Z",
          "startTimestamp": 1785588000,
          "statusCode": 3,
          "status": "finished",
          "homeTeam": {
            "name": "Wiebes L.",
            "shortName": "1",
            "abbr": "WIE",
            "id": "8xJY8q8b",
            "participantId": "CIVAwGJ2",
            "slug": "wiebes-lorena"
          },
          "awayTeam": { "name": "", "id": null },
          "homeScore": { "current": null }
        }
      ]
    }
  ]
}
```

Two rules cover everything:

1. **Each `leagues[]` entry is a classification, not a competition.**
   * `... - Overall` is the **General Classification** (GC).
   * `... - Stage N` is that stage's result.
   * One race therefore appears as several leagues sharing the same `tournamentId`.

2. **Each `events[]` entry is one rider's placing, not a match.**
   * `homeTeam.name` — the rider (`Wiebes L.`)
   * `homeTeam.shortName` — the **position** (`"1"`, `"2"`, `"3"`, …)
   * `homeTeam.slug` / `participantId` — stable rider identifiers
   * `status` / `statusCode` — `finished`, in progress, etc.
   * `awayTeam` and all score objects are unused for cycling — ignore them.

## Recipe: GC table and stage result

```python theme={null}
import requests

r = requests.get(
    "https://v3.cycling.sportsapipro.com/api/v1/cycling/today",
    headers={"x-api-key": "YOUR_API_KEY"},
    timeout=30,
)
data = r.json()

def classification(data, race_substring, kind):
    """kind: 'Overall' for GC, or 'Stage 2' for a stage result."""
    for entry in data["leagues"]:
        name = entry["league"]["name"]
        if race_substring.lower() in name.lower() and name.strip().endswith(f"- {kind}"):
            rows = [
                (int(e["homeTeam"]["shortName"]), e["homeTeam"]["name"])
                for e in entry["events"]
                if (e["homeTeam"].get("shortName") or "").isdigit()
            ]
            return sorted(rows)
    return []

for pos, rider in classification(data, "Tour de France Femmes", "Overall")[:10]:
    print(pos, rider)
```

Swap `"Overall"` for `"Stage 2"` to get that stage's finishing order.

## Coverage notes

* Men's and women's Grand Tours and week-long stage races appear under this structure **while they are running**. Once a race finishes it drops out of the `today` / `live` windows; use `yesterday` immediately after a stage.
* `league.name` is prefixed with the race family (for example `TOURS:`) and suffixed with the classification. Match on `tournamentId` when you need a stable key across days.
* Not available for cycling on any version: live GPS/telemetry, power and gradient data, per-rider in-stage splits, cycling odds, and multi-season historical backfill.
