# Lineups

### What does the include do?

The `lineups` include allows you to retrieve comprehensive information about the players who participated in a fixture, including starting eleven, substitutes, formations, jersey numbers, and positions on the field. This is essential for displaying team sheets, analysing tactical formations, and tracking player participation.

### Why use lineups?

The lineups include is crucial for:

* **Team sheet displays**: Show starting XIs and substitutes
* **Formation visualisation**: Display tactical formations (4-4-2, 4-3-3, etc.)
* **Player participation tracking**: See who played and in what position
* **Tactical analysis**: Analyse team formations and player positioning
* **Statistics context**: Understand player roles for performance analysis
* **Fantasy football**: Track player appearances and positions

### Requesting lineups

To retrieve lineup information for a fixture, use the following include:

```
https://api.sportmonks.com/v3/football/fixtures/{fixture_id}
?api_token=YOUR_TOKEN&include=lineups
```

Example: Get lineups for a fixture (fixture ID: 18535517)

```
https://api.sportmonks.com/v3/football/fixtures/18535517
?api_token=YOUR_TOKEN&include=lineups
```

### Response structure

When you include lineups in your request, you'll receive an array of lineup objects for all players:

```json
{
  "data": {
    "id": 19568568,
    "sport_id": 1,
    "league_id": 2,
    "season_id": 25580,
    "stage_id": 77478049,
    "group_id": null,
    "aggregate_id": null,
    "round_id": 388953,
    "state_id": 5,
    "venue_id": 131,
    "name": "Paris Saint Germain vs Tottenham Hotspur",
    "starting_at": "2025-11-26 20:00:00",
    "result_info": "Paris Saint Germain won after full-time.",
    "leg": "1/1",
    "details": null,
    "length": 90,
    "placeholder": false,
    "has_odds": true,
    "has_premium_odds": true,
    "starting_at_timestamp": 1764187200,
    "lineups": [
      {
        "id": 14671587223,
        "sport_id": 1,
        "fixture_id": 19568568,
        "player_id": 133779,
        "team_id": 6,
        "position_id": 24,
        "formation_field": "1:1",
        "type_id": 11,
        "formation_position": 1,
        "player_name": "Guglielmo Vicario",
        "jersey_number": 1
      },
      {
        "id": 14671603915,
        "sport_id": 1,
        "fixture_id": 19568568,
        "player_id": 33079,
        "team_id": 6,
        "position_id": 25,
        "formation_field": null,
        "type_id": 12,
        "formation_position": null,
        "player_name": "Kevin Danso",
        "jersey_number": 4
      }
    ]
  }
}
```

### Field descriptions

| Field                | Type         | Description                                                       |
| -------------------- | ------------ | ----------------------------------------------------------------- |
| `id`                 | integer      | Unique identifier for this lineup entry                           |
| `sport_id`           | integer      | Sport type identifier (1 = football)                              |
| `fixture_id`         | integer      | Associated fixture ID                                             |
| `player_id`          | integer      | Unique player identifier                                          |
| `team_id`            | integer      | Team identifier                                                   |
| `position_id`        | integer      | Player's position type (use nested include for details)           |
| `formation_field`    | string/null  | Player's position in formation (1-12), null if not in starting XI |
| `type_id`            | integer      | Player participation type (see below)                             |
| `formation_position` | integer/null | Additional formation position data                                |
| `player_name`        | string       | Player's name                                                     |
| `jersey_number`      | integer      | Jersey number worn in match                                       |

### Type IDs - Player participation

| Type ID | Meaning                              |
| ------- | ------------------------------------ |
| 11      | Starting player (in the starting XI) |
| 12      | Substitute (on the bench)            |

**Filter starters only:**

```python
starters = [p for p in lineups if p['type_id'] == 11]
```

### Formation field numbering (1-12)

The `formation_field` represents a player's position in the formation, numbered 1-12. This field is **null** for players not in the starting XI.

The formation numbers follow a sequential pattern:

* Formation starts at the defence on the right and goes to the left
* Numbers then continue to the midfielders, also from right to left
* Finally, numbers continue to the attackers from right to left
* Position 12 (or sometimes 1 depending on data source) is the goalkeeper

#### Example: 4-4-2 Formation

![](/files/MMZxmtcXN8u7dcpLPwdY)

#### Example: 4-3-3 Formation

![](/files/SHIbvC3xoQugUcAN7CgR)

**Important:** Always use `formation_field` for positioning, not player position IDs. The numbering may vary between matches and data sources.

### Position IDs and nested includes

To get detailed position information, use nested includes rather than relying on position\_id values:

**General positions (use nested include):**

```
&include=lineups.position
```

Returns: Goalkeeper, Defender, Midfielder, Attacker

**Detailed positions (use nested include):**

```
&include=lineups.detailedPosition
```

Returns: Specific positions like Left Back, Center Forward, Defensive Midfielder, etc.

### Nested includes

#### lineups.details.type

Get detailed statistics for each player's performance:

```
&include=lineups.details.type
```

This returns player fixture statistics (shots, passes, tackles, etc.).

#### lineups.position

Get general position information:

```
&include=lineups.position
```

Returns position data (Goalkeeper, Defender, Midfielder, Attacker).

#### lineups.player

Get complete player information:

```
&include=lineups.player
```

Returns full player profile including country, height, weight, birth date.

#### lineups.type

Get participation type information:

```
&include=lineups.type
```

Returns whether player is in starting lineup or on bench.

#### lineups.detailedPosition

Get specific position information:

```
&include=lineups.detailedPosition
```

Returns detailed position (Left Back, Center Forward, etc.).

### Code examples

#### Python example

```python
import requests

API_TOKEN = "YOUR_TOKEN"
FIXTURE_ID = 19568568

def get_match_lineups():
    url = f"https://api.sportmonks.com/v3/football/fixtures/{FIXTURE_ID}"
    params = {
        "api_token": API_TOKEN,
        "include": "lineups.player,lineups.position"
    }
    
    response = requests.get(url, params=params)
    data = response.json()
    lineups = data['data'].get('lineups', [])
    
    return lineups

# Separate lineups by team
def separate_by_team(lineups):
    teams = {}
    for player in lineups:
        team_id = player['team_id']
        if team_id not in teams:
            teams[team_id] = []
        teams[team_id].append(player)
    return teams

# Get starters and substitutes
def categorise_players(lineups):
    starters = [p for p in lineups if p['type_id'] == 11]
    substitutes = [p for p in lineups if p['type_id'] == 12]
    
    return {
        'starters': starters,
        'substitutes': substitutes
    }

# Display starting XI
def display_starting_xi(starters):
    # Sort by formation_field for positional display
    starters = sorted(
        [p for p in starters if p.get('formation_field')],
        key=lambda x: int(x.get('formation_field').split(':')[0])
    )
    
    print("Starting XI:\n")
    for player in starters:
        position = player.get('formation_field', '?')
        jersey = player.get('jersey_number', '?')
        name = player['player_name']
        print(f"#{jersey} {name} (Position: {position})")

# Build formation visualisation
def visualise_formation(starters):
    """Create a simple text-based formation display"""
    formation_dict = {}
    
    for player in starters:
        pos = player.get('formation_field')
        if pos:
            # Handle formation_field as "X:Y" format
            try:
                main_pos = int(pos.split(':')[0])
                formation_dict[main_pos] = {
                    'name': player['player_name'],
                    'jersey': player['jersey_number']
                }
            except (ValueError, AttributeError):
                continue
    
    # Group by lines (approximate)
    gk = formation_dict.get(1, {})
    defenders = [formation_dict.get(i) for i in [2, 3, 4, 5, 6] if i in formation_dict]
    midfielders = [formation_dict.get(i) for i in [7, 8, 9] if i in formation_dict]
    attackers = [formation_dict.get(i) for i in [10, 11, 12] if i in formation_dict]
    
    print("\n=== Formation ===\n")
    
    # Attackers
    if attackers:
        print("ATTACKERS:")
        for p in attackers:
            if p:
                print(f"  {p['jersey']} {p['name']}")
    
    # Midfielders
    if midfielders:
        print("\nMIDFIELDERS:")
        for p in midfielders:
            if p:
                print(f"  {p['jersey']} {p['name']}")
    
    # Defenders
    if defenders:
        print("\nDEFENDERS:")
        for p in defenders:
            if p:
                print(f"  {p['jersey']} {p['name']}")
    
    # Goalkeeper
    if gk:
        print(f"\nGOALKEEPER:")
        print(f"  {gk['jersey']} {gk['name']}")

# Usage
lineups = get_match_lineups()
by_team = separate_by_team(lineups)

for team_id, players in by_team.items():
    print(f"\n=== TEAM {team_id} ===")
    categories = categorise_players(players)
    
    print(f"\nStarters: {len(categories['starters'])}")
    display_starting_xi(categories['starters'])
    visualise_formation(categories['starters'])
    
    print(f"\nSubstitutes: {len(categories['substitutes'])}")
```

#### JavaScript example

```javascript
const API_TOKEN = "YOUR_TOKEN";
const FIXTURE_ID = 19568568;

async function getMatchLineups() {
    const url = `https://api.sportmonks.com/v3/football/fixtures/${FIXTURE_ID}`;
    const params = new URLSearchParams({
        api_token: API_TOKEN,
        include: "lineups.player,lineups.position"
    });

    try {
        const response = await fetch(`${url}?${params}`);
        const data = await response.json();
        return data.data.lineups || [];
    } catch (error) {
        console.error("Error fetching lineups:", error);
        return [];
    }
}

function categorisePlayer(lineups) {
    return {
        starters: lineups.filter(p => p.type_id === 11),
        substitutes: lineups.filter(p => p.type_id === 12)
    };
}

function buildLineupsDisplay(lineups) {
    const container = document.createElement('div');
    container.className = 'lineups-container';
    
    // Separate by team
    const teams = {};
    lineups.forEach(player => {
        if (!teams[player.team_id]) {
            teams[player.team_id] = [];
        }
        teams[player.team_id].push(player);
    });
    
    // Display each team
    Object.entries(teams).forEach(([teamId, players]) => {
        const teamSection = document.createElement('div');
        teamSection.className = 'team-lineups';
        
        const categories = categorisePlayer(players);
        
        // Starting XI
        const startingXI = document.createElement('div');
        startingXI.className = 'starting-xi';
        startingXI.innerHTML = '<h3>Starting XI</h3>';
        
        // Sort by formation_field
        const starters = categories.starters
            .filter(p => p.formation_field)
            .sort((a, b) => {
                const aPos = parseInt(a.formation_field.split(':')[0]) || 99;
                const bPos = parseInt(b.formation_field.split(':')[0]) || 99;
                return aPos - bPos;
            });
        
        starters.forEach(player => {
            const playerDiv = document.createElement('div');
            playerDiv.className = 'player-card';
            playerDiv.innerHTML = `
                <span class="jersey">${player.jersey_number}</span>
                <span class="name">${player.player_name}</span>
                <span class="position">Pos: ${player.formation_field || '?'}</span>
            `;
            startingXI.appendChild(playerDiv);
        });
        
        teamSection.appendChild(startingXI);
        
        // Substitutes
        if (categories.substitutes.length > 0) {
            const subsDiv = document.createElement('div');
            subsDiv.className = 'substitutes';
            subsDiv.innerHTML = '<h4>Substitutes</h4>';
            
            categories.substitutes.forEach(player => {
                const playerDiv = document.createElement('div');
                playerDiv.className = 'player-card sub';
                playerDiv.innerHTML = `
                    <span class="jersey">${player.jersey_number}</span>
                    <span class="name">${player.player_name}</span>
                `;
                subsDiv.appendChild(playerDiv);
            });
            
            teamSection.appendChild(subsDiv);
        }
        
        container.appendChild(teamSection);
    });
    
    document.body.appendChild(container);
}

// Build formation diagram
function buildFormationDiagram(starters) {
    const field = document.createElement('div');
    field.className = 'football-field';
    field.style.cssText = `
        width: 600px;
        height: 800px;
        background: #228B22;
        position: relative;
        border: 2px solid white;
    `;
    
    starters.forEach(player => {
        const formationPos = player.formation_field ? parseInt(player.formation_field.split(':')[0]) : null;
        if (!formationPos) return;
        
        // Calculate position on field (simplified)
        let x = 50; // percentage
        let y = 80 - (formationPos * 6); // approximate
        
        const playerDot = document.createElement('div');
        playerDot.className = 'player-position';
        playerDot.style.cssText = `
            position: absolute;
            left: ${x}%;
            top: ${y}%;
            transform: translate(-50%, -50%);
            background: white;
            border-radius: 50%;
            width: 40px;
            height: 40px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
        `;
        playerDot.textContent = player.jersey_number;
        playerDot.title = player.player_name;
        
        field.appendChild(playerDot);
    });
    
    document.body.appendChild(field);
}

// Run
getMatchLineups().then(lineups => {
    buildLineupsDisplay(lineups);
    const starters = lineups.filter(p => p.type_id === 11 && p.formation_field);
    buildFormationDiagram(starters);
});
```

### Best practices

1. **Always use type\_id to filter**: Use type\_id 11 for starters and type\_id 12 for substitutes.
2. **Check formation\_field before using**: formation\_field is null for bench players. Always validate.
3. **Sort by formation\_field**: When displaying starting XI, sort by formation\_field for positional order.
4. **Use nested includes for position data**: Always use `lineups.position` or `lineups.detailedPosition` for reliable position information rather than hardcoding position IDs.
5. **Use nested includes for complete data**: Include `lineups.player` to get full player data in one request.
6. **Cache completed matches**: Lineups don't change after a match ends.
7. **Always show jersey numbers**: Jersey numbers are important for display and identification.
8. **Handle null values gracefully**: formation\_field, formation\_position, and other fields may be null. Always validate.

### Related includes

* **Events** - Cross-reference substitution events with lineup changes
* **Formations** - Get team formation strings (4-4-2, 4-3-3, etc.)
* **Statistics** - Get player performance statistics via `lineups.details.type`
* **Participants** - Get team and player relationship data

### Summary

The `lineups` include provides comprehensive player participation data including starting XIs, substitutes, formations, jersey numbers, and field positions. With `type_id` filtering (11 = starters, 12 = substitutes) and `formation_field` positioning (1-12 sequential formation positions), it enables building team sheets, formation visualisations, and tactical analysis. Always use nested includes like `lineups.player` and `lineups.position` for complete player information and reliable position data in a single API call.


---

# 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/tutorials-and-guides/tutorials/includes/lineups.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.
