Historical API Public, no-authentication REST endpoints for F1 race data — results, standings, lap times, tyre stints, pit stops, and qualifying laps. Free to use, no API key required.
✦ No authentication required. All Historical API endpoints are public. No Authorization header, no token, no sign-up needed.
Base URL
https://api.racehooks.io/v1/historical/Cache
public, max-age=3600Pagination
?limit= (max 100) · ?offset=Response envelope Every response wraps its payload in an RHData object. All scalar values — numbers, years, positions, milliseconds — are serialised as strings .
Field Type Description RHData.seriesstringAlways "f1" RHData.urlstringCanonical URL of this request RHData.limitstringPage size used (serialised as string) RHData.offsetstringPage offset used (serialised as string) RHData.totalstringTotal records matching the query (serialised as string) RHData.<Table>objectData payload — SeasonTable, RaceTable, DriverTable, ConstructorTable, CircuitTable, or StandingsTable
ℹ Time formats: Lap and sector times use M:SS.mmm (or SS.mmm if under 1 minute). Race winner absolute time: H:MM:SS.mmm. Gap to leader: +S.mmm.
Quickstart curl https://api.racehooks.io/v1/historical/seasonsData coverage Field Type Description dataQualityTier"1"–"4"1=1950–94 (Wikipedia only) · 2=1995–2017 · 3=2018–22 · 4=2023+ (full telemetry ingest) Laps / Stints2019+Lap times, sector splits, tyre compounds, and stints require per-session ingest. Pre-2019 sessions return empty arrays. QualifyingLaps2019+Flying laps from Q1/Q2/Q3 (and sprint qualifying SQ1/SQ2/SQ3). Empty arrays for pre-2019 sessions. FastestLapvariesLap number, time, and average speed when available. Rank is not stored. PitStop.timeoptionalTime-of-day of pit entry — omitted when not stored. carNumberoptionalDerived from driver's current number. Omitted for pre-modern seasons or drivers without a permanent number.
All list endpoints support ?limit= (max 100) and ?offset=. Lap time, pit stop, stint, and qualifying lap endpoints default to limit=100; all others default to limit=30. The total field in the envelope reflects the count before pagination.
Note on lap pagination: /laps paginates by lap number , not by row. Each page contains complete timing data for all drivers on those laps.
Seasons List seasons GET /v1/historical/seasons
Returns all seasons in the database with the number of rounds per season.
json copy
{
"RHData": {
"series": "f1",
"url": "https://api.racehooks.io/v1/historical/seasons",
"limit": "30",
"offset": "0",
"total": "1",
"SeasonTable": {
"Seasons": [
{ "season": "2025", "rounds": "2" }
]
}
}
}Race calendar Season race calendar GET /v1/historical/:season/races
Race calendar for a season: round number, race name, date, official name, and circuit location.
Field Type Description :seasonintegerSeason year, e.g. 2025
json copy
{
"RHData": {
"series": "f1",
"url": "https://api.racehooks.io/v1/historical/2025/races",
"limit": "30",
"offset": "0",
"total": "2",
"RaceTable": {
"season": "2025",
"Races": [
{
"season": "2025",
"round": "1",
"raceName": "Bahrain Grand Prix",
"Circuit": {
"circuitId": "bahrain",
"circuitName": "Bahrain International Circuit",
"Location": { "lat": "26.0325", "long": "50.5106", "locality": "Sakhir", "country": "Bahrain" }
},
"date": "2025-03-16",
"officialName": "FORMULA 1 ARAMCO BAHRAIN GRAND PRIX 2025",
"dataQualityTier": "4"
}
]
}
}
}Race results Race results GET /v1/historical/:season/:round/results
Finish order, points, grid position, race time/gap, and fastest lap per driver.
Field Type Description :seasonintegerSeason year :roundintegerRound number within the season ?limitintegerPage size (default 30, max 100) ?offsetintegerPage offset
{
"RHData": {
"series": "f1",
"url": "https://api.racehooks.io/v1/historical/2025/1/results",
"limit": "30",
"offset": "0",
"total": "3",
"RaceTable": {
"season": "2025",
"round": "1",
"Races": [
{
"season": "2025",
"round": "1",
"raceName": "Bahrain Grand Prix",
"Circuit": { "circuitId": "bahrain", "circuitName": "Bahrain International Circuit", "Location": { "lat": "26.0325", "long": "50.5106", "locality": "Sakhir", "country": "Bahrain" } },
"date": "2025-03-16",
"Results": [
{
"position": "1",
"positionText": "1",
"points": "25",
"number": "1",
"Driver": { "driverId": "verstappen-max", "givenName": "Max", "familyName": "Verstappen", "permanentNumber": "1", "code": "VER", "dateOfBirth": "1997-09-30", "nationality": "Dutch", "activeFromYear": "2015" },
"Constructor": { "constructorId": "red-bull-racing", "name": "Red Bull Racing", "nationality": "Austrian", "lineageId": "red-bull-racing", "activeFromYear": "2005" },
"grid": "1",
"laps": "57",
"status": "Finished",
"Time": { "millis": "5523456", "time": "1:32:03.456" }
},
{
"position": "2",
"positionText": "2",
"points": "18",
"number": "4",
"Driver": { "driverId": "norris-lando", "givenName": "Lando", "familyName": "Norris" },
"Constructor": { "constructorId": "mclaren", "name": "McLaren" },
"grid": "3",
"laps": "57",
"status": "Finished",
"Time": { "time": "+12.345" }
}
]
}
]
}
}
}
Field Type Description positionstringFinishing position (numeric), or empty string for non-classified positionTextstringPosition text — mirrors position for classified drivers pointsstringChampionship points scored numberstringCar number — omitted when unavailable (pre-modern seasons) gridstringStarting grid position lapsstringLaps completed statusstringFinished | DNF | DSQ | DNS Time.millisstringRace winner only: absolute time in milliseconds Time.timestringWinner: H:MM:SS.mmm · Others: +S.mmm gap to leader FastestLapobjectLap number, time, and average speed — omitted when unavailable
Qualifying Qualifying results GET /v1/historical/:season/:round/qualifying
Grid position and Q1/Q2/Q3 session times per driver.
Field Type Description :seasonintegerSeason year :roundintegerRound number ?limitintegerPage size (default 30, max 100) ?offsetintegerPage offset
json copy
{
"RHData": {
"RaceTable": {
"season": "2025",
"round": "1",
"Races": [
{
"season": "2025",
"round": "1",
"raceName": "Bahrain Grand Prix",
"QualifyingResults": [
{
"position": "1",
"Driver": { "driverId": "verstappen-max", "givenName": "Max", "familyName": "Verstappen", "code": "VER" },
"Constructor": { "constructorId": "red-bull-racing", "name": "Red Bull Racing" },
"Q1": "1:30.100",
"Q2": "1:29.500",
"Q3": "1:28.979"
},
{
"position": "2",
"Driver": { "driverId": "leclerc-charles", "givenName": "Charles", "familyName": "Leclerc", "code": "LEC" },
"Constructor": { "constructorId": "ferrari", "name": "Ferrari" },
"Q1": "1:30.400",
"Q2": "1:29.700",
"Q3": "1:29.124"
}
]
}
]
}
}
}
Field Type Description positionstringQualifying position Q1stringBest Q1 lap time in M:SS.mmm format Q2stringBest Q2 lap time — omitted if driver did not participate Q3stringBest Q3 lap time — omitted if driver did not participate
Qualifying lap times GET /v1/historical/:season/:round/qualifying/laps2019+
Individual flying laps from Q1/Q2/Q3 (and sprint qualifying SQ1/SQ2/SQ3) with sector splits, tyre compound, and tyre age. Returns empty when per-session data is not available (pre-2019).
Field Type Description :seasonintegerSeason year :roundintegerRound number ?driverstringFilter by driver slug (e.g. verstappen-max) ?sessionstringFilter by session key: Q1, Q2, Q3, SQ1, SQ2, SQ3 ?limitintegerPage size (default 100, max 100) ?offsetintegerPage offset
json copy
{
"RHData": {
"RaceTable": {
"season": "2025",
"round": "1",
"Races": [
{
"season": "2025",
"round": "1",
"raceName": "Bahrain Grand Prix",
"QualifyingLaps": [
{
"driverId": "norris-lando",
"session": "Q3",
"lapNumber": "1",
"time": "1:29.200",
"compound": "SOFT",
"tyreAgeLaps": "1"
},
{
"driverId": "verstappen-max",
"session": "Q3",
"lapNumber": "1",
"time": "1:28.979",
"sector1": "26.500",
"sector2": "32.200",
"sector3": "30.279",
"compound": "SOFT",
"tyreAgeLaps": "1"
}
]
}
]
}
}
}
Field Type Description driverIdstringDriver slug sessionstringSession key (Q1, Q2, Q3, SQ1, SQ2, SQ3) lapNumberstringLap number within this qualifying session timestringLap time in M:SS.mmm format sector1/2/3stringSector times — omitted when unavailable compoundstringTyre compound: SOFT, MEDIUM, HARD, INTER, WET — omitted when unavailable tyreAgeLapsstringLaps on this set of tyres before this lap — omitted when unavailable trackStatusstringF1 track status code (1=clear, 2=yellow, etc.) — omitted when unavailable
Lap times Lap times GET /v1/historical/:season/:round/laps2019+
Per-lap timing data for all drivers, grouped by lap number. Includes sector splits, tyre compound, tyre life, gap to leader, and track status. Returns empty for pre-2019 sessions.
Field Type Description :seasonintegerSeason year :roundintegerRound number ?driverstringFilter to a single driver slug ?limitintegerNumber of lap numbers to return (default 100, max 100) ?offsetintegerLap number offset (paginates by distinct lap, not by row)
json copy
{
"RHData": {
"series": "f1",
"url": "https://api.racehooks.io/v1/historical/2025/1/laps?limit=1",
"limit": "1",
"offset": "0",
"total": "2",
"RaceTable": {
"season": "2025",
"round": "1",
"Races": [
{
"season": "2025",
"round": "1",
"raceName": "Bahrain Grand Prix",
"Laps": [
{
"number": "1",
"Timings": [
{
"driverId": "verstappen-max",
"position": "1",
"time": "1:36.500",
"sector1": "28.500",
"sector2": "35.000",
"sector3": "33.000",
"compound": "SOFT",
"tyreLife": "1",
"trackStatus": "1"
},
{
"driverId": "norris-lando",
"position": "2",
"time": "1:37.100",
"compound": "SOFT",
"tyreLife": "1",
"gapToLeader": "+0.600"
}
]
}
]
}
]
}
}
}
Field Type Description Laps[].numberstringLap number Timings[].driverIdstringDriver slug Timings[].positionstringRace position at end of this lap Timings[].timestringLap time in M:SS.mmm format Timings[].sector1/2/3stringSector times — omitted when unavailable Timings[].compoundstringTyre compound — omitted when unavailable Timings[].tyreLifestringLaps on current set (1 = first lap on these tyres) Timings[].isPitOutLap"true"Present only on pit-out laps Timings[].trackStatusstringF1 track status code — omitted when unavailable Timings[].gapToLeaderstring+S.mmm gap to race leader — omitted when unavailable Timings[].gapToCarAheadstring+S.mmm gap to the car immediately ahead — omitted when unavailable
# All laps for a driver
curl "https://api.racehooks.io/v1/historical/2025/1/laps?driver=verstappen-max"
# Specific lap range
curl "https://api.racehooks.io/v1/historical/2025/1/laps?offset=20&limit=10"Pit stops Pit stops GET /v1/historical/:season/:round/pitstops
All pit stop records for a race: stop number, lap, duration. Optional driver filter.
Field Type Description :seasonintegerSeason year :roundintegerRound number ?driverstringFilter to a single driver slug ?limitintegerPage size (default 100, max 100) ?offsetintegerPage offset
json copy
{
"RHData": {
"RaceTable": {
"season": "2025",
"round": "1",
"Races": [
{
"season": "2025",
"round": "1",
"raceName": "Bahrain Grand Prix",
"PitStops": [
{ "driverId": "verstappen-max", "stop": "1", "lap": "22", "duration": "22.100" },
{ "driverId": "norris-lando", "stop": "1", "lap": "24", "duration": "23.400" }
]
}
]
}
}
}
Field Type Description driverIdstringDriver slug stopstringStop number for this driver (1-indexed) lapstringLap on which the stop occurred timestringTime of day of pit entry (H:MM:SS.mmm) — omitted when unavailable durationstringStationary time in the pit box in M:SS.mmm format
Tyre stints Tyre stints GET /v1/historical/:season/:round/stints2019+
Tyre stint data per driver: stint number, lap range, compound, and tyre age at stint start. Returns empty for pre-2019 sessions.
Field Type Description :seasonintegerSeason year :roundintegerRound number ?driverstringFilter to a single driver slug ?limitintegerPage size (default 100, max 100) ?offsetintegerPage offset
json copy
{
"RHData": {
"RaceTable": {
"season": "2025",
"round": "1",
"Races": [
{
"season": "2025",
"round": "1",
"raceName": "Bahrain Grand Prix",
"Stints": [
{ "driverId": "verstappen-max", "stint": "1", "lapStart": "1", "lapEnd": "22", "compound": "SOFT", "tyreAgeAtStart": "0" },
{ "driverId": "verstappen-max", "stint": "2", "lapStart": "23", "lapEnd": "57", "compound": "MEDIUM", "tyreAgeAtStart": "0" },
{ "driverId": "norris-lando", "stint": "1", "lapStart": "1", "lapEnd": "24", "compound": "SOFT", "tyreAgeAtStart": "0" },
{ "driverId": "norris-lando", "stint": "2", "lapStart": "25", "lapEnd": "57", "compound": "MEDIUM", "tyreAgeAtStart": "0" }
]
}
]
}
}
}
Field Type Description driverIdstringDriver slug stintstringStint number for this driver (1-indexed) lapStartstringFirst lap of this stint lapEndstringLast lap of this stint compoundstringTyre compound: SOFT, MEDIUM, HARD, INTER, WET tyreAgeAtStartstringLaps already on these tyres when the stint began (0 = new set)
Standings Driver standings GET /v1/historical/:season/driverStandings
Driver championship standings for a season. The wins count is computed dynamically from race results (not a stored column), so it always reflects the authoritative finish data.
Field Type Description :seasonintegerSeason year ?limitintegerPage size (default 30, max 100) ?offsetintegerPage offset
json copy
{
"RHData": {
"series": "f1",
"url": "https://api.racehooks.io/v1/historical/2025/driverStandings",
"limit": "30",
"offset": "0",
"total": "3",
"StandingsTable": {
"season": "2025",
"StandingsLists": [
{
"season": "2025",
"round": "2",
"DriverStandings": [
{
"position": "1",
"positionText": "1",
"points": "43",
"wins": "1",
"Driver": { "driverId": "verstappen-max", "givenName": "Max", "familyName": "Verstappen", "permanentNumber": "1", "code": "VER", "nationality": "Dutch" },
"Constructors": [{ "constructorId": "red-bull-racing", "name": "Red Bull Racing", "nationality": "Austrian" }]
},
{
"position": "2",
"positionText": "2",
"points": "36",
"wins": "0",
"Driver": { "driverId": "norris-lando", "givenName": "Lando", "familyName": "Norris", "code": "NOR", "nationality": "British" },
"Constructors": [{ "constructorId": "mclaren", "name": "McLaren", "nationality": "British" }]
}
]
}
]
}
}
}
Field Type Description StandingsLists[].roundstringLast round number included in this dataset DriverStandings[].positionstringChampionship position DriverStandings[].pointsstringPoints total DriverStandings[].winsstringRace wins (computed from race results) DriverStandings[].DriverobjectDriver object — see Driver reference DriverStandings[].ConstructorsarrayArray containing the driver's current constructor
Constructor standings GET /v1/historical/:season/constructorStandings
Constructor championship standings. Engine-suffix duplicates (e.g. McLaren-Mercedes and McLaren-Renault for the same lineage) are automatically collapsed into a single entry. Wins are aggregated across all constructor variants sharing a lineageId.
Field Type Description :seasonintegerSeason year ?limitintegerPage size (default 30, max 100) ?offsetintegerPage offset
json copy
{
"RHData": {
"StandingsTable": {
"season": "2025",
"StandingsLists": [
{
"season": "2025",
"round": "2",
"ConstructorStandings": [
{
"position": "1",
"positionText": "1",
"points": "43",
"wins": "1",
"Constructor": { "constructorId": "red-bull-racing", "name": "Red Bull Racing", "nationality": "Austrian", "lineageId": "red-bull-racing", "activeFromYear": "2005" }
},
{
"position": "2",
"positionText": "2",
"points": "36",
"wins": "0",
"Constructor": { "constructorId": "mclaren", "name": "McLaren", "nationality": "British", "lineageId": "mclaren", "activeFromYear": "1966" }
}
]
}
]
}
}
}
Field Type Description ConstructorStandings[].winsstringRace wins (aggregated by lineageId across all engine variants) Constructor.lineageIdstringStable identifier across engine-suffix name changes. Use this for cross-season queries.
Reference objects Driver object GET /v1/historical/drivers
GET /v1/historical/drivers/:driverId
Returns all drivers in the database, or a single driver by slug.
json copy
{
"RHData": {
"series": "f1",
"url": "https://api.racehooks.io/v1/historical/drivers",
"limit": "30",
"offset": "0",
"total": "3",
"DriverTable": {
"Drivers": [
{
"driverId": "leclerc-charles",
"givenName": "Charles",
"familyName": "Leclerc",
"permanentNumber": "16",
"code": "LEC",
"dateOfBirth": "1997-10-16",
"nationality": "Monégasque",
"activeFromYear": "2018"
},
{
"driverId": "norris-lando",
"givenName": "Lando",
"familyName": "Norris",
"permanentNumber": "4",
"code": "NOR",
"dateOfBirth": "1999-11-13",
"nationality": "British",
"activeFromYear": "2019"
}
]
}
}
}
Field Type Description driverIdstringRaceHooks driver slug (forename-surname, lowercase) givenNamestringFirst name familyNamestringLast name permanentNumberstringPermanent car number codestring3-letter TLA (e.g. VER) dateOfBirthstringISO 8601 date (YYYY-MM-DD) nationalitystringNationality activeFromYearstringSeason of first race activeToYearstringSeason of last race — omitted for active drivers
Constructor object GET /v1/historical/constructors
GET /v1/historical/constructors/:constructorId
Field Type Description constructorIdstringRaceHooks constructor slug namestringConstructor name as it appears in historical records nationalitystringNationality lineageIdstringStable lineage identifier — use this for cross-season queries activeFromYearstringSeason of first race entry activeToYearstringSeason of last race entry — omitted for active constructors
Circuit object GET /v1/historical/circuits
GET /v1/historical/circuits/:circuitId
Field Type Description circuitIdstringRaceHooks circuit slug (e.g. bahrain, albert-park) circuitNamestringFull circuit name Location.latstringLatitude (decimal degrees) Location.longstringLongitude (decimal degrees) Location.localitystringCity or locality name Location.countrystringCountry name
All routes Endpoint Description Default limit Filters /historical/seasonsAll seasons with round count 30 /historical/:season/racesSeason race calendar 30 /historical/:season/:round/resultsRace results 30 /historical/:season/:round/qualifyingQualifying results (Q1/Q2/Q3) 30 /historical/:season/:round/qualifying/lapsQualifying flying laps 100 ?driver, ?session /historical/:season/:round/lapsPer-lap timings (by lap number) 100 ?driver /historical/:season/:round/pitstopsPit stop records 100 ?driver /historical/:season/:round/stintsTyre stint data 100 ?driver /historical/:season/driverStandingsDriver championship standings 30 /historical/:season/constructorStandingsConstructor championship standings 30 /historical/driversAll drivers 30 /historical/drivers/:driverIdSingle driver by slug 1 /historical/constructorsAll constructors 30 /historical/constructors/:constructorIdSingle constructor by slug 1 /historical/circuitsAll circuits 30 /historical/circuits/:circuitIdSingle circuit by slug 1