Feed Catalog Race Events RaceHooks-computed synthetic event streams. Instead of receiving raw position arrays and computing events yourself, you subscribe once and receive pre-detected, structured events. This family has three feeds: events.race (40+ event types, including overtakes, pit stops, safety cars, fastest laps, retirements, and more), session.timing (aggregated session state ), and events.qualifying (qualifying-scoped events ). Currently available for F1; equivalent feeds for other sports will be documented here as they launch.
Feed ID
Cadence: event-driven · available on the Developer plan and above
Subscribe bash copy
curl -X POST https://api.racehooks.io/v1/webhooks \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"webhookUrl": "https://your-app.com/race-events",
"feedId": "events.race"
}'subscribe.ts copy
import { RaceHooks } from "racehooks";
const rh = new RaceHooks({
clientId: process.env.RACEHOOKS_CLIENT_ID!,
clientSecret: process.env.RACEHOOKS_CLIENT_SECRET!,
});
// All race events for the entire field
const { webhook, webhookSecret } = await rh.webhooks.create({
feedId: "events.race",
webhookUrl: "https://your-app.com/race-events",
});
// Overtakes and pit stops for your fantasy team only
await rh.webhooks.create({
feedId: "events.race",
webhookUrl: "https://scoring.myapp.com/hook",
filters: { drivers: ["VER", "NOR", "LEC"] },
});Payload structure Every events.race delivery shares a common envelope with an event-specific data object:
Field Type Description feedstringAlways "events.race". Identifies this as a race event payload. sessionIdstringUnique identifier for the current F1 session. eventstringEvent type: one of the event types listed below. lapnumberCurrent race lap number when the event fired. utcstringISO 8601 timestamp of when the event was detected. dataobjectEvent-specific data. Schema varies per event type.
A complete delivery, recorded from the Canadian Grand Prix (2026-canada_r), lap 30, where Antonelli passes Russell for the lead:
json copy
{
"feed": "events.race",
"sessionId": "2026-canada_r",
"event": "overtake",
"lap": 30,
"utc": "2026-10-05T18:49:20.412Z",
"data": {
"overtakingDriver": {
"driverId": "antonelli-kimi",
"constructorId": "mercedes",
"number": "12",
"tla": "ANT",
"name": "Kimi Antonelli",
"team": "Mercedes",
"newPosition": 1,
"prevPosition": 2
},
"overtakenDriver": {
"driverId": "russell-george",
"constructorId": "mercedes",
"number": "63",
"tla": "RUS",
"name": "George Russell",
"team": "Mercedes",
"newPosition": 2,
"prevPosition": 1
}
}
}One pass, several events A single on-track pass is not one message. On the same lap of the recording, the lead change arrived as this run of events, in this order. One incident can produce several distinct events, so do not collapse them by lap and driver. Correlating them (grouping the events of one incident by lap and the driver ids) is a different operation from detecting duplicates. For duplicate handling, use X-RaceHooks-Delivery-Id: it is the same across the automatic retries of a delivery, so skip any id you have already processed.
overtake.attempt.startedlap 30 · 2026-10-05T18:49:20.412Z
overtakelap 30 · 2026-10-05T18:49:20.412Z
lead.changelap 30 · 2026-10-05T18:49:20.412Z
positions.gainedlap 30 · 2026-10-05T18:49:20.412Z
positions.lostlap 30 · 2026-10-05T18:49:20.412Z
overtake.attempt.resolvedlap 30 · 2026-10-05T18:49:25.415Z
Route on event in your webhook handler ; replay this race end to end with the quickstart to see the same sequence arrive at your endpoint.
Event types session.startAll
Session status transitions to Started.
json copy
// data field
{
"sessionName": "Race",
"sessionType": "Race",
"totalLaps": 68
}session.completeRace / Sprint
Race or Sprint session result is finalised and the winner is confirmed.
json copy
// data field
{
"sessionType": "Race",
"sessionName": "2026 Monaco Grand Prix — Race",
"winner": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
}
}overtakeRace / Sprint
A driver gains a position in live timing (provisional: a flicker swap-back or a pit stop right after can undo it; see overtake.confirmed). One event per car passed, never for cars in the pits or retired.
json copy
// data field
{
"overtakingDriver": {
"driverId": "antonelli-kimi",
"constructorId": "mercedes",
"number": "12",
"tla": "ANT",
"name": "Kimi Antonelli",
"team": "Mercedes",
"newPosition": 1,
"prevPosition": 2
},
"overtakenDriver": {
"driverId": "russell-george",
"constructorId": "mercedes",
"number": "63",
"tla": "RUS",
"name": "George Russell",
"team": "Mercedes",
"newPosition": 2,
"prevPosition": 1
}
}overtake.confirmedRace / Sprint
A pass has survived its 120 s lookahead (no flicker swap-back, neither car pitted) or the session ended: the final, never-retracted overtake.
json copy
// data field
{
"overtakingDriver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team",
"newPosition": 2,
"prevPosition": 3
},
"overtakenDriver": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing",
"newPosition": 3,
"prevPosition": 2
},
"lap": 42,
"passNumber": 61,
"passedAt": "2026-09-06T13:41:07.250Z",
"definition": "timing_pass_v1"
}overtake.countRace / Sprint
A driver's cumulative confirmed overtake count for the session increases; after the session, once more per driver (final: true) if the final re-run changed the total.
json copy
// data field
{
"driver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "1",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren"
},
"cumulativeOvertakes": 2
}overtake.attempt.startedRace / Sprint
A driver enters an active overtake attempt window (DRS pre-2026, Overtake Mode from 2026; OvertakeState = 2).
json copy
// data field
{
"attackingDriver": {
"driverId": "antonelli-kimi",
"constructorId": "mercedes",
"number": "12",
"tla": "ANT",
"name": "Kimi Antonelli",
"team": "Mercedes"
}
}overtake.attempt.resolvedRace / Sprint
An active overtake attempt window closes (OvertakeState drops below 2).
json copy
// data field
{
"attackingDriver": {
"driverId": "antonelli-kimi",
"constructorId": "mercedes",
"number": "12",
"tla": "ANT",
"name": "Kimi Antonelli",
"team": "Mercedes"
}
}lead.changeRace / Sprint
The race leader changes.
json copy
// data field
{
"newLeader": {
"driverId": "antonelli-kimi",
"constructorId": "mercedes",
"number": "12",
"tla": "ANT",
"name": "Kimi Antonelli",
"team": "Mercedes"
},
"previousLeader": {
"driverId": "russell-george",
"constructorId": "mercedes",
"number": "63",
"tla": "RUS",
"name": "George Russell",
"team": "Mercedes"
},
"viaOvertake": true
}battle.proximityRace / Sprint
A driver closes within overtake range of the car ahead (DRS pre-2026, Overtake Mode from 2026; gap ≤ 1.0 s).
json copy
// data field
{
"attackingDriver": {
"driverId": "leclerc-charles",
"constructorId": "ferrari",
"number": "16",
"tla": "LEC",
"name": "Charles Leclerc",
"team": "Ferrari"
},
"defendingDriver": {
"driverId": "hamilton-lewis",
"constructorId": "ferrari",
"number": "44",
"tla": "HAM",
"name": "Lewis Hamilton",
"team": "Ferrari"
},
"gapSeconds": 1.844,
"closingRateSecPerLap": 0.115,
"overrideAvailable": false,
"overrideRangeInLaps": 7.3
}positions.gainedRace / Sprint
A driver gains one or more positions (non-pit, detected from timing).
json copy
// data field
{
"driver": {
"driverId": "antonelli-kimi",
"constructorId": "mercedes",
"number": "12",
"tla": "ANT",
"name": "Kimi Antonelli",
"team": "Mercedes"
},
"gridPosition": 2,
"currentPosition": 1,
"positionsGained": 1
}positions.lostRace / Sprint
A driver loses one or more positions (non-pit, detected from timing).
json copy
// data field
{
"driver": {
"driverId": "russell-george",
"constructorId": "mercedes",
"number": "63",
"tla": "RUS",
"name": "George Russell",
"team": "Mercedes"
},
"gridPosition": 1,
"currentPosition": 2,
"positionsGained": -1
}pit.entryAll
Driver enters the pit lane.
json copy
// data field
{
"driver": {
"driverId": "russell-george",
"constructorId": "mercedes",
"number": "63",
"tla": "RUS",
"name": "George Russell",
"team": "Mercedes"
},
"positionBeforePit": 19,
"stopNumber": 1,
"compound": "SOFT",
"tyreAge": 32
}pit.exitAll
Driver exits the pit lane after a stop.
json copy
// data field
{
"driver": {
"driverId": "leclerc-charles",
"constructorId": "ferrari",
"number": "16",
"tla": "LEC",
"name": "Charles Leclerc",
"team": "Scuderia Ferrari"
},
"stopNumber": 2,
"positionAfterPit": 5
}pit.stop.completeAll
Official pit stop timing confirmed (from PitStop feed during live sessions).
json copy
// data field
{
"driver": {
"driverId": "colapinto-franco",
"constructorId": "alpine",
"number": "43",
"tla": "COL",
"name": "Franco Colapinto",
"team": "Alpine"
},
"lap": 30,
"stopNumber": 1,
"pitStopTimeMs": 3800,
"pitLaneTimeMs": 25640
}pit.fastestRace / Sprint
A driver sets the fastest pit lane time of the session.
json copy
// data field
{
"driver": {
"driverId": "piastri-oscar",
"constructorId": "mclaren",
"number": "81",
"tla": "PIA",
"name": "Oscar Piastri",
"team": "McLaren"
},
"pitLaneTimeSec": 24.1
}fastest.lapAll
A new session fastest lap is set.
json copy
// data field
{
"driver": {
"driverId": "antonelli-kimi",
"constructorId": "mercedes",
"number": "12",
"tla": "ANT",
"name": "Kimi Antonelli",
"team": "Mercedes"
},
"lapTime": {
"display": "1:21.447",
"ms": 81447
}
}fastest.lap.statsAll
Detailed breakdown of the current fastest lap holder's sectors and speed trap times.
json copy
// data field
{
"driver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
},
"lap": 51,
"lapTime": {
"display": "1:27.412",
"ms": 87412
},
"sectors": [
{
"position": 1,
"time": "28.441"
},
{
"position": 1,
"time": "31.204"
},
{
"position": 1,
"time": "27.767"
}
],
"speeds": {
"i1": {
"position": 1,
"speedKmh": 312.4
},
"i2": {
"position": 2,
"speedKmh": 287.1
},
"fl": {
"position": 1,
"speedKmh": 302.7
},
"st": {
"position": 1,
"speedKmh": 347.2
}
}
}retirementAll
A driver retires from the session.
json copy
// data field
{
"driver": {
"driverId": "russell-george",
"constructorId": "mercedes",
"number": "63",
"tla": "RUS",
"name": "George Russell",
"team": "Mercedes"
},
"positionAtRetirement": 19,
"pitsCompleted": 0,
"cause": null,
"causeRawMessage": null
}strategy.signalRace / Sprint
A potential undercut or overcut window is detected from team radio + timing data.
json copy
// data field
{
"driver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
},
"signals": [
"undercut_window"
],
"radioEventsLast3Min": 2,
"currentPosition": 2,
"compound": "MEDIUM",
"tyreAge": 22
}safety.car.deployedAll
Safety Car or Virtual Safety Car deployed; type is "full" (SC) or "virtual" (VSC).
json copy
// data field
{
"type": "virtual",
"previousStatus": "yellow",
"leader": {
"driverId": "antonelli-kimi",
"constructorId": "mercedes",
"number": "12",
"tla": "ANT",
"name": "Kimi Antonelli",
"team": "Mercedes"
}
}safety.car.clearedAll
Safety Car has returned to pit lane and track is green.
json copy
// data field
{
"previousType": "virtual",
"status": "ending",
"leader": {
"driverId": "antonelli-kimi",
"constructorId": "mercedes",
"number": "12",
"tla": "ANT",
"name": "Kimi Antonelli",
"team": "Mercedes"
}
}safety.car.risk.updatedRace
Every race-control message while the track is green: the probability that a Safety Car, VSC or red flag is deployed within the next 30 seconds.
json copy
// data field
{
"probability": 0.184,
"horizonSec": 30,
"lapEndProbability": 0.021,
"yellowSectors": 1,
"doubleYellowSectors": 1,
"secondsSinceYellow": 4,
"stoppedCarRecent": true,
"triggerMessage": "DOUBLE YELLOW IN TRACK SECTOR 7",
"model": "sc_onset_refresh_v1"
}red.flagAll
Red flag shown and session suspended.
json copy
// data field
{
"message": "RED FLAG"
}session.clock.pausedAll
Session clock stops counting down (e.g. red flag, pre-start).
json copy
// data field
{
"remaining": "0:42:11",
"utc": "2026-06-08T14:22:18.441Z"
}session.clock.resumedAll
Session clock resumes counting down after a pause.
json copy
// data field
{
"remaining": "0:42:11",
"utc": "2026-06-08T14:28:05.112Z"
}qualifying.hot_lap.startedQualifying / Sprint Shoot-out
A driver begins a timed flying lap in qualifying.
json copy
// data field
{
"driver": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing"
},
"segment": "Q3"
}qualifying.hot_lap.abortedQualifying / Sprint Shoot-out
A driver abandons their flying lap (slows, pits, yellow flag).
json copy
// data field
{
"driver": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing"
},
"segment": "Q3"
}qualifying.lap_improvementQualifying / Sprint Shoot-out
A driver sets a new personal best in the current qualifying segment.
json copy
// data field
{
"driver": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing"
},
"lapTime": {
"display": "1:09.872",
"ms": 69872
},
"improvementMs": -342,
"position": 1,
"segment": "Q3",
"lap": 6
}qualifying.driver_eliminatedQualifying
A driver is knocked out at the end of Q1 or Q2.
json copy
// data field
{
"driver": {
"driverId": "hamilton-lewis",
"constructorId": "ferrari",
"number": "44",
"tla": "HAM",
"name": "Lewis Hamilton",
"team": "Scuderia Ferrari"
},
"position": 16,
"lapTime": {
"display": "1:11.204",
"ms": 71204
},
"segment": "Q1",
"finalPosition": 16
}qualifying.pole_positionQualifying
Q3 ends and pole position is confirmed.
json copy
// data field
{
"driver": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing"
},
"lapTime": {
"display": "1:09.530",
"ms": 69530
},
"marginToP2Ms": 241
}qualifying.front_rowQualifying
Q3 ends and the top 3 starting positions are confirmed.
json copy
// data field
{
"results": [
{
"driver": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing"
},
"position": 1,
"lapTime": {
"display": "1:09.530",
"ms": 69530
}
},
{
"driver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
},
"position": 2,
"lapTime": {
"display": "1:09.771",
"ms": 69771
}
},
{
"driver": {
"driverId": "leclerc-charles",
"constructorId": "ferrari",
"number": "16",
"tla": "LEC",
"name": "Charles Leclerc",
"team": "Scuderia Ferrari"
},
"position": 3,
"lapTime": {
"display": "1:09.983",
"ms": 69983
}
}
]
}qualifying.session_completeQualifying / Sprint Shoot-out
Full qualifying order confirmed at session end.
json copy
// data field
{
"results": [
{
"driver": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing"
},
"lapTime": {
"display": "1:09.530",
"ms": 69530
},
"position": 1
},
{
"driver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
},
"lapTime": {
"display": "1:09.771",
"ms": 69771
},
"position": 2
},
{
"driver": {
"driverId": "leclerc-charles",
"constructorId": "ferrari",
"number": "16",
"tla": "LEC",
"name": "Charles Leclerc",
"team": "Scuderia Ferrari"
},
"lapTime": {
"display": "1:09.983",
"ms": 69983
},
"position": 3
}
]
}top.three.updateAll
The live top-3 leaderboard changes (position, gap, or fastest status).
json copy
// data field
{
"drivers": [
{
"position": 1,
"driver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
},
"lapTime": "1:27.412",
"gapToLeader": "",
"overallFastest": true
},
{
"position": 2,
"driver": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing"
},
"lapTime": "1:27.831",
"gapToLeader": "+4.819",
"overallFastest": false
},
{
"position": 3,
"driver": {
"driverId": "leclerc-charles",
"constructorId": "ferrari",
"number": "16",
"tla": "LEC",
"name": "Charles Leclerc",
"team": "Scuderia Ferrari"
},
"lapTime": "1:28.209",
"gapToLeader": "+8.211",
"overallFastest": false
}
]
}championship.prediction.updateRace / Sprint
Predicted championship standings change based on current race positions.
json copy
// data field
{
"leadersChanged": false,
"drivers": [
{
"driver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
},
"currentPoints": 148,
"projectedPoints": 173,
"currentPosition": 1,
"projectedPosition": 1,
"delta": 25
},
{
"driver": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing"
},
"currentPoints": 136,
"projectedPoints": 154,
"currentPosition": 2,
"projectedPosition": 2,
"delta": 18
}
]
}standings.readyRace / Sprint
Unofficial race results are available. They are derived from live lap timing data immediately after session end (official: false).
json copy
// data field
{
"raceId": "2026-monaco-r7",
"raceName": "2026 Monaco Grand Prix",
"resultCount": 20,
"official": false
}standings.updatedRace / Sprint
Official results, once confirmed, have been written. official: true. Replaces any prior unofficial standings.
json copy
// data field
{
"raceId": "2026-monaco-r7",
"raceName": "2026 Monaco Grand Prix",
"resultCount": 20,
"official": true
}investigation.openedAll
An FIA stewards investigation is opened against one or more drivers (UNDER INVESTIGATION or WILL BE INVESTIGATED race control message).
json copy
// data field
{
"cars": [
{
"driverId": "russell-george",
"constructorId": "mercedes",
"number": "63",
"tla": "RUS",
"name": "George Russell",
"team": "Mercedes"
}
],
"deferred": true,
"rawMessage": "FIA STEWARDS: INCIDENT INVOLVING CAR 63 (RUS) WILL BE INVESTIGATED AFTER THE RACE (16:47:47)"
}penalty.appliedAll
A time, drive-through, or stop-and-go penalty is issued to a driver by the stewards.
json copy
// data field
{
"driver": {
"driverId": "bortoleto-gabriel",
"constructorId": "audi",
"number": "5",
"tla": "BOR",
"name": "Gabriel Bortoleto",
"team": "Audi"
},
"penaltyType": "time",
"seconds": 5,
"reason": "VSC INFRINGEMENT",
"rawMessage": "FIA STEWARDS: 5 SECOND TIME PENALTY FOR CAR 5 (BOR) - VSC INFRINGEMENT"
}penalty.servedAll
A previously issued penalty has been served by the driver.
json copy
// data field
{
"driver": {
"driverId": "russell-george",
"constructorId": "mercedes",
"number": "63",
"tla": "RUS",
"name": "George Russell",
"team": "Mercedes-AMG Petronas F1 Team"
},
"penaltyType": "time",
"seconds": 5,
"reason": null,
"rawMessage": "FIA STEWARDS: PENALTY SERVED - 5 SECOND TIME PENALTY FOR CAR 63 (RUS)"
}lap.time.deletedAll
A lap time is deleted by the stewards for a track limits violation.
json copy
// data field
{
"driver": {
"driverId": "russell-george",
"constructorId": "mercedes",
"number": "63",
"tla": "RUS",
"name": "George Russell",
"team": "Mercedes"
},
"lapTime": "1:16.828",
"turn": 14,
"lapNumber": 24,
"isPitLap": false,
"rawMessage": "CAR 63 (RUS) TIME 1:16.828 DELETED - TRACK LIMITS AT TURN 14 LAP 24 16:40:29"
}overtake.enabledRace / Sprint
The overtake system (DRS / Overtake Mode) is enabled for the field.
json copy
// data field
{
"enabled": true
}overtake.disabledRace / Sprint
The overtake system (DRS / Overtake Mode) is disabled for the field (safety car, red flag, etc.).
json copy
// data field
{
"enabled": false
}team.double.stopRace / Sprint
Both drivers from the same constructor pit on the same lap (stacked or simultaneous stops).
json copy
// data field
{
"constructor": {
"constructorId": "mclaren",
"name": "McLaren F1 Team"
},
"drivers": [
{
"driver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
},
"stopNumber": 1
},
{
"driver": {
"driverId": "hamilton-lewis",
"constructorId": "ferrari",
"number": "44",
"tla": "HAM",
"name": "Lewis Hamilton",
"team": "Scuderia Ferrari"
},
"stopNumber": 1
}
],
"lap": 28
}strategy.crossoverRace / Sprint
An undercut or overcut outcome is confirmed: the pitting driver either emerged ahead (undercut) or behind (overcut) the car they were following before their stop.
json copy
// data field
{
"type": "undercut",
"pittedDriver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
},
"carGained": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing"
},
"lapsBetweenStops": 1,
"gapAtCrossoverSec": 1.4
}session.restart.scheduledAll
An official restart time is announced via race control after a red flag suspension.
json copy
// data field
{
"resumeAt": "14:30",
"resumeAtUtc": "2026-06-08T14:30:00.000Z",
"message": "RED FLAG - RACE RESTART EXPECTED AT 14:30"
}red.flag.clearingAll
The session is suspended under a red flag (intermediate state between red.flag and session.clock.resumed).
json copy
// data field
{
"message": "RACE SUSPENDED"
}qualifying.segment.startQualifying / Sprint Shoot-out
A qualifying segment (Q1, Q2, or Q3) officially begins.
json copy
// data field
{
"segment": "Q2",
"part": 2,
"utc": "2026-06-07T14:22:00.000Z"
}qualifying.segment.endQualifying / Sprint Shoot-out
A qualifying segment ends and drivers' times in that segment are final.
json copy
// data field
{
"segment": "Q1",
"part": 1,
"utc": "2026-06-07T14:18:00.000Z"
}lapseries.position.gainedRace / Sprint
Official end-of-lap position gain confirmed from timing.lap-history data.
json copy
// data field
{
"driver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
},
"lap": 42,
"newPosition": 1,
"prevPosition": 2,
"positionsGained": 1
}lapseries.position.lostRace / Sprint
Official end-of-lap position loss confirmed from timing.lap-history data.
json copy
// data field
{
"driver": {
"driverId": "verstappen-max",
"constructorId": "red-bull-racing",
"number": "1",
"tla": "VER",
"name": "Max Verstappen",
"team": "Red Bull Racing"
},
"lap": 42,
"newPosition": 2,
"prevPosition": 1,
"positionsGained": 1
}driver.score.updateRace / Sprint
F1-provided driving style scores update for a driver (Brake, Throttle, Steering, etc.).
json copy
// data field
{
"driver": {
"driverId": "norris-lando",
"constructorId": "mclaren",
"number": "4",
"tla": "NOR",
"name": "Lando Norris",
"team": "McLaren F1 Team"
},
"currentPosition": 1,
"scores": {
"Brake": 8.2,
"Gforce Lat": 9.1,
"Gforce Long": 7.4,
"Steering": 8.8,
"Throttle": 9.4,
"Average": 8.6
}
}Handle deliveries race-events-handler.ts copy
// Express endpoint
app.post("/race-events", express.raw({ type: "application/json" }), (req, res) => {
// events.race is a paid feed: every POST is batch-v1, {"events":[{seq, feed, data}, ...]}; the event payload is each entry's data.
const { events } = JSON.parse(req.body.toString());
for (const { data: payload } of events) switch (payload.event) {
case "overtake":
console.log(
`${payload.data.overtakingDriver.tla} (P${payload.data.overtakingDriver.newPosition}) overtook ${payload.data.overtakenDriver.tla}`
);
break;
case "pit.entry":
console.log(`${payload.data.driver.tla} into the pits on lap ${payload.lap}`);
break;
case "fastest.lap":
console.log(`Fastest lap: ${payload.data.driver.tla} ${payload.data.lapTime.display}`);
break;
case "safety.car.deployed":
console.log(`${payload.data.type} deployed, leader: ${payload.data.leader.tla}`);
break;
case "retirement":
console.log(`${payload.data.driver.tla} has retired after ${payload.data.pitsCompleted} stops`);
break;
case "qualifying.pole_position":
console.log(
`POLE: ${payload.data.driver.tla}, ${payload.data.lapTime.display} (+${(payload.data.marginToP2Ms / 1000).toFixed(3)}s to P2)`
);
break;
}
res.sendStatus(200);
});Filtering race events Use filters.drivers to scope race events to specific drivers. This is especially useful for fantasy scoring engines or fan apps that only care about a specific team or driver combination.
ℹ Position filters (positions.min / positions.max) are not applied to events.race deliveries, since events like safety.car.deployed are session-wide and have no single position to filter on.
session.timing: aggregated session state live session.timing aggregates TrackStatus, ExtrapolatedClock, LapCount, SessionData, and RaceControlMessages into a single coherent snapshot, delivered on every state change, so you have an up-to-date picture of the session without subscribing to multiple raw feeds. Every delivery is a full snapshot, not a diff.
json copy
{
"feed": "session.timing",
"sessionId": "2026-canada_r",
"utc": "2026-10-05T18:48:39.843Z",
"state": "racing",
"flag": "green",
"lap": 30,
"totalLaps": 68,
"sessionType": "Race",
"clock": {
"remaining": "01:59:59",
"extrapolating": true,
"utc": "2026-05-24T20:09:48.004Z"
},
"resumeAt": null,
"resumeAtUtc": null,
"qualifyingSegment": null
}Fields Field Type Description statestringDerived session state. See the state values below. flagstring"green" | "yellow" | "sc" | "vsc" | "red" | "checkered". Current track flag. lapnumberCurrent race lap number. 0 during the formation lap. totalLapsnumberTotal scheduled laps. 0 for timed sessions (practice, qualifying). sessionTypestring"Race" | "Sprint" | "Qualifying" | "Practice1" | "Practice2" | "Practice3". clockobject | nullSession clock: remaining time, extrapolating boolean, F1 server UTC. null before session start. clock.remainingstringRemaining session time in "H:MM:SS" format. clock.extrapolatingbooleantrue when F1 is extrapolating the clock (paused periods, formation lap). The value is an estimate. resumeAtstring | nullLocal time ("HH:MM") of an announced restart after a red flag. null otherwise. qualifyingSegmentnumber | null1, 2, or 3 for the active qualifying segment (Q1/Q2/Q3). null outside qualifying.
State values The state field is derived from the track status code, session started/finished flags, lap number, and qualifying segment. It is the recommended field for branching your integration logic.
State Description pre_sessionBefore the session has started. formation_lapRace/Sprint only. After session.start, before lap 1 begins. racingGreen flag, lap ≥ 1. yellow_flagTrackStatus code 2: yellow flag sector. safety_carTrackStatus code 4: Safety Car deployed. sc_endingTrackStatus code 7: Safety Car returning this lap. virtual_safety_carTrackStatus code 6: Virtual Safety Car. red_flagTrackStatus code 5: session suspended. qualifying_q1Q1 segment active. qualifying_q2Q2 segment active. qualifying_q3Q3 segment active. pausedSession suspended but not red-flagged (e.g. practice delay). finishedSession ended.
events.qualifying: qualifying-scoped events live events.qualifying delivers the qualifying-specific synthetic events (lap improvements, eliminations, pole position, front row, and session complete) as their own subscribable stream scoped to Qualifying and Sprint Shoot-out sessions. The same events also appear inline on events.race (the qualifying.* types above); subscribe to events.qualifying when you want only the qualifying stream.
fantasy.scores: provisional fantasy points live fantasy.scores pushes provisional fantasy points per driver, with the full component breakdown, whenever a score actually changes. A position swap, a driver taking their teammate, or a retirement counts as a change. A lap counter ticking over is not a change, so you get a frame when the board actually moves rather than one per ingest tick. Race and Sprint sessions only; a sprint scores on the compressed points table.
These are the same numbers GET /v1/fantasy/session/:sessionId/scores returns, from the same scoring function, so a pushed frame and a polled response never disagree. Components that are only settled at the flag (grid-derived points and the fastest-lap bonus) are null rather than 0 while the session runs: a zero would claim the driver scored nothing there. Full field reference on the Fantasy API page .
Sample arrives with the next session.