active, completed, or closed). Up to 50 sessions per item. Simkl returns the full session list so you can replicate the simkl.com “Rewatches” panel.
?allow_rewatch=yes get a silent no-op — the request still consumes a rate-limit slot but returns added: { movies: 0, shows: 0, episodes: 0 }. Gate the flag behind the user’s plan instead of sending it blindly:- On sign-in (or first launch), call
POST /users/settingsonce and readaccount.type— one of"free","pro", or"vip". Cache it locally. - Don’t refetch on every poll. User settings are set-and-forget. Watch
activities.settings.allfromGET /sync/activities(you’re already polling it for the sync delta — see the Sync guide); when that timestamp bumps, refetch/users/settingsonce to pick up plan upgrades, downgrades, timezone changes, etc. - If
account.type === "free", hide or disable the “Rewatch” button with a short note like “Rewatch tracking requires Simkl Pro or VIP” and link to simkl.com/vip. Don’t send?allow_rewatch=yesfor free-tier users — there’s no value in firing a request that the server will silently drop.
Endpoints used
POST /sync/history
?allow_rewatch=yes makes the write land in a rewatch session instead of the canonical row.GET /sync/all-items
?allow_rewatch=yes adds one extra row per saved session alongside the canonical entry.Quick start
A movie rewatch:rewatch_id and rewatch_status inside added.statuses[].response. Cache the rewatch_id and pin it on every subsequent write for that session.
When does a write become a rewatch?
The server always tries the regular write first. If the regular write would actually mark new data, that takes precedence — no rewatch is created. A write lands in a rewatch session when any of these holds:- The item is already Completed and the regular add is a no-op (movies: user already finished it; shows: payload has no episodes and the show is Completed).
- You included episodes and every one is already on the user’s history — i.e. the regular write would change nothing.
- You passed
is_rewatch: trueon the item.
is_rewatch: true does not bypass the regular-first logic. If the write tries to add a date that already exists in canonical history, it’s still rejected. The flag’s main use is to create an empty rewatch session on a Completed item your UI explicitly marked as “starting a rewatch” — without writing any episodes yet.
The episode or movie must already exist on the user’s history (completed / watching / hold / dropped) — Plan-to-Watch entries can’t be rewatched, there’s nothing to rewatch.
Per-item rewatch fields
All fields below are optional. They only take effect when?allow_rewatch=yes is on the URL.
| Field | Type | Purpose |
|---|---|---|
is_rewatch | bool | Trigger rewatch logic explicitly. See When does a write become a rewatch? for what overrides what. |
rewatch_id | int | Resume a specific session. Use the value from a previous response. Without it, the server picks the item’s active session if one exists, else creates a new session. |
rewatch_status | string | Explicitly set session state — active, closed, or (movies only) completed. See Session states for the full state machine. |
watched_at | string (ISO-8601) | Standard per-item timestamp. Also serves as the session’s start date. |
last_watched_at | string (ISO-8601) | Primarily a response field from GET /sync/all-items (the session’s most recent watch event). Rarely set on writes. |
Session states
A session is in exactly one of three states. For TV / anime,completed is server-earned only: the server promotes a session when the rewatch covers every aired regular episode (specials in season 0 don’t count). For movies, completed is the default and only meaningful state.
| State | Meaning |
|---|---|
active | In progress. Exactly one per item — starting another auto-closes this one. |
closed | Explicitly ended by the user. Resumable. Keeps watched_episodes_count. |
completed | All aired regular episodes covered (TV / anime); or the movie’s default. |
POST /sync/history?allow_rewatch=yes + rewatch_status: "..."):
"active"— start or reactivate a session. The previously-active session for the item auto-closes."closed"— end the active session. No-op against acompletedsession; reactivate it first if you really need to close it."completed"— honored for movies. For TV / anime, silently clamped to"closed"because only coverage earns DONE. Subsequent episode writes that complete coverage will promote the session back to"completed".
completed session (whether active or closed) auto-promotes to completed the moment an episode write pushes coverage to every aired regular episode.
The 2-day gap
Any two watch events on the same item (movie or individual episode) must be at least 2 days apart, or the second write collapses into the first session. It’s a rewatch, not a rewind 😄. The gap is per-item, not per-show. Watching S1E1 on Monday and S1E2 on Tuesday is fine — those are different items. The rule only fires when the same episode is written twice within 48h.- Sleep-and-resume — user starts an episode at night, finishes the next morning. One viewing, not two.
- Wrong timezones — clients labeling local time as UTC (or vice versa) drift 1–12 hours per write.
- DST transitions — naive date libraries miscalculate by an hour twice a year.
- Multi-device duplicates — phone + TV both report the same play.
- Retry storms — flaky connections retry a write that already landed.
- Importer re-runs — re-running an import re-sends the same
watched_at. - Scrobble pause/resume noise — bathroom break → re-fire of
/start+/stop. - Buggy progress reporting — players hitting 80%+ multiple times on seeks.
Reading sessions back
?allow_rewatch=yes on GET /sync/all-items adds one extra entry per saved rewatch session alongside the canonical entry for each item. Always pair with date_from — never call without it outside the initial Phase-1 sync.
Canonical vs rewatch rows
| Field | Canonical (is_rewatch: false) | Rewatch (is_rewatch: true) |
|---|---|---|
is_rewatch | false (emitted when ?allow_rewatch=yes is set; otherwise absent) | true |
rewatch_id | absent | session id |
rewatch_status | absent | active / completed / closed |
last_watched_at | The canonical (original) last watch date for the item — does not reflect rewatch sessions. | This session’s most-recent watch event. |
watched_episodes_count | Episodes marked watched on the canonical row (e.g. 62/62 for a finished show). Not a lifetime total across rewatches. | Per-session count — 0 as a sentinel without extended=full. |
last_watched_at and watched_episodes_count on the canonical entry never incorporate rewatch progress, no matter how many sessions exist for the item.
Worked example — Game of Thrones with one rewatch session
A representative shape fromGET /sync/all-items?allow_rewatch=yes&extended=full&episode_watched_at=yes — Game of Thrones (Simkl ID 17465) finished long ago, currently being rewatched in progress (4 of 73 episodes into S1). The item appears twice in shows[]: once as the canonical row, once as the in-progress rewatch row.
- Same
simklID on both rows —17465appears twice. Group byids.simklwhen iterating; treatis_rewatch: truerows as side-cars on the canonical entry. - Canonical
watched_episodes_countis73/73(the user finished the show originally); the rewatch row’s4/73is per-session and does NOT advance the canonical count. last_watched_atis independent on each row — canonical reflects the original final watch (2026-05-15); the rewatch row reflects its own most-recent episode (2026-05-16T20:00:00Z).rewatch_status: "active"because the session is mid-coverage (4/73). It auto-flips to"completed"whenwatched_episodes_count >= total_episodes_count - not_aired_episodes_count. See Session states for the full rules.seasons[].episodes[]only appears on the rewatch row under this flag combo (extended=full+episode_watched_at=yes). Withoutextended=full, the rewatch row would arrive summary-only:watched_episodes_count: 0sentinel, noseasons[]block.- Movies are simpler — no
seasons[], justmovie: { ... }, and the rewatch row’srewatch_statusalways starts atcompleted(movies have nothing to track episode-wise). - Anime rewatch rows have the same shape as show rows plus an
anime_typefield ("tv","movie", etc.) on the rewatch row itself.
Flag combinations for episode lists
Flags (on top of allow_rewatch=yes) | What rewatch entries carry |
|---|---|
| (none) | Summary only. watched_episodes_count returns 0 as a sentinel even when the session actually has episodes. |
extended=full | Summary fields populated with real per-session counts, plus seasons[].episodes[] listing episode number. |
extended=full_anime_seasons | Same plus anime tvdb mapping per episode. |
extended=full + episode_watched_at=yes | Same plus per-episode watched_at (from each episode’s completed_on). |
episode_watched_at=yes is a modifier — it adds timestamps to episodes already loaded. Without extended=full, episodes aren’t loaded and the flag has no effect on rewatch entries.
UI patterns (mirror simkl.com)
Stats badge — '×3 times (1 partial), last 12 days ago'
Stats badge — '×3 times (1 partial), last 12 days ago'
?allow_rewatch=yes response for the current item and count by rewatch_status. closed is the “partial” count; completed is the clean-finish count.'Currently rewatching #N' progress bar (TV / anime)
'Currently rewatching #N' progress bar (TV / anime)
active session and show watched_episodes_count / total_episodes_count. Number the badge by chronological index among all sessions for the item — the number isn’t stored on the server, you compute it client-side.Movies don’t really have an active phase — every movie rewatch session flips to completed immediately.'Mark next episode rewatched' button
'Mark next episode rewatched' button
'Reactivate' / 'Start new' / 'Close' buttons
'Reactivate' / 'Start new' / 'Close' buttons
Rewatch history list — '×3 sessions' panel
Rewatch history list — '×3 sessions' panel
last_watched_at ascending. Label sessions “Rewatch #1”, “Rewatch #2”, etc. on the client.Limits and rules
- Maximum 50 rewatches per item (movie, show, or anime — combined cap).
- One
activesession per item. Making another session active auto-closes the previous active one. - 2-day minimum gap between watch events on the same movie or episode. See The 2-day gap.
- Simkl Pro / VIP only. Free-tier writes are silent no-ops.
Edge cases
Free-tier user calls `?allow_rewatch=yes`
Free-tier user calls `?allow_rewatch=yes`
200 OK with added: { movies: 0, shows: 0, episodes: 0 }. No error code is surfaced. To prevent this in your app, check account.type from POST /users/settings at sign-in (cache it locally; refetch only when activities.settings.all bumps — see the Pro / VIP gate at the top of this page). Reading the added counts in the response is a fallback if you can’t gate up-front, but it’s wasteful — the request still consumed a rate-limit slot.50-cap reached
50-cap reached
Active session collision
Active session collision
watched_episodes_count is preserved). The old session is still readable and still counts toward the 50-cap.`watched_at` collides with canonical history
`watched_at` collides with canonical history
is_rewatch: true — is rejected if the watched_at date matches an existing canonical episode/movie row. Use a different watched_at value, or omit the conflicting episode.Same episode written twice within 48h
Same episode written twice within 48h
watched_episodes_count doesn’t increment; last_watched_at updates to the latest value. Intentional — see The 2-day gap.Conflict-split on same episode, different dates
Conflict-split on same episode, different dates
watched_at more than 48h away, the server closes the current active session (preserving its watched_episodes_count) and opens a fresh active session with the conflicting episode at the new timestamp. Common with offline-capable apps catching up after a long sync gap.Sessions started via simkl.com are pre-populated
Sessions started via simkl.com are pre-populated
/sync/all-items after a session was created on simkl.com to see what’s actually there.`1970-01-01T00:00:01Z` on a rewatch episode
`1970-01-01T00:00:01Z` on a rewatch episode
Reference
Sync guide
date_from semantics, deletion reconciliation, edge cases.