# Periods

### What does the include do?

The `periods` include allows you to retrieve detailed information about different periods within a football match, including regular time, extra time, and penalties. This include provides comprehensive timing data including the current minute, seconds elapsed, period start/end times, and whether the period is currently active (ticking).

### Why use periods?

The periods include is essential for:

* **Live match tracking**: Display accurate match time with minute and second precision
* **Match state management**: Know which period is currently being played
* **Time-based analysis**: Analyse events by period (first half, second half, extra time)
* **Broadcast applications**: Show precise match timing for live streams
* **Statistical analysis**: Break down team performance by match period
* **Injury time tracking**: Monitor added time in each period

### Requesting periods

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

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

**Example:** Get periods for Real Madrid vs FC Barcelona (fixture ID: 19439347)

```http
https://api.sportmonks.com/v3/football/fixtures/19439347
?api_token=YOUR_TOKEN&include=periods
```

### Response structure

When you include `periods` in your request, you'll receive an array of period objects for each match period:

```json
{
  "data": {
    "id": 19439347,
    "sport_id": 1,
    "league_id": 564,
    "season_id": 25659,
    "stage_id": 77476930,
    "group_id": null,
    "aggregate_id": null,
    "round_id": 373219,
    "state_id": 5,
    "venue_id": 2020,
    "name": "Real Madrid vs FC Barcelona",
    "starting_at": "2025-10-26 15:15:00",
    "result_info": "Real Madrid won after full-time.",
    "leg": "1\/1",
    "details": null,
    "length": 90,
    "placeholder": false,
    "has_odds": true,
    "has_premium_odds": true,
    "starting_at_timestamp": 1761491700,
    "periods": [
      {
        "id": 6330171,
        "fixture_id": 19439347,
        "type_id": 1,
        "started": 1761491882,
        "ended": 1761494952,
        "counts_from": 0,
        "ticking": false,
        "sort_order": 1,
        "description": "1st-half",
        "time_added": 6,
        "period_length": 45,
        "minutes": 51,
        "seconds": 10,
        "has_timer": false
      },
      {
        "id": 6330453,
        "fixture_id": 19439347,
        "type_id": 2,
        "started": 1761495960,
        "ended": 1761499312,
        "counts_from": 45,
        "ticking": false,
        "sort_order": 2,
        "description": "2nd-half",
        "time_added": 10,
        "period_length": 45,
        "minutes": 100,
        "seconds": 52,
        "has_timer": false
      }
    ]
  }
}
```

### Field descriptions

| Field           | Type         | Description                                                                           |
| --------------- | ------------ | ------------------------------------------------------------------------------------- |
| `id`            | integer      | Unique identifier for this period                                                     |
| `fixture_id`    | integer      | ID of the fixture this period belongs to                                              |
| `type_id`       | integer      | Type identifier for the period (see Period Types below)                               |
| `started`       | integer      | UNIX timestamp of when the period started                                             |
| `ended`         | integer/null | UNIX timestamp of when the period ended (null if ongoing)                             |
| `counts_from`   | integer      | Minute from which this period starts counting (e.g., 0 for 1st half, 45 for 2nd half) |
| `ticking`       | boolean      | Whether the period is currently active/being played                                   |
| `sort_order`    | integer      | Sorting order of the period (1 = first, 2 = second, etc.)                             |
| `description`   | string       | Human-readable description of the period                                              |
| `time_added`    | integer/null | Additional injury/stoppage time added to the period (in minutes)                      |
| `period_length` | integer      | Standard length of the period in minutes (usually 45 for regular time)                |
| `minutes`       | integer      | Current minute within the match (cumulative)                                          |
| `seconds`       | integer      | Seconds after the current minute (0-59)                                               |
| `has_timer`     | boolean      | Whether detailed timer information (minutes/seconds) is available                     |

### Period types

The `type_id` field indicates what type of period this represents:

| Type ID | Description              | counts\_from | period\_length |
| ------- | ------------------------ | ------------ | -------------- |
| 1       | First Half (1ST\_HALF)   | 0            | 45             |
| 2       | Second Half (2ND\_HALF)  | 45           | 45             |
| 3       | Extra Time - First Half  | 90           | 15             |
| 4       | Extra Time - Second Half | 105          | 15             |
| 5       | Penalty Shootout         | 120          | Variable       |
| 14      | Awaiting Extra Time      | 90           | 0              |
| 16      | Extra Time Halftime      | 105          | 0              |
| 18      | Awaiting Penalties       | 120          | 0              |

### Understanding period timing

#### counts\_from

This field indicates the starting minute for the period:

* 1st half: `counts_from = 0` (minutes 0-45)
* 2nd half: `counts_from = 45` (minutes 45-90)
* Extra time 1st: `counts_from = 90` (minutes 90-105)
* Extra time 2nd: `counts_from = 105` (minutes 105-120)

#### minutes and seconds

These fields provide the current match time:

* `minutes`: Cumulative minute count from match start (e.g., 47 means 47th minute)
* `seconds`: Seconds within current minute (0-59)

**Example:** `minutes = 47, seconds = 23` means the match is at 47:23

#### ticking

* `true`: This period is currently active (match is live in this period)
* `false`: This period has ended

#### time\_added (Injury time)

The additional minutes added to the period for stoppages:

* Usually 1-5 minutes in regular time
* Shows as "45+2" in match displays when 2 minutes added to 1st half

### Current period include

In addition to the `periods` include, you can use the `currentPeriod` include for a more convenient way to get only the active period:

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

This returns only the period that is currently ticking (or null if match hasn't started or has ended).

### Nested includes

The periods include supports the following nested includes:

#### periods.type

Get detailed information about the period type:

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

#### periods.events

Get all events that occurred during this specific period:

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

#### periods.statistics

Get statistics specific to this period:

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

### Code examples

#### Python example

```python
import requests
from datetime import datetime

# API configuration
API_TOKEN = "YOUR_TOKEN"
FIXTURE_ID = 19439347

# Request periods
url = f"https://api.sportmonks.com/v3/football/fixtures/{FIXTURE_ID}"
params = {
    "api_token": API_TOKEN,
    "include": "periods"
}

response = requests.get(url, params=params)
data = response.json()

# Extract periods
periods = data['data'].get('periods', [])

# Display all periods
for period in periods:
    print(f"\n{period['description']}:")
    print(f"  Started: {datetime.fromtimestamp(period['started'])}")
    if period['ended']:
        print(f"  Ended: {datetime.fromtimestamp(period['ended'])}")
        duration = period['ended'] - period['started']
        print(f"  Duration: {duration // 60} minutes")
    print(f"  Ticking: {period['ticking']}")
    if period['time_added']:
        print(f"  Injury time: +{period['time_added']} minutes")

# Find current/active period
def get_current_period(periods):
    """Get the currently active period"""
    return next((p for p in periods if p['ticking']), None)

current = get_current_period(periods)
if current:
    print(f"\n🔴 LIVE: Currently in {current['description']}")
    print(f"⏱️  Match time: {current['minutes']}:{current['seconds']:02d}")
else:
    print("\n✅ Match ended or not started")

# Calculate total match time
def calculate_total_time(periods):
    """Calculate total playing time including injury time"""
    total_minutes = 0
    for period in periods:
        if period['ended']:
            duration_seconds = period['ended'] - period['started']
            total_minutes += duration_seconds // 60
    return total_minutes

total_time = calculate_total_time(periods)
print(f"\n⏱️  Total playing time: {total_time} minutes")

# Track injury time patterns
def analyze_injury_time(periods):
    """Analyse injury time added in each period"""
    injury_time = {}
    for period in periods:
        if period['time_added']:
            injury_time[period['description']] = period['time_added']
    return injury_time

injury_analysis = analyze_injury_time(periods)
print(f"\n🚑 Injury time analysis:")
for period_name, minutes in injury_analysis.items():
    print(f"  {period_name}: +{minutes} minutes")

# Check if match went to extra time
def has_extra_time(periods):
    """Check if match included extra time"""
    return any(p['type_id'] in [3, 4] for p in periods)

def has_penalties(periods):
    """Check if match went to penalties"""
    return any(p['type_id'] == 5 for p in periods)

if has_extra_time(periods):
    print("\n⏱️  Match included extra time")
if has_penalties(periods):
    print("🎯 Match decided by penalties")
```

#### JavaScript example

```javascript
// API configuration
const API_TOKEN = "YOUR_TOKEN";
const FIXTURE_ID = 19439347;

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

    try {
        const response = await fetch(`${url}?${params}`);
        const data = await response.json();
        
        const periods = data.data.periods || [];
        
        // Display all periods
        periods.forEach(period => {
            console.log(`\n${period.description}:`);
            console.log(`  Started: ${new Date(period.started * 1000).toLocaleString()}`);
            if (period.ended) {
                console.log(`  Ended: ${new Date(period.ended * 1000).toLocaleString()}`);
                const duration = Math.floor((period.ended - period.started) / 60);
                console.log(`  Duration: ${duration} minutes`);
            }
            console.log(`  Ticking: ${period.ticking}`);
            if (period.time_added) {
                console.log(`  Injury time: +${period.time_added} minutes`);
            }
        });
        
        // Find current period
        const currentPeriod = getCurrentPeriod(periods);
        if (currentPeriod) {
            console.log(`\n🔴 LIVE: Currently in ${currentPeriod.description}`);
            console.log(`⏱️  Match time: ${currentPeriod.minutes}:${String(currentPeriod.seconds).padStart(2, '0')}`);
            
            // Display live timer
            displayLiveTimer(currentPeriod);
        } else {
            console.log("\n✅ Match ended or not started");
        }
        
        // Calculate total time
        const totalTime = calculateTotalTime(periods);
        console.log(`\n⏱️  Total playing time: ${totalTime} minutes`);
        
        // Check match extras
        if (hasExtraTime(periods)) {
            console.log("⏱️  Match included extra time");
        }
        if (hasPenalties(periods)) {
            console.log("🎯 Match decided by penalties");
        }
        
    } catch (error) {
        console.error("Error fetching periods:", error);
    }
}

function getCurrentPeriod(periods) {
    return periods.find(p => p.ticking === true);
}

function calculateTotalTime(periods) {
    return periods.reduce((total, period) => {
        if (period.ended) {
            const durationMinutes = Math.floor((period.ended - period.started) / 60);
            return total + durationMinutes;
        }
        return total;
    }, 0);
}

function hasExtraTime(periods) {
    return periods.some(p => [3, 4].includes(p.type_id));
}

function hasPenalties(periods) {
    return periods.some(p => p.type_id === 5);
}

// Display live match timer
function displayLiveTimer(period) {
    const timerDiv = document.createElement('div');
    timerDiv.className = 'live-timer';
    timerDiv.innerHTML = `
        <div class="timer-container">
            <div class="period-name">${period.description}</div>
            <div class="match-time">${period.minutes}:${String(period.seconds).padStart(2, '0')}</div>
            ${period.time_added ? `<div class="injury-time">+${period.time_added} min</div>` : ''}
            <div class="live-indicator">🔴 LIVE</div>
        </div>
    `;
    document.body.appendChild(timerDiv);
}

// Build period timeline visualization
function buildPeriodTimeline(periods) {
    const timeline = document.createElement('div');
    timeline.className = 'period-timeline';
    
    periods.forEach((period, index) => {
        const periodBlock = document.createElement('div');
        periodBlock.className = `period-block ${period.ticking ? 'active' : 'completed'}`;
        periodBlock.innerHTML = `
            <div class="period-label">${period.description}</div>
            <div class="period-time">${period.counts_from}-${period.counts_from + period.period_length}'</div>
            ${period.time_added ? `<div class="added-time">+${period.time_added}'</div>` : ''}
        `;
        timeline.appendChild(periodBlock);
    });
    
    document.body.appendChild(timeline);
}

// Format match time display
function formatMatchTime(period) {
    const baseMinute = period.minutes;
    const seconds = period.seconds;
    
    // Check if in injury time
    const regularTime = period.counts_from + period.period_length;
    if (baseMinute >= regularTime && period.time_added) {
        const injuryMinute = baseMinute - regularTime;
        return `${regularTime}+${injuryMinute}:${String(seconds).padStart(2, '0')}`;
    }
    
    return `${baseMinute}:${String(seconds).padStart(2, '0')}`;
}

// Run the example
getFixturePeriods();
```

### Common use cases

#### 1. Live match timer display

Display accurate live match time with injury time:

```python
def format_match_time(period):
    """Format match time for display"""
    minutes = period['minutes']
    seconds = period['seconds']
    regular_time = period['counts_from'] + period['period_length']
    
    # Check if in injury time
    if minutes >= regular_time and period['time_added']:
        injury_minute = minutes - regular_time
        return f"{regular_time}+{injury_minute}:{seconds:02d}"
    
    return f"{minutes}:{seconds:02d}"
```

#### 2. Period-based statistics

Analyze team performance by period:

```python
def analyze_by_period(fixtures_with_periods_and_events):
    """Analyse goals scored by period"""
    period_stats = {
        '1ST_HALF': {'goals': 0},
        '2ND_HALF': {'goals': 0},
        'EXTRA_TIME': {'goals': 0}
    }
    
    for fixture in fixtures_with_periods_and_events:
        events = fixture.get('events', [])
        for event in events:
            if event['type_id'] == 14:  # Goal
                period_id = event['period_id']
                period = next((p for p in fixture['periods'] if p['id'] == period_id), None)
                if period:
                    period_stats[period['description']]['goals'] += 1
    
    return period_stats
```

#### 3. Match state detection

Determine current match state:

```python
def get_match_state(periods):
    """Determine current match state"""
    current = next((p for p in periods if p['ticking']), None)
    
    if not current:
        if any(p['ended'] for p in periods):
            return "FINISHED"
        return "NOT_STARTED"
    
    if current['type_id'] == 1:
        return "FIRST_HALF"
    elif current['type_id'] == 2:
        return "SECOND_HALF"
    elif current['type_id'] in [3, 4]:
        return "EXTRA_TIME"
    elif current['type_id'] == 5:
        return "PENALTIES"
    
    return "UNKNOWN"
```

### Best practices

1. **Use has\_timer to check data availability**: Not all matches have detailed timer information. Check `has_timer` before displaying seconds.
2. **Handle null ended timestamps**: For live matches, `ended` will be null for the current period.
3. **Use currentPeriod for live updates**: If you only need the active period, use `include=currentPeriod` instead of fetching all periods.
4. **Calculate injury time correctly**: Display as "45+2" not "47" when showing injury time to users.
5. **Check ticking for live status**: The `ticking` field is the most reliable way to determine if a period is currently active.
6. **Sort by sort\_order**: Always use `sort_order` to display periods in chronological order.
7. **Cache completed periods**: Period data doesn't change after a period ends. Cache historical periods to reduce API calls.

### Related includes

* [**Events**](https://docs.sportmonks.com/football/tutorials-and-guides/tutorials/includes/events) - Cross-reference events with periods to show when they occurred
* [**Statistics**](https://docs.sportmonks.com/football/definitions/types/statistics) - Get period-specific statistics
* [**States**](https://docs.sportmonks.com/football/tutorials-and-guides/tutorials/includes/states) - Understand match state transitions
* [**Scores**](https://docs.sportmonks.com/football/tutorials-and-guides/tutorials/includes/scores) - See scores by period

### Summary

The `periods` include provides comprehensive timing information for all match periods including first half, second half, extra time, and penalties. With fields for current minutes/seconds, injury time, and active status, it enables accurate live match timers, period-based analysis, and match state management. Use `currentPeriod` for live matches when you only need the active period data.
