Skip to main content
Developer Documentation

Racey Public API v1

Build integrations, overlays, bots, and analytics tools with programmatic access to Racey league data. REST API v1 is currently read-only and secured by API key authentication.

API Key Auth

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

Rate Limits

200 read requests/min per API key.

Scoped Access

Restrict keys by scope and optionally limit to specific leagues. An unrestricted key (no league filter) may read any league the key owner can access; a league-restricted key may only read the specific leagues listed on the key and returns 403 LEAGUE_ACCESS_DENIED for any other league.

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_example_redacted

Base URL & Response Format

Base URL
https://racey.gg/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

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
401UNAUTHORIZEDMissing or malformed Authorization header
401INVALID_API_KEYInvalid, 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_LIMITEDToo many requests; wait for the rate limit window to reset
500INTERNAL_ERRORUnexpected server error

Webhooks
Coming Soon

Webhooks let you receive real-time HTTP notifications when events happen in your leagues — results published, protests filed, standings updated, and more. Once shipped, you will configure webhook endpoints in your league settings.

Planned Webhook Events

EventDescription
result.publishedRace results have been published for a round
standings.updatedChampionship standings recalculated after a result or correction
protest.filedA driver has filed a protest for a round
protest.decidedStewards have issued a verdict on a protest
appeal.filedA driver has appealed a stewarding decision
appeal.decidedAn appeal panel has issued its final verdict
registration.approvedA driver registration request has been approved
round.scheduledA new round has been added to a season schedule

Payload Shape

Each webhook delivery is an HTTP POST with a JSON body in this format:

Webhook payload
{
  "event": "result.published",
  "leagueId": "clx1abc...",
  "roundId": "clx2def...",
  "timestamp": "2026-04-10T14:30:00Z",
  "data": { ... }  // event-specific payload
}

Deliveries will include an X-Racey-Signature header (HMAC-SHA256 of the raw body using your webhook secret) so you can verify authenticity.

Ready to Build?

Create an API key and start building integrations in minutes.