Skip to main content
Developer Documentation

Racey Public API v1

Build integrations, overlays, bots, and analytics tools with programmatic access to Racey league data. Read-only API with API key authentication.

API Key Auth

Authenticate with Bearer tokens. Create and manage keys from your settings.

Rate Limits

200 read requests/min and 60 write requests/min per API key.

Scoped Access

Restrict keys by scope (read/write/admin) and optionally limit to specific leagues.

Authentication

All API requests must include your API key in the Authorization header as a Bearer token.

Getting an API Key

  1. Sign in to your Racey account
  2. Go to Settings → API Keys
  3. Click “Create API Key” and give it a name
  4. Copy the key immediately — it will only be shown once

Using Your Key

HTTP Header
Authorization: Bearer rk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

Base URL & Response Format

Base URL
https://your-domain.com/api/v1

All responses follow a consistent envelope format:

Success Response
{
  "success": true,
  "data": { ... }
}
Error Response
{
  "success": false,
  "error": "Error message",
  "code": "ERROR_CODE"
}

Paginated endpoints return an additional wrapper:

Paginated Response
{
  "success": true,
  "data": {
    "data": [ ... ],
    "total": 42,
    "page": 1,
    "limit": 20,
    "totalPages": 3
  }
}

Rate Limits

TierLimitWindow
Read (GET)200 requestsper minute
Write (POST/PATCH/DELETE)60 requestsper minute

When rate limited, the API returns HTTP 429. Wait until the reset window before retrying.

Endpoints Reference

GET
/api/v1/leagues

List leagues accessible to the authenticated user. Supports search and filtering.

Parameters

NameTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20, max: 100)
searchstringSearch by league name
statusstringFilter by status (draft, active, paused, archived)

Example Response

{
  "success": true,
  "data": {
    "data": [
      {
        "id": "clx1abc...",
        "name": "Sunday Road Racing",
        "slug": "sunday-road-racing",
        "discipline": "road",
        "region": "na",
        "status": "active",
        "seasonCount": 3,
        "staffCount": 5
      }
    ],
    "total": 1,
    "page": 1,
    "limit": 20,
    "totalPages": 1
  }
}
GET
/api/v1/leagues/:leagueId

Get detailed information about a specific league including its current season.

Example Response

{
  "success": true,
  "data": {
    "id": "clx1abc...",
    "name": "Sunday Road Racing",
    "slug": "sunday-road-racing",
    "description": "Weekly road racing league",
    "discipline": "road",
    "region": "na",
    "status": "active",
    "currentSeason": {
      "id": "clx2def...",
      "name": "Season 3",
      "status": "active"
    },
    "seasonCount": 3,
    "staffCount": 5
  }
}
GET
/api/v1/seasons/:seasonId

Get season details with the full rounds schedule.

Example Response

{
  "success": true,
  "data": {
    "id": "clx2def...",
    "name": "Season 3",
    "status": "active",
    "league": { "id": "clx1abc...", "name": "Sunday Road Racing" },
    "rounds": [
      {
        "id": "clx3ghi...",
        "roundNumber": 1,
        "name": "Daytona Road Course",
        "trackName": "Daytona International Speedway",
        "status": "completed"
      }
    ],
    "registrationCount": 24,
    "standingsCount": 24
  }
}
GET
/api/v1/standings/:seasonId

Full championship standings for a season.

Parameters

NameTypeDescription
carClassIdstringFilter by car class (optional)

Example Response

{
  "success": true,
  "data": {
    "season": { "id": "clx2def...", "name": "Season 3", "status": "active" },
    "standings": [
      {
        "position": 1,
        "userId": "clx4jkl...",
        "driverName": "Casey Brooks",
        "totalPoints": 245,
        "wins": 3,
        "podiums": 7,
        "dnfs": 0
      }
    ]
  }
}
GET
/api/v1/results/:roundId

Race results for all sessions in a round, including points breakdown.

Example Response

{
  "success": true,
  "data": {
    "round": {
      "id": "clx3ghi...",
      "roundNumber": 1,
      "name": "Daytona Road Course",
      "status": "completed"
    },
    "sessions": [
      {
        "sessionId": "clx5mno...",
        "type": "race",
        "results": [
          {
            "position": 1,
            "driverName": "Casey Brooks",
            "startPosition": 3,
            "lapsCompleted": 45,
            "finishStatus": "running",
            "gap": null,
            "points": {
              "position": 25,
              "bonus": { "fastestLap": 1 },
              "penalty": 0,
              "total": 26
            }
          }
        ]
      }
    ]
  }
}
GET
/api/v1/drivers/:userId

Driver profile with career statistics across all seasons.

Example Response

{
  "success": true,
  "data": {
    "id": "clx4jkl...",
    "displayName": "Casey Brooks",
    "avatar": null,
    "preferredNumber": 42,
    "careerStats": {
      "seasonsRaced": 5,
      "totalWins": 12,
      "totalPodiums": 28,
      "championships": 2,
      "totalPoints": 1250.5
    },
    "simProfiles": [
      { "platform": "iracing", "iRating": 3200, "safetyRating": 4.5 }
    ]
  }
}

Code Examples

curl

Fetch league standings
curl -H "Authorization: Bearer rk_live_YOUR_KEY_HERE" \
  "https://your-domain.com/api/v1/standings/SEASON_ID"

JavaScript / TypeScript

fetch example
const API_KEY = 'rk_live_YOUR_KEY_HERE';
const BASE_URL = 'https://your-domain.com/api/v1';

async function getStandings(seasonId: string) {
  const res = await fetch(`${BASE_URL}/standings/${seasonId}`, {
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
  });

  if (!res.ok) {
    throw new Error(`API error: ${res.status}`);
  }

  const json = await res.json();
  if (!json.success) {
    throw new Error(json.error);
  }

  return json.data;
}

// Usage
const data = await getStandings('clx2def...');
console.log(data.standings);

Python

requests example
import requests

API_KEY = "rk_live_YOUR_KEY_HERE"
BASE_URL = "https://your-domain.com/api/v1"

def get_standings(season_id: str):
    response = requests.get(
        f"{BASE_URL}/standings/{season_id}",
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    response.raise_for_status()
    data = response.json()
    if not data["success"]:
        raise Exception(data["error"])
    return data["data"]

# Usage
standings = get_standings("clx2def...")
for entry in standings["standings"]:
    print(f"{entry['position']}. {entry['driverName']} - {entry['totalPoints']} pts")

Error Codes

HTTP StatusCodeDescription
401INVALID_API_KEYMissing, invalid, expired, or revoked API key
403INSUFFICIENT_SCOPEAPI key lacks the required scope for this endpoint
403LEAGUE_ACCESS_DENIEDAPI key restricted to specific leagues that don't include the requested league
404NOT_FOUNDRequested resource does not exist
429RATE_LIMIT_EXCEEDEDToo many requests; wait for the rate limit window to reset
500INTERNAL_ERRORUnexpected server error

Ready to Build?

Create an API key and start building integrations in minutes.