Contents
What makes the Motorsport API different?
Unlike traditional sports APIs, motorsport data has unique characteristics that require specialised endpoints and data structures:
– Granular timing data: Access lap-by-lap timing, sector times, and detailed telemetry
– Race strategy tracking: Monitor pit stops, tyre stints, and strategic decisions in real-time
– Multi-session events: Handle practice sessions, qualifying, sprint races, and main races
– Live race states: Track races as they unfold with real-time updates
– Rich relational data: Use the powerful includes system to pull related data in a single request
Getting started
1. Create your account and generate an API token
Before making any requests, you’ll need an API token. This is your unique key for authenticating with the Sportmonks API.
Steps to generate your token:
- Visit MySportmonks and create an account.
- Navigate to the API section in your dashboard.
- Select “Tokens” from the dropdown menu.
- Enter a name for your token (e.g., “My Racing App”)
- Click “Generate Token”
Important security notes:
– Your token has no expiration date and remains valid until you delete it.
– Store your token securely (use environment variables, never hardcode it)
– Never expose your token in client-side code, logs, or version control.
– Use a backend/proxy server to handle API communication in web applications.
2. Understanding the API structure
The Motorsport API follows a consistent structure across all endpoints:
Base URL:
https://api.sportmonks.com/v3/motorsport
Request format:
https://api.sportmonks.com/v3/motorsport/{endpoint}?api_token=YOUR_TOKEN&{parameters}
Authentication methods:
You can authenticate in two ways (both count toward the same rate limit):
Option 1: Query parameter (simple)
const url = 'https://api.sportmonks.com/v3/motorsport/fixtures?api_token=YOUR_TOKEN';
Option 2: Authorization header (recommended for production)
const response = await fetch('https://api.sportmonks.com/v3/motorsport/fixtures', {
headers: {
'Authorization': 'YOUR_TOKEN',
'Accept': 'application/json'
}
});
3. Making your first request
Let’s fetch all upcoming F1 races:
const API_TOKEN = 'your_token_here'; // Store this securely!
async function getUpcomingRaces() {
const url = `https://api.sportmonks.com/v3/motorsport/fixtures?api_token=${API_TOKEN}`;
try {
const response = await fetch(url);
const data = await response.json();
console.log('Upcoming Races:', data.data);
return data.data;
} catch (error) {
console.error('Error fetching races:', error);
}
}
getUpcomingRaces();
Example response structure:
{
"data": [
{
"id": 123456,
"name": "Bahrain Grand Prix 2024",
"starting_at": "2024-03-02 15:00:00",
"state_id": 1,
"stage_id": 5001,
"venue_id": 12
}
],
"subscription": [
{
"meta": {},
"plans": []
}
],
"rate_limit": {
"resets_in_seconds": 3421,
"remaining": 2997,
"requested_entity": "Fixture"
}
}
Notice the rate_limit object in the response? The default plan provides 3,000 API calls per entity per hour. The rate limit resets one hour after your first request.
Core concepts
Entities and relationships
The Motorsport API is built around interconnected entities. Understanding these relationships is key to using the API effectively:
– Leagues: The championship (e.g., Formula 1 World Championship)
– Seasons: A racing calendar year (e.g., 2025 F1 Season)
– Stages: Race weekends or specific sessions (practice, qualifying, race)
– Fixtures: Individual race events
– Venues: Circuits and tracks
– Teams: Constructor teams (e.g., Red Bull Racing, Mercedes)
– Drivers: Individual drivers
– Standings: Championship positions (drivers and constructors)
– Laps: Lap-by-lap timing data
– Pitstops: Pit stop information
– Stints: Tyre stint data
– States: Race/session status (scheduled, live, finished, etc.)
The power of includes
One of the most powerful features of the API is the include parameter. Instead of making multiple requests to get related data, you can enrich your response with a single call.
Basic usage:
// Get a race with driver and venue information
const url = `https://api.sportmonks.com/v3/motorsport/fixtures/123456?api_token=${API_TOKEN}&include=drivers,venue`;
Nested includes: You can go deeper with dot notation:
// Get fixtures with teams and their drivers
const url = `https://api.sportmonks.com/v3/motorsport/fixtures?api_token=${API_TOKEN}&include=teams.drivers`;
Common include combinations for motorsport:
// Live race tracking include=state,participants,laps,pitstops // Race results with full context include=drivers,teams,venue,standings,state // Historical analysis include=season,stage,laps,stints,pitstops // Championship standings include=drivers,teams,season
Best practices for includes:
– Only include what you need (reduces response size and improves performance)
– Check endpoint documentation for supported includes
– Monitor query complexity (complex includes may count as multiple API calls)
– Cache responses with heavy includes to avoid repeated requests.
Endpoint groups overview
The Motorsport API organises endpoints into logical groups. Here’s what each group provides:
Live data endpoints
Purpose: Real-time race information as events unfold
Key endpoints:
– GET /livescores – All currently live scores
Use cases:
– Live race trackers
– Real-time notifications
– Live timing displays
– Race state monitoring
Example:
async function getLiveRaces() {
const url = `https://api.sportmonks.com/v3/motorsport/livescores?api_token=${API_TOKEN}&include=state,participants,venue`;
const response = await fetch(url);
const data = await response.json();
data.data.forEach(race => {
console.log(`🔴 LIVE: ${race.name} - ${race.state.name}`);
});
}
Fixtures endpoints
Purpose: Race events (past, present, and future)
Key endpoints:
– GET /fixtures – All fixtures
– GET /fixtures/{id} – Specific race details
– GET /fixtures/date/{date} – Races on a specific date
– GET /fixtures/between/{start}/{end} – Races in a date range
Use cases:
– Race calendars
– Schedule displays
– Historical race data
– Event planning
Example:
async function getRaceCalendar(year = 2024) {
const startDate = `${year}-01-01`;
const endDate = `${year}-12-31`;
const url = `https://api.sportmonks.com/v3/motorsport/fixtures/between/${startDate}/${endDate}?api_token=${API_TOKEN}&include=venue,stage`;
const response = await fetch(url);
const data = await response.json();
console.log(`${data.data.length} races in ${year}`);
return data.data;
}
Teams endpoints
Purpose: Constructor/team information
Key endpoints:
– GET /teams – All teams
– GET /teams/{id} – Specific team details
– GET /teams/search/{name} – Search teams by name
Use cases:
– Team profiles
– Constructor comparisons
– Team historical data
– Brand/sponsor displays
Example:
async function getTeamWithDrivers(teamId) {
const url = `https://api.sportmonks.com/v3/motorsport/teams/${teamId}?api_token=${API_TOKEN}&include=drivers,venue`;
const response = await fetch(url);
const data = await response.json();
const team = data.data;
console.log(`${team.name} drivers:`, team.drivers);
return team;
}
Drivers endpoints
Purpose: Driver profiles and statistics
Key endpoints:
– GET /drivers – All drivers
– GET /drivers/{id} – Specific driver details
– GET /drivers/search/{name} – Search drivers by name
Use cases:
– Driver profiles
– Career statistics
– Driver comparisons
– Fantasy racing apps
Example:
async function getDriverStats(driverId) {
const url = `https://api.sportmonks.com/v3/motorsport/drivers/${driverId}?api_token=${API_TOKEN}&include=team,standings`;
const response = await fetch(url);
const data = await response.json();
const driver = data.data;
console.log(`${driver.name} - Current team: ${driver.team?.name}`);
return driver;
}
Laps endpoints
Purpose: Granular lap-by-lap timing data
Key endpoints:
– GET /fixtures/{fixture_id}/laps – Specific all laps for the given fixture
– GET /fixtures/{fixture_id}/laps/drivers/{driver_id} – All laps for the given fixture ID and driver ID
Use cases:
– Lap time analysis
– Race pace comparisons
– Fastest lap tracking
– Sector time analysis
– Performance graphs
Example:
async function analyzeLapTimes(fixtureId) {
const url = `https://api.sportmonks.com/v3/motorsport/fixtures/${fixtureId}/laps?api_token=${API_TOKEN}&include=driver`;
const response = await fetch(url);
const data = await response.json();
// Find fastest lap
const fastestLap = data.data.reduce((fastest, lap) =>
lap.time < fastest.time ? lap : fastest
);
console.log(`Fastest lap: ${fastestLap.driver.name} - ${fastestLap.time}s`);
return fastestLap;
}
Pitstops endpoints
Purpose: Pit stop information and strategy data
Key endpoints:
– GET /fixture/{fixture_id}/pitstops – All pitstops for the given fixture ID
– GET /fixture/{fixture_id}/pitstops/drivers/{driver_id} – All pitstops for the given fixture ID and driver ID
– GET /fixtures/{fixture_id}/pitstops/latest – The latest pitstops for the given fixture ID
Use cases:
– Strategy analysis
– Pit stop duration tracking
– Team performance comparison
– Race strategy visualisation
Example:
async function analyzePitStops(fixtureId) {
const url = `https://api.sportmonks.com/v3/motorsport//fixture/{fixture_id}/pitstop?api_token=${API_TOKEN}&include=driver,team`;
const response = await fetch(url);
const data = await response.json();
// Calculate average pit stop time per team
const teamPitStops = {};
data.data.forEach(stop => {
const teamName = stop.team.name;
if (!teamPitStops[teamName]) {
teamPitStops[teamName] = [];
}
teamPitStops[teamName].push(stop.duration);
});
Object.keys(teamPitStops).forEach(team => {
const avg = teamPitStops[team].reduce((a, b) => a + b, 0) / teamPitStops[team].length;
console.log(`${team} avg pit stop: ${avg.toFixed(2)}s`);
});
}
Stints endpoints
Purpose: Tire stint and strategy information
Key endpoints:
– GET /fixtures/{fixture_id}/stints – All stints for the given fixture ID
– GET /fixture/{fixture_id}/stints/drivers/{driver_id} – All stints for the given fixture ID and driver ID
– GET /stints/fixture/{fixture_id} – All stints for a race
Use cases:
– Tire strategy analysis
– Compound performance tracking
– Strategy comparisons
– Stint length analysis
async function analyzeStrategyStints(fixtureId) {
const url = `https://api.sportmonks.com/v3/motorsport/fixtures/{fixture_id}/stints?api_token=${API_TOKEN}&include=driver,team`;
const response = await fetch(url);
const data = await response.json();
// Group stints by driver
const driverStrategies = {};
data.data.forEach(stint => {
const driverName = stint.driver.name;
if (!driverStrategies[driverName]) {
driverStrategies[driverName] = [];
}
driverStrategies[driverName].push({
compound: stint.tyre_compound,
laps: stint.laps_completed
});
});
console.log('Race strategies:', driverStrategies);
return driverStrategies;
}
Standings endpoints
Purpose: Championship positions and points
Key endpoints:
– GET /drivers/standings – All the driver standings available
– GET /standings/drivers/seasons/{season_id} – The driver standings for a provided season ID
– GET /standings/teams – All the team standings available
Use cases
– Championship tables
– Points tracking
– Historical championship data
– Driver/constructor rankings
async function getChampionshipStandings(seasonId) {
const url = `https://api.sportmonks.com/v3/motorsport/standings/drivers/seasons/{season_id}?api_token=${API_TOKEN}&include=driver,team`;
const response = await fetch(url);
const data = await response.json();
console.log('Championship Standings:');
data.data.forEach((standing, index) => {
console.log(`${index + 1}. ${standing.driver?.name} - ${standing.points} points`);
});
return data.data;
}
Venues endpoints
Purpose: Circuit and track information
Key endpoints:
– GET /venues – All venues
– GET /venues/{id} – Specific venue details
– GET /venues/search/{name} – Search venues by name
Use cases:
– Circuit profiles
– Track characteristics
– Venue history
– Geographic data
Leagues endpoints
Purpose: Championship information
Key endpoints:
– GET /leagues – All leagues
– GET /leagues/{id} – Specific league details
Use cases:
– Championship metadata
– Series information
– League hierarchies
Seasons endpoints
Purpose: Calendar year racing seasons
Key endpoints:
– GET /seasons – All seasons
– GET /seasons/{id} – Specific season details
Use cases:
– Historical season data
– Calendar information
– Season comparisons
Schedules endpoints
Purpose: Race calendar organisation
Key endpoints:
– GET /schedules/season/{season_id} – Schedule for a season
Use cases:
– Race calendars
– Event planning
– Schedule displays
Stages endpoints
Purpose: Race weekend sessions (practice, qualifying, race)
Key endpoints:
– GET /stages – All stages
– GET /stages/{id} – Specific stage details
– GET /stages/season/{season_id} – All stages for a season
Use cases:
– Session tracking
– Multi-session events
– Practice/qualifying data
– Session type filtering
States endpoints
Purpose: Race and session status information
Key endpoints:
– GET /states – All possible states
– GET /states/{id} – Specific state details
States include:
– NS – Not Started
– LIVE – Currently racing
– FT – Finished
– CANCELLED – Cancelled
– POSTPONED – Postponed
Use cases:
– Race status tracking
– Live/finished filtering
– Event state management
Advanced features
Filtering
Filter responses to get exactly the data you need:
// Get only live fixtures
const url = `https://api.sportmonks.com/v3/motorsport/fixtures?api_token=${API_TOKEN}&filters=fixtureStates:LIVE`;
// Get fixtures for specific venues
const url = `https://api.sportmonks.com/v3/motorsport/fixtures?api_token=${API_TOKEN}&filters=venues:12,15,20`;
Field selection
Request only specific fields to reduce response size:
const url = `https://api.sportmonks.com/v3/motorsport/fixtures?api_token=${API_TOKEN}&select=id,name,starting_at`;
Pagination
Navigate through large datasets efficiently:
async function getAllFixtures() {
let allFixtures = [];
let hasMore = true;
let page = 1;
while (hasMore) {
const url = `https://api.sportmonks.com/v3/motorsport/fixtures?api_token=${API_TOKEN}&page=${page}`;
const response = await fetch(url);
const data = await response.json();
allFixtures = allFixtures.concat(data.data);
hasMore = data.pagination?.has_more || false;
page++;
}
return allFixtures;
}
Common use cases
Building a live race tracker
class LiveRaceTracker {
constructor(apiToken) {
this.apiToken = apiToken;
this.baseUrl = 'https://api.sportmonks.com/v3/motorsport';
}
async getCurrentLiveRaces() {
const url = `${this.baseUrl}/live?api_token=${this.apiToken}&include=state,participants,venue,laps.driver`;
const response = await fetch(url);
const data = await response.json();
return data.data;
}
async getRaceDetails(fixtureId) {
const url = `${this.baseUrl}/fixtures/${fixtureId}?api_token=${this.apiToken}&include=laps,pitstops,stints,participants`;
const response = await fetch(url);
const data = await response.json();
return data.data;
}
async pollForUpdates(fixtureId, callback, intervalMs = 5000) {
setInterval(async () => {
const raceData = await this.getRaceDetails(fixtureId);
callback(raceData);
}, intervalMs);
}
}
// Usage
const tracker = new LiveRaceTracker('YOUR_TOKEN');
tracker.pollForUpdates(123456, (data) => {
console.log('Race update:', data);
});
Creating a championship dashboard
async function buildChampionshipDashboard(seasonId) {
const baseUrl = 'https://api.sportmonks.com/v3/motorsport';
const token = 'YOUR_TOKEN';
// Get driver standings
const standingsResponse = await fetch(
`${baseUrl}/standings/drivers/seasons/{season_id}?api_token=${token}&include=driver,team`
);
const standings = await standingsResponse.json();
// Get upcoming races
const today = new Date().toISOString().split('T')[0];
const fixturesResponse = await fetch(
`${baseUrl}/fixtures?api_token=${token}&include=venue,state&filters=startDate:${today}`
);
const fixtures = await fixturesResponse.json();
return {
standings: standings.data,
upcomingRaces: fixtures.data,
lastUpdated: new Date()
};
}
Statistical analysis tool
async function analyzeDriverPerformance(driverId, seasonId) {
const baseUrl = 'https://api.sportmonks.com/v3/motorsport';
const token = 'YOUR_TOKEN';
// Get all fixtures for the season
const fixturesResponse = await fetch(
`${baseUrl}/fixtures?api_token=${token}&filters=seasons:${seasonId}`
);
const fixtures = await fixturesResponse.json();
// Get lap times for each race
const performanceData = [];
for (const fixture of fixtures.data) {
const lapsResponse = await fetch(
`${baseUrl}/laps/fixture/${fixture.id}?api_token=${token}&filters=drivers:${driverId}`
);
const laps = await lapsResponse.json();
if (laps.data.length > 0) {
const avgLapTime = laps.data.reduce((sum, lap) => sum + lap.time, 0) / laps.data.length;
const fastestLap = Math.min(...laps.data.map(l => l.time));
performanceData.push({
race: fixture.name,
avgLapTime,
fastestLap,
totalLaps: laps.data.length
});
}
}
return performanceData;
}
Fantasy racing platform
class FantasyRacingAPI {
constructor(apiToken) {
this.apiToken = apiToken;
this.baseUrl = 'https://api.sportmonks.com/v3/motorsport';
}
async getAvailableDrivers(seasonId) {
const url = `${this.baseUrl}/drivers?api_token=${this.apiToken}&include=team,standings&filters=seasons:${seasonId}`;
const response = await fetch(url);
const data = await response.json();
// Add fantasy points calculation based on standings
return data.data.map(driver => ({
id: driver.id,
name: driver.name,
team: driver.team?.name,
points: driver.standings?.[0]?.points || 0,
fantasyValue: this.calculateFantasyValue(driver)
}));
}
calculateFantasyValue(driver) {
// Custom fantasy points logic
const standings = driver.standings?.[0];
if (!standings) return 0;
return standings.points * 1.5; // Example calculation
}
async getWeekendResults(fixtureId) {
const url = `${this.baseUrl}/fixtures/${fixtureId}?api_token=${this.apiToken}&include=participants,standings,laps`;
const response = await fetch(url);
const data = await response.json();
return this.processFantasyPoints(data.data);
}
processFantasyPoints(fixtureData) {
// Process race results into fantasy points
// Example: points for position, fastest lap, etc.
return fixtureData.participants?.map(participant => ({
driverId: participant.id,
position: participant.meta?.position,
fantasyPoints: this.calculateRaceFantasyPoints(participant)
}));
}
calculateRaceFantasyPoints(participant) {
// Custom fantasy points for race finish
const positionPoints = {
1: 25, 2: 18, 3: 15, 4: 12, 5: 10,
6: 8, 7: 6, 8: 4, 9: 2, 10: 1
};
return positionPoints[participant.meta?.position] || 0;
}
}
Best practices
1. Efficient data fetching
Do:
– Use includes to reduce the number of requests.
– Implement caching for frequently accessed data.
– Use field selection to minimise response size.
– Filter at the API level rather than in your application.
Don’t:
– Make unnecessary requests in loops.
– Fetch the same data repeatedly.
– Include data you don’t need
– Ignore pagination for large datasets.
2. Error handling
async function safeApiCall(url) {
try {
const response = await fetch(url);
if (!response.ok) {
const errorData = await response.json();
switch (response.status) {
case 401:
throw new Error('Invalid API token');
case 403:
throw new Error('Access forbidden - check your plan permissions');
case 429:
throw new Error('Rate limit exceeded - please wait');
case 404:
throw new Error('Resource not found');
default:
throw new Error(`API error: ${errorData.message || response.statusText}`);
}
}
return await response.json();
} catch (error) {
console.error('API call failed:', error);
throw error;
}
}
3. Rate limit management
Monitor your rate limit usage:
function checkRateLimit(response) {
const rateLimit = response.rate_limit;
if (rateLimit.remaining < 100) {
console.warn(`Low API calls remaining: ${rateLimit.remaining}`);
console.warn(`Resets in: ${rateLimit.resets_in_seconds} seconds`);
}
return rateLimit;
}
4. Caching strategy
Implement smart caching to reduce API calls:
class CachedMotorsportAPI {
constructor(apiToken) {
this.apiToken = apiToken;
this.cache = new Map();
this.cacheDuration = 60000; // 1 minute in milliseconds
}
getCacheKey(endpoint, params) {
return `${endpoint}:${JSON.stringify(params)}`;
}
async fetch(endpoint, params = {}) {
const cacheKey = this.getCacheKey(endpoint, params);
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheDuration) {
console.log('Returning cached data');
return cached.data;
}
const url = new URL(`https://api.sportmonks.com/v3/motorsport${endpoint}`);
url.searchParams.append('api_token', this.apiToken);
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
const response = await fetch(url.toString());
const data = await response.json();
this.cache.set(cacheKey, {
data,
timestamp: Date.now()
});
return data;
}
}
5. Real-time updates
class LiveRacePoller {
constructor(apiToken, fixtureId) {
this.apiToken = apiToken;
this.fixtureId = fixtureId;
this.pollInterval = null;
this.lastState = null;
}
start(callback, intervalMs = 5000) {
this.pollInterval = setInterval(async () => {
const url = `https://api.sportmonks.com/v3/motorsport/fixtures/${this.fixtureId}?api_token=${this.apiToken}&include=state,laps.driver,pitstops`;
try {
const response = await fetch(url);
const data = await response.json();
const fixture = data.data;
// Only callback if state changed
if (JSON.stringify(fixture) !== JSON.stringify(this.lastState)) {
callback(fixture);
this.lastState = fixture;
}
// Stop polling if the race finished
if (fixture.state?.state === 'FT') {
this.stop();
}
} catch (error) {
console.error('Polling error:', error);
}
}, intervalMs);
}
stop() {
if (this.pollInterval) {
clearInterval(this.pollInterval);
this.pollInterval = null;
console.log('Stopped polling');
}
}
}
Understanding response codes

Migrating from Formula One API (V1)
If you’re currently using the older Formula One API v1, the Motorsport API v3 offers significant improvements:
Key differences
URL structure changed:
1. URL structure changed:
– Old: api.sportmonks.com/v1/formula-one
– New: api.sportmonks.com/v3/motorsport
2. More granular data:
– Lap-by-lap timing
– Detailed pit stop information
– Tire stint tracking
– Richer session data
3. Better response structure:
– Consistent JSON format across all endpoints
– Clearer entity relationships
– Type-safe data structures
4. Powerful includes system:
– Fetch related data in one request
– Nested includes support
– Reduced API calls needed
5. Improved filtering and selection:
– More flexible query options
– Better performance
– Reduced data transfer
Migration guide
For detailed migration instructions, see our Migration from Formula One API (v1) to Motorsport API v3 guide.
Additional resources
Documentation
– Full API Reference: https://docs.sportmonks.com/v3/motorsport-api
– Endpoint List: https://docs.sportmonks.com/v3/motorsport-api/endpoints-and-entities/endpoints
– Entity Documentation: https://docs.sportmonks.com/v3/motorsport-api/endpoints-and-entities/entities
Support
– Email Support: [email protected]
– Documentation: https://docs.sportmonks.com
– Account Dashboard: https://my.sportmonks.com
Important notes
– The Motorsport API v3 is currently in beta.
– Features and endpoints may receive updates.
– Contact support for any questions or issues
– Check the documentation regularly for updates.

