# WSBK Data API

Base URL:

```text
https://api.wsbkdata.pro
```

Local development URL:

```text
http://127.0.0.1:18000
```

All data is collected from public WorldSBK pages. Static image assets are cached in MongoDB and can be fetched by `asset_id`.

## Authentication

Public API endpoints under `/api/motorsport/wsbk` require an API key.

Recommended header:

```http
X-API-Key: your_api_key
```

Bearer token is also accepted:

```http
Authorization: Bearer your_api_key
```

For simple image links or constrained clients, `?api_key=your_api_key` is also accepted.

Example:

```bash
curl -H "X-API-Key: your_api_key" \
  "https://api.wsbkdata.pro/api/motorsport/wsbk/2026/calendar"
```

`/health`, `/docs`, and `/openapi.json` do not require an API key.

## Health

```http
GET /health
```

Response:

```json
{
  "status": "ok"
}
```

## Calendar

```http
GET /api/motorsport/wsbk/2026/calendar
```

Response shape:

```json
{
  "series": "WorldSBK",
  "season": 2026,
  "calendar": [
    {
      "id": "mongo_id",
      "event_code": "AUS",
      "round_number": 1,
      "round_name": "Australian Round",
      "circuit": "Phillip Island Grand Prix Circuit",
      "country": "AUS",
      "date_label": "20 Feb - 22 Feb",
      "date_start": "2026-02-20T00:00:00",
      "date_end": "2026-02-22T00:00:00",
      "source_url": "https://www.worldsbk.com/en/calendar/event/2026-AUS",
      "background_image_url": "https://resources.wsbk.pulselive.com/...",
      "background_image_asset_id": "mongo_asset_id",
      "circuit_svg": "<svg>...</svg>",
      "destination_guide": {
        "intro": ["..."],
        "sections": [
          {
            "title": "Why we love Australia and Victoria",
            "description": "...",
            "image_url": "https://resources.wsbk.pulselive.com/..."
          }
        ],
        "text": "..."
      },
      "destination_guide_asset_ids": ["mongo_asset_id"]
    }
  ]
}
```

## Event Sessions

```http
GET /api/motorsport/wsbk/2026/events/AUS/sessions
```

Response shape:

```json
{
  "series": "WorldSBK",
  "season": 2026,
  "event_code": "AUS",
  "sessions": [
    {
      "session_code": "AUS-20260222-SBK-RACE-2-12-00",
      "class_code": "SBK",
      "category": "WorldSBK",
      "type": "Race 2",
      "day_label": "Sunday 22nd",
      "session_date": "2026-02-22T00:00:00",
      "time": "12:00 - 12:40",
      "timezone": "Asia/Bangkok",
      "status": "Finished",
      "final": true,
      "results_url": "https://www.worldsbk.com/en/results/2026/aus/sbk/003",
      "replay_url": "https://worldsbk.com/en/videos/..."
    }
  ]
}
```

## Riders

```http
GET /api/motorsport/wsbk/2026/riders
GET /api/motorsport/wsbk/2026/riders?class_code=SBK
GET /api/motorsport/wsbk/2026/riders?class_code=SSP
GET /api/motorsport/wsbk/2026/riders?class_code=SPB
GET /api/motorsport/wsbk/2026/riders?class_code=YR3EC
GET /api/motorsport/wsbk/2026/riders?class_code=WCR
```

Response shape:

```json
{
  "series": "WorldSBK",
  "season": 2026,
  "class": "SBK",
  "riders": [
    {
      "rider_id": "6331",
      "class_code": "SBK",
      "number": 5,
      "name": "Yari Montella",
      "country": "ITA",
      "team": "Barni Spark Racing Team",
      "bike": "Panigale V4R",
      "date_of_birth": "5 January, 2000",
      "place_of_birth": "Oliveto Citra",
      "profile_url": "https://www.worldsbk.com/en/riders/yari-montella/6331",
      "image_url": "https://resources.wsbk.pulselive.com/...",
      "image_asset_id": "mongo_asset_id",
      "team_mate": {
        "name": "Alvaro Bautista",
        "image_url": "https://resources.wsbk.pulselive.com/..."
      },
      "all_time_stats": {
        "category": "WorldSBK",
        "races": 53,
        "poles": null,
        "wins": null,
        "podiums": 5
      },
      "stats_by_year": [
        {
          "year": 2026,
          "category": "WorldSBK",
          "races": 17,
          "podiums": 5
        }
      ],
      "rider_story": "...",
      "rider_story_sections": [
        {
          "title": "Ducati (2025-)",
          "paragraphs": ["..."]
        }
      ]
    }
  ]
}
```

## Teams

```http
GET /api/motorsport/wsbk/2026/teams
GET /api/motorsport/wsbk/2026/teams?class_code=SBK
```

Response shape:

```json
{
  "series": "WorldSBK",
  "season": 2026,
  "class": "SBK",
  "teams": [
    {
      "team_id": "SBK-2026-1",
      "class_code": "SBK",
      "name": "Barni Spark Racing Team",
      "team_url": "https://www.worldsbk.com/en/teams/sbk/barni-spark-racing-team/SBK-2026-1",
      "image_url": "https://resources.wsbk.pulselive.com/...",
      "image_asset_id": "mongo_asset_id",
      "rider_numbers": [5, 19],
      "riders": ["Yari Montella", "Alvaro Bautista"]
    }
  ]
}
```

## Standings

```http
GET /api/motorsport/wsbk/2026/standings?class_code=SBK
GET /api/motorsport/wsbk/2026/standings?class_code=SSP
GET /api/motorsport/wsbk/2026/standings?class_code=WCR
```

Response shape:

```json
{
  "series": "WorldSBK",
  "season": 2026,
  "class": "SBK",
  "standing_type": "riders",
  "standings": [
    {
      "position": 1,
      "rider_name": "Nicolo Bulega",
      "rider_number": 11,
      "team": "Aruba.it Racing - Ducati",
      "points": 347,
      "scraped_at": "2026-05-31T12:09:11.170000"
    }
  ]
}
```

## Results

```http
GET /api/motorsport/wsbk/2026/result-documents?class_code=SBK
GET /api/motorsport/wsbk/2026/results?class_code=SBK&event_code=ARA&session_code=002
```

## Cached Assets

```http
GET /api/motorsport/wsbk/assets/{asset_id}
```

Returns binary content with the correct `Content-Type`, for example `image/jpeg` or `image/png`.

Example:

```text
https://api.wsbkdata.pro/api/motorsport/wsbk/assets/6a1c35fdc1f0c24dd6c99609
```

## Update Jobs

Manual crawler commands:

```bash
python -m crawler.jobs scrape-calendar --season 2026
python -m crawler.jobs scrape-riders --all-classes --with-profiles
python -m crawler.jobs scrape-teams --all-classes
python -m crawler.jobs scrape-standings --season 2026 --class-code SBK
python -m crawler.jobs cache-assets
```

The standings worker runs daily in Docker and updates `SBK,SSP,WCR`.
