📖 OpenLiveTiming API Documentation
Table of Contents
Overview
OpenLiveTiming provides a REST API and SignalR hub for streaming live motorsport timing data. You can push race data from your own timing application and have it displayed in real-time on your dedicated live timing page.
The platform is organized around a simple hierarchy:
Account (your organization)
└─ Instance (a live timing feed, e.g. "adac-mx-masters")
└─ API Key (grants push access to specific instances)Authentication
The API supports two authentication methods for pushing data:
API Key (recommended for workers)
Use the X-Api-Key header with a key created from your
account dashboard.
X-Api-Key: olt_a1b2c3d4e5f6...
JWT Bearer Token (for user-facing operations)
Obtain a token via POST /api/auth/login:
POST /api/auth/login
Content-Type: application/json
{
"email": "you@example.com",
"password": "your-password"
}
// Response:
{
"token": "eyJhbGciOi...",
"email": "you@example.com",
"displayName": "Your Name"
}
// Use in subsequent requests:
Authorization: Bearer eyJhbGciOi...Quick Start
- Create your live timing at /create (or via the API).
- Create an API key from your account dashboard, scoped to your instance.
- Push a full state to initialize your timing page (see below).
- Push incremental events as the race progresses.
- View live at
openlivetiming.com/lt/your-slug, or embed it on your website.
Pushing Race Data
Full State (complete snapshot)
Push a complete race state. This is the primary way to update your timing page. New viewers and reconnecting clients will receive this state immediately.
POST /api/instances/{slug}/race/fullstate
X-Api-Key: your-api-key
Content-Type: application/json
{
"session": {
"trackName": "Circuit de Spa",
"groupName": "Race 1",
"runName": "Final",
"sectorCount": 3,
"flagStatus": "Green",
"timeRemaining": "00:25:00",
"timeOfDay": "14:30:00",
"totalLaps": 20,
"currentLap": 5
},
"drivers": {
"1": {
"number": "1",
"name": "Max Speed",
"team": "Team Alpha",
"position": 1,
"laps": 5,
"lastLapTime": "00:01:45.123",
"bestLapTime": "00:01:44.567",
"sectorTimes": ["00:00:32.100", "00:00:38.200", "00:00:34.823"],
"bestSectorTimes": ["00:00:31.900", "00:00:37.800", "00:00:34.567"],
"gap": "",
"interval": "",
"status": "Running"
},
"44": {
"number": "44",
"name": "Lewis Quick",
"team": "Team Beta",
"position": 2,
"laps": 5,
"lastLapTime": "00:01:45.456",
"bestLapTime": "00:01:44.890",
"gap": "+0.323",
"interval": "+0.323",
"status": "Running"
}
}
}
Update Cache Only (no broadcast)
Use PUT instead of POST to update the cached state without broadcasting to connected viewers. Useful for high-frequency updates.
PUT /api/instances/{slug}/race/fullstate
X-Api-Key: your-api-key
Content-Type: application/json
{ ...same body... }
Push Individual Events
Send individual race events for real-time updates:
POST /api/instances/{slug}/race/event
X-Api-Key: your-api-key
Content-Type: application/json
{
"$type": "LapCompleted",
"number": "44",
"lapTime": "00:01:44.567",
"lapNumber": 6,
"position": 2
}
Push Batch Events
POST /api/instances/{slug}/race/events
X-Api-Key: your-api-key
Content-Type: application/json
[
{ "$type": "SectorCompleted", "number": "1", "sector": 1, "sectorTime": "00:00:31.900" },
{ "$type": "SectorCompleted", "number": "44", "sector": 1, "sectorTime": "00:00:32.100" }
]Race Event Types
Events use a $type discriminator for polymorphic JSON serialization:
| Type | Description |
|---|---|
SectorCompleted | A driver completed a timing sector |
LapCompleted | A driver completed a lap |
PositionChange | Driver classification position changed |
BestLap | New session overall best lap time |
BestSector | New session overall best sector time |
FlagChange | Track flag status changed (Green, Yellow, Red, etc.) |
SessionInfoUpdate | Session metadata updated |
FullState | Complete state snapshot |
Announcement | Race control announcement |
Real-Time via SignalR
For consuming live data in real-time, connect to the SignalR hub:
// JavaScript example
const connection = new signalR.HubConnectionBuilder()
.withUrl("/racehub?instance=your-slug")
.build();
// Request the current state
await connection.start();
await connection.invoke("RequestFullState");
// Listen for events
connection.on("ReceiveFullState", (state) => {
console.log("Full state:", state);
});
connection.on("ReceiveRaceEvent", (event) => {
console.log("Event:", event);
});
connection.on("ReceiveBatchEvents", (events) => {
console.log("Batch:", events);
});
Hub Methods
| Method | Direction | Description |
|---|---|---|
RequestFullState() | Client → Server | Request cached full state |
ReceiveFullState | Server → Client | Complete race snapshot |
ReceiveRaceEvent | Server → Client | Single race event |
ReceiveBatchEvents | Server → Client | Batch of race events |
Interactive API Reference
For the complete interactive API reference with request/response schemas, visit the OpenAPI documentation:
OpenAPI Spec (JSON)Questions? Reach out at info@openlivetiming.com