> For the complete documentation index, see [llms.txt](https://docs.sportmonks.com/v3/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sportmonks.com/v3/motorsport-api/tutorials-and-guides/guides/how-to-manage-query-complexity-in-the-motorsport-api.md).

# How to Manage Query Complexity in the Motorsport API

> **✅ Included in All Plans**
>
> Query complexity management applies to all plans.
>
> Plans differ only in leagues and API call limits.
>
> [Compare plans →](https://www.sportmonks.com/football-api/plans-pricing/)

This guide explains how query complexity works in the Motorsport API, how to read the complexity score on each endpoint, and how to restructure requests that exceed the threshold.

### When to use this

Read this guide when you:

* Receive a `422` error with a complexity-related message
* Want to understand why a particular include combination is rejected
* Are planning a heavy live-race request and want to avoid hitting the threshold
* Need to decide between one large request versus several smaller ones

### What query complexity Is

Every include you add to a request has a complexity score. The API sums these scores and rejects the request if the total exceeds the endpoint's threshold, returning a `422` status.

This is separate from your plan's rate limit (hourly call count). A complexity error means a single request is too expensive to process - it has nothing to do with how many requests you've made.

The complexity score for each include is listed on the individual endpoint documentation page, alongside the "Include depth" and "Include options" sections.

### Reading the complexity score

On each endpoint's documentation page, the include options section shows the allowed includes. The complexity score for each appears either inline or via the linked type reference. The `GET Laps by Fixture ID` endpoint, for example, lists `fixture`, `participant`, and `details` as its includes - each has a score that contributes to the total.

Before building a complex request, check:

1. The endpoint's maximum include depth
2. The complexity score of each include you intend to use
3. Whether your combination stays below the threshold

### Common motorsport include combinations

These are practical combinations tested against typical use cases, ordered from lightest to heaviest:

#### Live session - minimal (low complexity)

```
GET /v3/motorsport/livescores
?api_token={your_token}&include=state
```

Just the fixture state. Very light. Suitable for a session status indicator that only needs to know if a race is live or finished.

#### Live session - race order (moderate complexity)

```
GET /v3/motorsport/livescores
?api_token={your_token}&include=state;results
```

Adds driver positions, lap times, gaps, and tyre data via the `results` include. Good balance for a leaderboard display.

#### Live session - full timing (heavier)

```
GET /v3/motorsport/livescores
?api_token={your_token}&include=state;results;latestLaps
```

Adds the latest lap for each driver on top of the race order. Use this when you need lap-by-lap timing in your live display. Poll at a sensible interval (15+ seconds).

#### Live session - maximum enrichment (heaviest)

```
GET /v3/motorsport/livescores
?api_token={your_token}&include=state;results;latestLaps;latestPitstops;latestStints
```

Full live picture: positions, latest lap, latest pit stop, and current stint. This is the heaviest practical combination for a live race display. If this approaches or exceeds the threshold, split into two requests - one for `results` and a separate one for `latestLaps;latestPitstops`.

#### Standings with driver details (moderate)

```
GET /v3/motorsport/standings/drivers/seasons/{season_id}
?api_token={your_token}&include=participant;stage
```

Driver name, image, and the most recent race weekend context. Standard for a championship table display.

#### Fixture with lineup and driver details (moderate)

```
GET /v3/motorsport/fixtures/{id}
?api_token={your_token}&include=lineups.driver
```

Driver names and headshots for each car in the session. One level of nesting.

#### Fixture with lineup and nationality (heavier)

```http
GET /v3/motorsport/fixtures/{id}
?api_token={your_token}&include=lineups.driver;lineups.driver.country
```

Two nested includes on the same base entity. Adds nationality flag data per driver. Only do this once at session start and cache the result - driver nationalities do not change during a race.

### Reducing Complexity

If a request returns a `422` complexity error, try these strategies in order:

**Remove includes one at a time** to find which one tips you over. Start with the deepest or heaviest include.

**Use field selection** to reduce payload without removing the include entirely. `include=lineups.driver:display_name,image_path` requests only two fields from the driver entity instead of the full profile:

```http
GET /v3/motorsport/fixtures/{id}
?api_token={your_token}
&include=lineups.driver:display_name,image_path;lineups.driver.country:name,image_path
```

**Split into two requests** for enrichment data you only need once. Fetch lineup driver details at session start and cache them. During the live race, only poll for `results` and `latestLaps` - you already have the driver names.

**Cache stable data aggressively.** Driver names, team logos, venue details, and country flags do not change during a race. Fetch them once and store locally. Your live poll only needs the data that actually changes: positions, lap times, pit stops.

**Use the dedicated endpoints** for granular data instead of piling includes on the livescores endpoint. Rather than `include=laps` on a livescores call, use `GET Laps by Fixture ID` separately after you have the fixture ID.

### Practical caching strategy for a live race

```javascript
// At session start - fetch once, cache locally
const [lineups, venue] = await Promise.all([
  fetch(`${BASE}/fixtures/${FIXTURE_ID}?api_token=${TOKEN}&include=lineups.driver:display_name,common_name,image_path`),
  fetch(`${BASE}/fixtures/${FIXTURE_ID}?api_token=${TOKEN}&include=venue`)
]);

const driverMap = buildDriverMap(await lineups.json()); // { participantId: driverInfo }
const venueInfo = (await venue.json()).data.venue;

// During the race - poll with lightweight includes only
setInterval(async () => {
  const live = await fetch(
    `${BASE}/livescores?api_token=${TOKEN}&include=state;results`
  );
  const { data } = await live.json();
  // Join positions to driverMap for display
  updateLeaderboard(data, driverMap);
}, 15000);
```

This keeps live polls light while still having rich driver data available for display.

### Common errors

| Status | Message               | Fix                                                          |
| ------ | --------------------- | ------------------------------------------------------------ |
| `422`  | Query too complex     | Remove includes or split into multiple requests              |
| `400`  | Parameter not allowed | The include is not supported on this endpoint                |
| `429`  | Rate limit exceeded   | Reduce polling frequency; you have hit the hourly call limit |

### See also

**Reference**

* [Query Complexity](https://docs.sportmonks.com/v3/motorsport-api/welcome/query-complexity)
* [Request Options](https://docs.sportmonks.com/v3/motorsport-api/welcome/request-options)
* [Results and Live Data Type Reference](https://docs.sportmonks.com/v3/motorsport-api/welcome/results-and-live-data-type-reference)

**Related tutorials**

* [How to Use Includes in the Motorsport API](https://docs.sportmonks.com/v3/motorsport-api/tutorials-and-guides/guides/how-to-use-includes-in-the-motorsport-api.md)
* [How to Build a Live Race Tracker](https://docs.sportmonks.com/v3/motorsport-api/tutorials-and-guides/guides/how-to-build-a-live-race-tracker.md)

### FAQ

**Is query complexity the same as rate limiting?** No. Rate limiting counts how many requests you make per hour against your plan's limit. Query complexity is per-request - it measures how expensive a single request is to process. A complexity error means the request itself is too heavy, regardless of how many other calls you have made.

**Does query complexity apply to all endpoints?** Yes, but the threshold and scores vary by endpoint. A lighter endpoint like `GET Driver by ID` has a higher tolerance for includes than a heavier one like `GET All Livescores`.

**If I split a heavy request into two lighter requests, does that hurt my rate limit?** It counts as two requests instead of one against your hourly limit. For most plans this is negligible - the trade-off is nearly always worth it to avoid complexity errors during a live race.

**Does caching the response locally help with query complexity?** Caching does not change whether a single request exceeds the complexity threshold - it either does or it doesn't. But caching stable data means you can use lighter includes on your polling requests, which reduces the chance of hitting the threshold in the first place.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.sportmonks.com/v3/motorsport-api/tutorials-and-guides/guides/how-to-manage-query-complexity-in-the-motorsport-api.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
