---
title: "Streaming API v2: History and continue watching"
description: "The line's watch history, the continue watching row, and how and when to report progress."
---

The line's **watch history** lives in the panel, not in the app: every app
signed in to the same line (yours, or any other app built on this API) sees
it. Use it for "recently watched", "continue watching" and "recent
channels". The panel cannot tell how far a movie was watched: **the app
reports it** with `history-update`. Apps that use `player_api.php` do not
write history.

History belongs to the line (there are no profiles). Signing out, `logout-all`
or a password change do not erase it; `history-clear` does. The panel keeps
the 300 most recent entries of each line, for 180 days.

## `POST history-update`

Form-encoded body:

| Field | |
|---|---|
| `type` | `movie`, `episode` or `channel` |
| `id` | The item `id` (the episode `id` for an episode) |
| `position` | Seconds from the start (movies and episodes; ignored for channels) |
| `duration` | Total seconds, if known (`0` or omitted: unknown; the panel keeps the last one it got) |
| `watched` | Optional, `1` or `0`. Without it, the item counts as watched once `position` reaches 95 % of `duration` |

Answers `{"stored": true}`. `position` and `duration` go from `0` to `604800`
(7 days); anything else is `400 invalid_parameter`. Content outside the
line's package is `403 not_in_package`; an episode the panel cannot find,
`404 not_found`. Content in hidden categories is stored but not listed.

When to report (each report is a request to the panel; keep them few):

- **Movies and episodes**: when playback pauses, stops or the app goes to the
  background, at the end (with `watched=1`), and **every 2 minutes at most**
  while playing. Never on every second or on seek.
- **Channels**: once, after about 30 seconds on the channel. Never while
  zapping.
- Starting a watched item again from the beginning makes it "in progress"
  again (unless you send `watched=1`).

The panel accepts 30 reports per minute per line, across all its devices.
Beyond that it answers `429 rate_limited` with `Retry-After`: **drop that
report, do not retry it**; the next one replaces it.

## `GET history`

Parameters: `type` (`all` default, `movie`, `episode`, `channel`), `offset`,
`limit` (default `20`, `1`-`50`). Most recent first.

```json
{
  "type": "all", "total": 2, "offset": 0, "limit": 20, "next_offset": null,
  "items": [
    { "item": { "id": 5001, "type": "episode", "season": 1, "episode_num": 1, "title": "Pilot", "…": "…",
                "series_id": 88, "series_name": "Breaking Bad", "series_poster": "https://img.example.com/bb.jpg" },
      "position": 1740, "duration": 3480, "progress": 0.5, "watched": false, "updated_at": 1767225000 },
    { "item": { "id": 4321, "type": "movie", "name": "The Matrix", "…": "…" },
      "position": 8160, "duration": 8160, "progress": 1, "watched": true, "updated_at": 1767220000 }
  ]
}
```

- `item` has the shape of its list (`live-channels`, `vod-movies`) or, for an
  episode, of `episode-info`.
- `progress` is `position / duration` (0 to 1), or `null` when the duration is
  unknown (and for channels).
- Entries for content the line no longer has (removed from the panel or from
  its package) are left out of `items` but still count in `total`, so a page
  may come back shorter than `limit`. Keep paging with `next_offset`.

## `GET continue-watching`

Parameter: `limit` (default `20`, `1`-`50`). What a "continue watching" row
needs, most recent first, in the entry shape of `history` plus `reason`:

- `in_progress`: a movie, or the latest episode of a series, started and not
  finished.
- `next_episode`: the latest episode of a series was finished; `item` is the
  episode that follows it (`position` `0`). A finished series does not appear.

One entry per series.

## `POST history-remove`, `POST history-clear`

`history-remove` takes `type` and `id` and removes that entry; `history-clear`
removes the line's whole history. Both answer `{"removed": <number of
entries>}`.
