---
title: Calendar
description: Read the global airing schedule or a signed-in user's personalized calendar.
section: Your data
order: 10
---

# Calendar

You read episode airing schedules through the `/v3/calendar` endpoints, either the global schedule or a signed-in user's personalized one.

> [!REQUIRED]
> `GET /v3/calendar/my/shows/{start}/{days}` needs the `read` scope. `GET /v3/calendar/shows/{start}/{days}` needs no credential at all. See [Authentication](/dev/authentication).

## Global airing schedule

`GET /v3/calendar/shows/{start}/{days}` returns every episode airing in the date range across FlickList's whole catalog, filtered to shows above a small popularity floor, grouped by date. It isn't scoped to any user, and no credential is used or checked.

`start` is `YYYY-MM-DD`. `days` is the length of the range starting at `start`, from 1 to 180; anything over 180 is a `400`, not a silent clamp. FlickList doesn't impose a short calendar cap, 180 is a performance ceiling, not a feature gate.

:::tabs
```bash
curl "https://flicklist.tv/api/v3/calendar/shows/2026-06-01/7"
```
```javascript
const res = await fetch('https://flicklist.tv/api/v3/calendar/shows/2026-06-01/7');
const calendar = await res.json();
```
```python
import requests
r = requests.get("https://flicklist.tv/api/v3/calendar/shows/2026-06-01/7")
calendar = r.json()
```
:::

```json
{
  "start": "2026-06-01",
  "end": "2026-06-07",
  "days": [
    {
      "date": "2026-06-01",
      "items": [
        {
          "show_title": "Severance",
          "season_number": 2,
          "episode_number": 5,
          "episode_title": "Trojan's Horse",
          "air_date": "2026-06-01",
          "air_time": "20:00",
          "network": "Apple TV+",
          "ids": { "fldb": "flt_4b8e12d7", "tmdb": 95396, "imdb": "tt11280740", "tvdb": null, "slug": "severance", "anilist": null }
        }
      ]
    }
  ]
}
```

## Personalized airing schedule

`GET /v3/calendar/my/shows/{start}/{days}` returns episodes in range for shows the caller tracks, has watchlisted (`watching` or `plan_to_watch`), or has any watch history for. There's no popularity floor here, since these are shows the user already has a relationship with. `start` and `days` follow the same rules as the global endpoint.

:::tabs
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://flicklist.tv/api/v3/calendar/my/shows/2026-06-01/7"
```
```javascript
const res = await fetch('https://flicklist.tv/api/v3/calendar/my/shows/2026-06-01/7', {
  headers: { Authorization: `Bearer ${token}` },
});
const myCalendar = await res.json();
```
```python
import requests
r = requests.get(
    "https://flicklist.tv/api/v3/calendar/my/shows/2026-06-01/7",
    headers={"Authorization": f"Bearer {token}"},
)
my_calendar = r.json()
```
:::

The response shape is identical to the global endpoint: `start`, `end`, and `days`, each day carrying its own `items` array.

> [!WARNING]
> A `days` value over 180 is a 400 on both endpoints, not a silent clamp.

## Requesting a longer window

Break a range over 180 days into consecutive requests, advancing `start` by the previous window's length each time.

```javascript
async function fetchRange(start, totalDays) {
  const chunks = [];
  let cursor = new Date(start);
  let remaining = totalDays;
  while (remaining > 0) {
    const days = Math.min(remaining, 180);
    const startStr = cursor.toISOString().slice(0, 10);
    const res = await fetch(`https://flicklist.tv/api/v3/calendar/shows/${startStr}/${days}`);
    chunks.push(await res.json());
    cursor.setDate(cursor.getDate() + days);
    remaining -= days;
  }
  return chunks;
}
```
