# Driver and Team Profile Guide

> **🏎️ Motorsport API Required**
>
> This guide requires an active Motorsport API subscription (€79/mo, 3,000 API calls/hr).
>
> [View pricing →](https://www.sportmonks.com/formula-one-api/)

This guide walks through how to build driver and team profile pages using the Motorsport API - combining biographical data, current season context, championship standings, and race results into rich, data-driven profiles.

**What you'll learn:**

* How to look up driver and team IDs by name
* How to build a complete driver profile with biographical data, current team, and standings
* How to build a complete team profile with constructor data, current drivers, and standings
* How to enrich profiles with season race results

**Prerequisites:** Active Motorsport API subscription, API token, familiarity with REST APIs

### 1. When to use driver and team profiles

This approach is well suited to:

* Driver profile pages showing career details, current team, championship position, and season results
* Constructor profile pages showing team identity, current driver lineup, and championship standing
* Fantasy F1 applications displaying driver cards with points and recent form
* Comparison tools contrasting two drivers or constructors across a season

Profile data is relatively stable - driver biographical data rarely changes, and standings/results only update after each race weekend. Cache aggressively and refresh after race events.

### 2. Step 1: Look up the ID by name

Driver and team IDs are required for the standings and race results endpoints. Use the search endpoints to find them by name before making any other call.

**Search for a driver:**

```http
GET /v3/motorsport/drivers/search/norris?api_token=YOUR_TOKEN
```

**Search for a team:**

```http
GET /v3/motorsport/teams/search/mclaren?api_token=YOUR_TOKEN
```

Both search endpoints accept partial names and are case-insensitive. The `id` in the response is the value to use in all subsequent calls. For drivers, this is the same value referenced as `player_id` in race result lineups and `participant_id` in standings, laps, pitstops, and stints responses.

```javascript
async function searchDriver(name, token) {
  const res = await fetch(
    `https://api.sportmonks.com/v3/motorsport/drivers/search/${encodeURIComponent(name)}?api_token=${token}`
  );
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const { data } = await res.json();
  return data[0] ?? null; // First result is typically the closest match
}

async function searchTeam(name, token) {
  const res = await fetch(
    `https://api.sportmonks.com/v3/motorsport/teams/search/${encodeURIComponent(name)}
?api_token=${token}`
  );
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const { data } = await res.json();
  return data[0] ?? null;
}
```

### 3. Step 2: Build a driver profile

With the driver ID in hand, fetch the full profile in a single enriched call:

```http
GET /v3/motorsport/drivers/DRIVER_ID
?api_token=YOUR_TOKEN&include=teams.team;nationality;country;position;metadata
```

This returns:

* Biographical data: full name, date of birth, headshot image
* `nationality` - the country the driver represents
* `country` - the driver's country of birth (may differ from nationality)
* `teams.team` - the driver's current team with constructor name and logo
* `position` - the driver's role within the team (first driver, second driver, or test driver)
* `metadata` - additional profile data such as short name and debut information

Include depth on drivers is **3**. `teams.team` counts as 2 levels (`teams` → `team`), leaving one further level available.

Key fields to use in your UI:

| Field                      | Use for                                                        |
| -------------------------- | -------------------------------------------------------------- |
| `display_name`             | Full name on profile header (e.g. "Max Verstappen")            |
| `common_name`              | Compact name for cards and leaderboards (e.g. "M. Verstappen") |
| `image_path`               | Driver headshot image                                          |
| `date_of_birth`            | Age calculation and biography                                  |
| `nationality.name`         | Nationality flag and label                                     |
| `teams[0].team.name`       | Current constructor name                                       |
| `teams[0].team.image_path` | Constructor logo                                               |
| `position.name`            | Team role (first driver, second driver)                        |

### 4. Step 3: Get the driver's championship standing

With the driver's `participant_id` (same as their `id`) and the current season ID, fetch their championship position:

```http
GET /v3/motorsport/standings/drivers/seasons/25273
?api_token=YOUR_TOKEN&include=participant;stage
```

This returns standings for all drivers. Filter client-side by `participant_id` to isolate the specific driver:

```javascript
function getDriverStanding(standings, driverId) {
  return standings.find(s => s.participant_id === driverId) ?? null;
}
```

The `stage` include gives you the most recently completed race weekend - use `stage.name` and `stage.sort_order` to display "Championship position after Round X".

### 5. Step 4: Get the driver's season race results

Fetch the full season race result record for the driver using their ID and the season ID:

```http
GET /v3/motorsport/results/seasons/25273/drivers/DRIVER_ID?api_token=YOUR_TOKEN
```

This returns all race and sprint race fixtures for the season with the driver's lineup and result details embedded. No includes are available - all data is pre-embedded.

Paginate through all pages to get the complete season. Use `sort_order` on each stage to order rounds chronologically. Extract position and points from the `details` array on each lineup object, resolving `type_id` values via the [Results & Live Data Type Reference](https://docs.sportmonks.com/v3/motorsport-api/welcome/results-and-live-data-type-reference).

```javascript
async function getDriverResults(seasonId, driverId, token) {
  const BASE = 'https://api.sportmonks.com/v3/motorsport';
  const results = [];
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const res = await fetch(
      `${BASE}/results/seasons/${seasonId}/drivers/${driverId}?api_token=${token}&page=${page}`
    );
    if (!res.ok) throw new Error(`HTTP ${res.status}`);

    const payload = await res.json();
    results.push(...payload.data);

    hasMore = payload.pagination?.has_more ?? false;
    page++;
  }

  // Sort by calendar round and extract race fixtures only
  return results
    .sort((a, b) => a.sort_order - b.sort_order)
    .map(stage => {
      const raceFix = stage.fixtures?.find(f => f.name === 'Race');
      const lineup = raceFix?.lineups?.[0];
      const positionDetail = lineup?.details?.find(d => d.type_id === 9711);

      return {
        round: stage.sort_order,
        grand_prix: stage.name,
        fixture_id: raceFix?.id ?? null,
        grid_position: lineup?.grid_position ?? null,
        finish_position: positionDetail?.data?.position ?? null,
        driver_number: lineup?.driver_number ?? null
      };
    });
}
```

> `type_id: 9711` is the position result type confirmed from the live race results example (Norris P3 at Abu Dhabi). Verify all type IDs against the [Results & Live Data Type Reference](https://docs.sportmonks.com/v3/motorsport-api/welcome/results-and-live-data-type-reference) before deploying.

### 6. Building a team profile

#### Step 1: Fetch the team profile

```http
GET /v3/motorsport/teams/TEAM_ID
?api_token=YOUR_TOKEN&include=drivers.driver;country;seasonDetails;seasonDrivers
```

This returns:

* Team identity: name, short code, logo, founding year
* `country` - the country the team is registered in
* `drivers.driver` - current season driver lineup with full driver profiles
* `seasonDetails` - per-season car details, team principal, and branding
* `seasonDrivers` - driver participation details for the current season

Include depth on teams is **3**. `drivers.driver` counts as 2 levels, leaving one further level.

Key fields for your UI:

| Field                           | Use for                                      |
| ------------------------------- | -------------------------------------------- |
| `name`                          | Team name on profile header (e.g. "McLaren") |
| `short_code`                    | Compact constructor code (e.g. "MCL")        |
| `image_path`                    | Constructor logo                             |
| `type`                          | Power unit type (e.g. "hybrid")              |
| `drivers[].driver.display_name` | Current driver names                         |
| `drivers[].driver.image_path`   | Driver headshots                             |
| `country.name`                  | Constructor nationality                      |

#### Step 2: Get the constructor championship standing

```http
GET /v3/motorsport/standings/teams/seasons/25273
?api_token=YOUR_TOKEN&include=participant;stage
```

Filter by `participant_id` matching the team ID to isolate the specific constructor's standing. The `points` field contains the combined points of both drivers.

#### Step 3: Get the team's season race results

```http
GET /v3/motorsport/results/seasons/25273/teams/TEAM_ID?api_token=YOUR_TOKEN
```

The team results response differs from the driver results response in one important way: the `lineups` array for each fixture contains **both drivers** who raced for that team. This means you can show both drivers' results side by side for each race weekend from a single call.

```javascript
function extractTeamRaceResults(stages) {
  return stages
    .sort((a, b) => a.sort_order - b.sort_order)
    .map(stage => {
      const raceFix = stage.fixtures?.find(f => f.name === 'Race');

      const driverResults = (raceFix?.lineups ?? []).map(lineup => {
        const positionDetail = lineup.details?.find(d => d.type_id === 9711);
        return {
          driver_name: lineup.driver_name,
          driver_number: lineup.driver_number,
          grid_position: lineup.grid_position,
          finish_position: positionDetail?.data?.position ?? null,
          player_id: lineup.player_id
        };
      });

      return {
        round: stage.sort_order,
        grand_prix: stage.name,
        drivers: driverResults
      };
    });
}
```

### 7. Complete driver profile implementation

The following brings together all four steps for a driver profile page.

{% tabs %}
{% tab title="Javascript" %}

```javascript
const BASE = 'https://api.sportmonks.com/v3/motorsport';
const TOKEN = 'YOUR_API_TOKEN';
const SEASON_ID = 25273;

async function buildDriverProfile(driverName) {
  // Step 1: find the driver
  const searchRes = await fetch(
    `${BASE}/drivers/search/${encodeURIComponent(driverName)}?api_token=${TOKEN}`
  );
  const { data: searchResults } = await searchRes.json();
  if (!searchResults.length) throw new Error('Driver not found');
  const driverId = searchResults[0].id;

  // Steps 2-4: fetch in parallel
  const [profileRes, standingsRes] = await Promise.all([
    fetch(`${BASE}/drivers/${driverId}?api_token=${TOKEN}&include=teams.team;nationality;position`),
    fetch(`${BASE}/standings/drivers/seasons/${SEASON_ID}?api_token=${TOKEN}&include=participant;stage`)
  ]);

  const { data: profile } = await profileRes.json();
  const { data: allStandings } = await standingsRes.json();

  const standing = allStandings.find(s => s.participant_id === driverId);
  const results = await getDriverResults(SEASON_ID, driverId, TOKEN);

  return {
    id: profile.id,
    name: profile.display_name,
    common_name: profile.common_name,
    image: profile.image_path,
    dob: profile.date_of_birth,
    nationality: profile.nationality?.name ?? null,
    team: profile.teams?.[0]?.team?.name ?? null,
    team_logo: profile.teams?.[0]?.team?.image_path ?? null,
    position: profile.position?.name ?? null,
    championship_position: standing?.position ?? null,
    championship_points: standing?.points ?? null,
    standings_as_of: standing?.stage?.name ?? null,
    race_results: results
  };
}
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

BASE = 'https://api.sportmonks.com/v3/motorsport'
TOKEN = 'YOUR_API_TOKEN'
SEASON_ID = 25273

def build_driver_profile(driver_name):
    # Step 1: find the driver
    search_res = requests.get(
        f'{BASE}/drivers/search/{driver_name}',
        params={'api_token': TOKEN},
        timeout=30
    )
    search_res.raise_for_status()
    search_results = search_res.json()['data']

    if not search_results:
        raise ValueError('Driver not found')

    driver_id = search_results[0]['id']

    # Step 2: fetch profile
    profile_res = requests.get(
        f'{BASE}/drivers/{driver_id}',
        params={
            'api_token': TOKEN,
            'include': 'teams.team;nationality;position'
        },
        timeout=30
    )
    profile_res.raise_for_status()
    profile = profile_res.json()['data']

    # Step 3: fetch standings
    standings_res = requests.get(
        f'{BASE}/standings/drivers/seasons/{SEASON_ID}',
        params={'api_token': TOKEN, 'include': 'participant;stage'},
        timeout=30
    )
    standings_res.raise_for_status()
    all_standings = standings_res.json()['data']
    standing = next(
        (s for s in all_standings if s['participant_id'] == driver_id),
        None
    )

    teams = profile.get('teams', [])
    current_team = teams[0].get('team') if teams else None

    return {
        'id': profile['id'],
        'name': profile['display_name'],
        'common_name': profile['common_name'],
        'image': profile['image_path'],
        'dob': profile['date_of_birth'],
        'nationality': profile.get('nationality', {}).get('name'),
        'team': current_team.get('name') if current_team else None,
        'team_logo': current_team.get('image_path') if current_team else None,
        'championship_position': standing['position'] if standing else None,
        'championship_points': standing['points'] if standing else None,
        'standings_as_of': standing.get('stage', {}).get('name') if standing else None
    }
```

{% endtab %}
{% endtabs %}

### 8. Common pitfalls

**Using `name` instead of `display_name` for UI display**

The `name` field and `display_name` field often contain the same value but `display_name` is explicitly the field intended for application display. Use `display_name` for profile headers and `common_name` for compact timing-style displays.

**Assuming `teams[0]` is always the current team**

The `teams` include returns the driver's participation for the current season. In most cases this is a single entry, but always access it safely with optional chaining or a null check rather than assuming the array is populated.

**Mixing up driver `id` and `participant_id`**

The driver's `id` from the Drivers endpoint is the same value as `player_id` in race result lineups and `participant_id` in standings, laps, pitstops, and stints responses. These are three names for the same value. Always use the driver `id` as your cross-endpoint join key.

**Fetching team results and expecting one driver per race**

Unlike the driver results endpoint, the team results endpoint returns both drivers' lineups for each fixture. Your data processing must handle a `lineups` array with multiple entries per fixture, not just one.

**Not paginating race results**

Race results paginate at the stage level. A 24-round season will return results across multiple pages. Always paginate to get the complete season record.

### 9. Related features

* [Drivers](https://docs.sportmonks.com/v3/motorsport-api/endpoints-and-entities/endpoints/drivers) - Driver endpoints and field reference
* [Teams](https://docs.sportmonks.com/v3/motorsport-api/endpoints-and-entities/endpoints/teams) - Team endpoints and field reference
* [Standings](https://docs.sportmonks.com/v3/motorsport-api/endpoints-and-entities/endpoints/standings) - Driver and constructor championship standings
* [Race Results](https://docs.sportmonks.com/v3/motorsport-api/endpoints-and-entities/endpoints/race-results) - Season race result records
* [Season Dashboard Guide](https://docs.sportmonks.com/v3/motorsport-api/tutorials-and-guides/guides/season-dashboard) - Season-level data patterns
* [Results & Live Data Type Reference](https://docs.sportmonks.com/v3/motorsport-api/welcome/results-and-live-data-type-reference)
* [Metadata & Per-Season Data Type Reference](https://docs.sportmonks.com/v3/motorsport-api/welcome/metadata-and-per-season-data-type-reference)

### 10. FAQ

**Q: How do I get a driver's age from `date_of_birth`?**

`date_of_birth` is a `YYYY-MM-DD` string. Calculate age in your application by comparing it to the current date. Do not store a pre-calculated age value as it will become stale.

**Q: The `height` and `weight` fields are null - is this expected?**

Yes. These fields are present in the schema but sparsely populated. The search endpoint example shows `height: 181` and `weight: 72` for Verstappen, so data exists for some drivers. Always handle `null` gracefully in your application.

**Q: How do I know which team a driver raced for in a past season?**

The `teams` include returns current season participation. For historical team data, use the Race Results endpoint for that season - the `team_id` field in each lineup object shows which constructor the driver raced for in that specific race.

**Q: Can I get a team's full historical driver roster across multiple seasons?**

Use `?include=seasons` on the team to get all seasons, then call the Race Results endpoint for each season using the team ID. The `lineups` array in each fixture shows all drivers who raced for that team.

**Q: Is this available in all subscription plans?**

All Motorsport API endpoints require an active Motorsport API subscription (€79/mo). [View pricing →](https://www.sportmonks.com/formula-one-api/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sportmonks.com/v3/motorsport-api/tutorials-and-guides/guides/driver-and-team-profile-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
