> ## Documentation Index
> Fetch the complete documentation index at: https://api.simkl.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Last Activities

> Returns the most recent update timestamps for each of the user's lists. **Always call this first** when syncing — compare against your last-saved timestamps and pull only the lists that have moved. This is the cheapest call in the API.

#### Top-level fields

| Field | Use |
|---|---|
| `all` | Newest timestamp anywhere in this response — every domain block, `settings`, `custom_lists`, ratings and playback. If it hasn't moved since your saved snapshot, nothing has. |
| `settings.all` | Updates to account settings (name, time zone, …) at https://simkl.com/settings/. |
| `tv_shows`, `anime`, `movies` | Per-domain timestamp groups. |
| `custom_lists.lists` | Custom Lists timestamps, one level deeper than the other blocks — see [Custom Lists have their own timestamps](/guides/sync#custom-lists-have-their-own-timestamps). |

#### Per-domain timestamps

| Field | Meaning | Cheapest next call |
|---|---|---|
| `all` | Latest update in this domain. | — |
| `rated_at` | A rating was added, changed, or removed. | Only when this moved — never on every sync, since every `/sync/all-items` item already carries `user_rating`. Then [`GET /sync/ratings/{type}`](/api-reference/simkl/get-user-ratings) with `date_from` and **no** rating segment — the changed ratings, removals included as `user_rating: null`. A rating-only change never appears in a `/sync/all-items` delta. Walkthrough: [Ratings come in their own delta](/guides/sync#ratings-delta). |
| `playback` | A paused playback was added, resumed, or cleared. | [`GET /sync/playback/{type}`](/api-reference/simkl/get-playback-sessions) with `date_from` — only the changed sessions. |
| `plantowatch`, `watching`, `completed`, `hold`, `dropped` | Items moved into/out of these lists, or episodes were marked watched/unwatched. | [`GET /sync/all-items/{type}/{status}`](/api-reference/simkl/get-all-items) with `date_from` and `extended=full` — full delta of modified items. Walkthrough: [Phase 2 — Continuous sync](/guides/sync#phase-2-continuous-sync). |
| `removed_from_list` | Items were deleted from the library entirely. `date_from` **won't surface removals** — you can only detect them by diffing. | [`GET /sync/all-items/{type}/{status}`](/api-reference/simkl/get-all-items) with `extended=simkl_ids_only` — cheapest possible payload (just the IDs) — and diff against your local cache. Walkthrough: [Detecting deletions](/guides/sync#detecting-deletions). |

> Movies don't have `watching` or `hold` — movies are atomic, so those statuses don't apply.

#### Auto-move side effects

When a user **rates** an unrated item, Simkl auto-files it: movies → `Completed`, shows/anime → `Watching`. That auto-move bumps the corresponding list timestamp, so the rated item also appears in subsequent `/sync/all-items?date_from=` queries.

#### Recommended sync loop

1. **Before** the first pull, read this endpoint and keep the whole response — your snapshot. Pull each list once with no `date_from`, then save the snapshot, but only if every pull succeeded.
2. On each poll, read this endpoint again. If the top-level `all` equals your snapshot's, stop — nothing changed anywhere.
3. Otherwise compare bucket by bucket and call only the endpoints for the buckets that moved (table above), each with `date_from` = your saved snapshot's top-level `all`, passed exactly as returned. `date_from` returns only what changed strictly after that value.
4. Once every fetch has succeeded, save this response as the new snapshot. If any failed, keep the old one — the next poll sends the same `date_from` and picks up what was missed.

Read the snapshot **before** the fetch it anchors, never after: a change made while you fetch would otherwise be stamped at or below the value you save, and no later `date_from` would return it. Full walkthrough: [Phase 1](/guides/sync#phase-1-initial-sync) and [Phase 2](/guides/sync#phase-2-continuous-sync).

#### Removal cascade

When `removed_from_list` moves, the user actively deleted items from their library. Refetch with `extended=simkl_ids_only` and diff against your local cache to detect deletions — `date_from` won't surface them. Also clear any local rating you stored for those items: Simkl wipes the rating when an item is removed, which is why removals can move both `removed_from_list` *and* `rated_at`.

<Card title="Sync guide — full walkthrough" icon="arrows-rotate" href="/guides/sync" horizontal>
 Two-phase model (initial pull → activities-checked delta loop), `date_from` semantics, deletion reconciliation, edge cases, and reference implementations in Node and Python.
</Card>



## OpenAPI

````yaml /openapi.json get /sync/activities
openapi: 3.1.0
info:
  title: Simkl API
  version: 1.0.0
  description: >-
    The **Simkl API** lets you build apps that track Movies, TV Shows, and Anime
    — scrobble playback, sync watch history, and pull rich metadata.


    All requests use HTTPS and return JSON. The base URL is
    `https://api.simkl.com`.


    **Every request needs three URL parameters and a `User-Agent` header:**


    ```

    /endpoint?client_id=YOUR_CLIENT_ID&app-name=my-app&app-version=1.0

    ```


    See [Headers and required parameters](/conventions/headers) for the full
    reference. Endpoints that read or modify a user's data also need an
    `Authorization: Bearer <token>` header — see [OAuth
    2.0](/api-reference/oauth) or the [PIN flow](/api-reference/pin).


    > ⚠️ **About the auto-rendered cURL examples on each endpoint page:** they
    omit `?client_id=…&app-name=…&app-version=…` from the URL for brevity. **You
    must add them yourself when copy-pasting**, or use the interactive **"Try
    it"** playground (it fills them in for you). This is a Mintlify rendering
    convention — every Mintlify-built API doc behaves the same way.


    **Get started**


    - [Quickstart](/quickstart) — first request in 60 seconds

    - [API rules](/api-rules) — what's allowed, what isn't

    - [Standard media objects](/conventions/standard-media-objects) — the shapes
    every endpoint speaks

    - [Errors](/conventions/errors) — every status code Simkl returns
  contact:
    name: Simkl Developer Support
    url: https://support.simkl.com
  termsOfService: https://simkl.com/about/policies/terms/
  license:
    name: Simkl API Terms of Use
    url: https://simkl.com/about/policies/terms/
  x-logo:
    url: https://i.simkl.com/img_tv/apiary_logo_api.png
    backgroundColor: '#0E5DAB'
    altText: Simkl
servers:
  - url: https://api.simkl.com
    description: Production API
  - url: https://data.simkl.in
    description: CDN for static, public data files (Calendar + Trending). No auth required.
security:
  - clientId: []
  - simklApiKey: []
tags:
  - name: OAuth V2
    description: >-
      Standards-compliant OAuth 2.0 with PKCE, scopes and refresh tokens. The
      recommended way to authenticate new apps.
  - name: OAuth 2.0
    description: >-
      OAuth 2.0 authorization-code flow for web and mobile apps. The user is
      redirected to Simkl, signs in, approves your app, and is redirected back
      with a `code` you exchange for an `access_token`. Long-lived tokens — no
      refresh-token flow needed.
    externalDocs:
      description: OAuth 2.0 walkthrough
      url: https://api.simkl.org/api-reference/oauth
  - name: PIN
    description: >-
      Device flow for TVs, consoles, smart watches, CLI tools — anywhere typing
      a URL is hard. Show a 5-character code; user enters it on simkl.com/pin;
      you poll for the access token. **No `client_secret` required.**
    externalDocs:
      description: PIN flow walkthrough
      url: https://api.simkl.org/api-reference/pin
  - name: Redirect
    description: >-
      Helper redirects for one-click "mark as watched", trailers, sharing, and
      more.
  - name: Search
    description: Find shows, movies, and anime by ID, text query, file name, or randomly.
    externalDocs:
      description: Search guide
      url: https://api.simkl.org/guides/search
  - name: Movies
    description: >-
      Browse the Simkl movies catalog: details, premieres, top-of-best, and
      genre filters.
  - name: TV
    description: >-
      Browse the Simkl TV catalog: details, episodes, what's airing, premieres,
      top-of-best, and genre filters.
  - name: Anime
    description: >-
      Browse the Simkl anime catalog: details, episodes, what's airing,
      premieres, top-of-best, and genre filters.
  - name: Ratings
    description: >-
      Read Simkl's average community rating, rank, drop rate, and external
      ratings (IMDB, MAL) for any item, or for every item in a user's lists.
  - name: Scrobble
    description: >-
      Report real-time playback to Simkl with `start`, `pause`, and `stop`. At ≥
      80 % progress (adjustable per call with `?min_progress=`) Simkl marks the
      item as watched automatically; below that the session is saved as a paused
      playback the user can resume from any device.


      See [Standard media objects](/conventions/standard-media-objects) for the
      supported ID keys.


      <!-- IDS_TABLE_START -->


      ### Supported ID keys


      Inside any `ids` object, pass as many of these as you have. Simkl resolves
      to the canonical record.


      | ID key | Type | Example |

      |---|---|---|

      | `simkl` | integer | `49108`. Simkl's canonical ID. Most reliable. |

      | `imdb` | string | `tt1520211` |

      | `tmdb` | integer | `76757` (for TV, specify `type`) |

      | `tvdb` | int / string | `153021` or `the-walking-dead` |

      | `mal` | integer | `4246` (MyAnimeList) |

      | `anidb` | integer | `10846`. Specifying just this is enough for anime
      lookups. |

      | `anilist` | integer | `21` |

      | `kitsu` | integer | `12` |

      | `anisearch` | integer | `2227` |

      | `animeplanet` | string | `one-piece` |

      | `livechart` | integer | `321` |

      | `letterboxd` | string | `the-truman-show` |

      | `netflix` | integer | `70210890` (movie ID) |

      | `traktslug` | string | `john-wick-chapter-4-2023` |


      > 📖 Full reference: [Standard media
      objects](/conventions/standard-media-objects)


      <!-- IDS_TABLE_END -->
    externalDocs:
      description: Scrobble guide
      url: https://api.simkl.org/guides/scrobble
  - name: Sync
    description: >-
      Use Simkl as a cloud backup for the user's watch history and lists
      (Watching, Plan to Watch, On Hold, Dropped, Completed). **Always check
      [`/sync/activities`](/api-reference/simkl/get-activities) first** and sync
      only the lists that have moved.


      All write endpoints accept arrays — batch aggressively. See [Standard
      media objects](/conventions/standard-media-objects) for the supported ID
      keys.


      <!-- IDS_TABLE_START -->


      ### Supported ID keys


      Inside any `ids` object, pass as many of these as you have. Simkl resolves
      to the canonical record.


      | ID key | Type | Example |

      |---|---|---|

      | `simkl` | integer | `49108`. Simkl's canonical ID. Most reliable. |

      | `imdb` | string | `tt1520211` |

      | `tmdb` | integer | `76757` (for TV, specify `type`) |

      | `tvdb` | int / string | `153021` or `the-walking-dead` |

      | `mal` | integer | `4246` (MyAnimeList) |

      | `anidb` | integer | `10846`. Specifying just this is enough for anime
      lookups. |

      | `anilist` | integer | `21` |

      | `kitsu` | integer | `12` |

      | `anisearch` | integer | `2227` |

      | `animeplanet` | string | `one-piece` |

      | `livechart` | integer | `321` |

      | `letterboxd` | string | `the-truman-show` |

      | `netflix` | integer | `70210890` (movie ID) |

      | `traktslug` | string | `john-wick-chapter-4-2023` |


      > 📖 Full reference: [Standard media
      objects](/conventions/standard-media-objects)


      <!-- IDS_TABLE_END -->
    externalDocs:
      description: Sync guide
      url: https://api.simkl.org/guides/sync
  - name: Users
    description: User profile, settings, and watch statistics.
  - name: Lists
    description: >-
      Custom lists, read-only and in beta. Requires a Simkl PRO or VIP access
      token.
externalDocs:
  description: Simkl API documentation
  url: https://api.simkl.org
paths:
  /sync/activities:
    get:
      tags:
        - Sync
      summary: Get Last Activities
      description: >-
        Returns the most recent update timestamps for each of the user's lists.
        **Always call this first** when syncing — compare against your
        last-saved timestamps and pull only the lists that have moved. This is
        the cheapest call in the API.


        #### Top-level fields


        | Field | Use |

        |---|---|

        | `all` | Newest timestamp anywhere in this response — every domain
        block, `settings`, `custom_lists`, ratings and playback. If it hasn't
        moved since your saved snapshot, nothing has. |

        | `settings.all` | Updates to account settings (name, time zone, …) at
        https://simkl.com/settings/. |

        | `tv_shows`, `anime`, `movies` | Per-domain timestamp groups. |

        | `custom_lists.lists` | Custom Lists timestamps, one level deeper than
        the other blocks — see [Custom Lists have their own
        timestamps](/guides/sync#custom-lists-have-their-own-timestamps). |


        #### Per-domain timestamps


        | Field | Meaning | Cheapest next call |

        |---|---|---|

        | `all` | Latest update in this domain. | — |

        | `rated_at` | A rating was added, changed, or removed. | Only when this
        moved — never on every sync, since every `/sync/all-items` item already
        carries `user_rating`. Then [`GET
        /sync/ratings/{type}`](/api-reference/simkl/get-user-ratings) with
        `date_from` and **no** rating segment — the changed ratings, removals
        included as `user_rating: null`. A rating-only change never appears in a
        `/sync/all-items` delta. Walkthrough: [Ratings come in their own
        delta](/guides/sync#ratings-delta). |

        | `playback` | A paused playback was added, resumed, or cleared. | [`GET
        /sync/playback/{type}`](/api-reference/simkl/get-playback-sessions) with
        `date_from` — only the changed sessions. |

        | `plantowatch`, `watching`, `completed`, `hold`, `dropped` | Items
        moved into/out of these lists, or episodes were marked
        watched/unwatched. | [`GET
        /sync/all-items/{type}/{status}`](/api-reference/simkl/get-all-items)
        with `date_from` and `extended=full` — full delta of modified items.
        Walkthrough: [Phase 2 — Continuous
        sync](/guides/sync#phase-2-continuous-sync). |

        | `removed_from_list` | Items were deleted from the library entirely.
        `date_from` **won't surface removals** — you can only detect them by
        diffing. | [`GET
        /sync/all-items/{type}/{status}`](/api-reference/simkl/get-all-items)
        with `extended=simkl_ids_only` — cheapest possible payload (just the
        IDs) — and diff against your local cache. Walkthrough: [Detecting
        deletions](/guides/sync#detecting-deletions). |


        > Movies don't have `watching` or `hold` — movies are atomic, so those
        statuses don't apply.


        #### Auto-move side effects


        When a user **rates** an unrated item, Simkl auto-files it: movies →
        `Completed`, shows/anime → `Watching`. That auto-move bumps the
        corresponding list timestamp, so the rated item also appears in
        subsequent `/sync/all-items?date_from=` queries.


        #### Recommended sync loop


        1. **Before** the first pull, read this endpoint and keep the whole
        response — your snapshot. Pull each list once with no `date_from`, then
        save the snapshot, but only if every pull succeeded.

        2. On each poll, read this endpoint again. If the top-level `all` equals
        your snapshot's, stop — nothing changed anywhere.

        3. Otherwise compare bucket by bucket and call only the endpoints for
        the buckets that moved (table above), each with `date_from` = your saved
        snapshot's top-level `all`, passed exactly as returned. `date_from`
        returns only what changed strictly after that value.

        4. Once every fetch has succeeded, save this response as the new
        snapshot. If any failed, keep the old one — the next poll sends the same
        `date_from` and picks up what was missed.


        Read the snapshot **before** the fetch it anchors, never after: a change
        made while you fetch would otherwise be stamped at or below the value
        you save, and no later `date_from` would return it. Full walkthrough:
        [Phase 1](/guides/sync#phase-1-initial-sync) and [Phase
        2](/guides/sync#phase-2-continuous-sync).


        #### Removal cascade


        When `removed_from_list` moves, the user actively deleted items from
        their library. Refetch with `extended=simkl_ids_only` and diff against
        your local cache to detect deletions — `date_from` won't surface them.
        Also clear any local rating you stored for those items: Simkl wipes the
        rating when an item is removed, which is why removals can move both
        `removed_from_list` *and* `rated_at`.


        <Card title="Sync guide — full walkthrough" icon="arrows-rotate"
        href="/guides/sync" horizontal>
         Two-phase model (initial pull → activities-checked delta loop), `date_from` semantics, deletion reconciliation, edge cases, and reference implementations in Node and Python.
        </Card>
      operationId: get-sync-activities
      parameters:
        - $ref: '#/components/parameters/ClientIdQuery'
        - $ref: '#/components/parameters/AppNameQuery'
        - $ref: '#/components/parameters/AppVersionQuery'
        - $ref: '#/components/parameters/UserAgentHeader'
      responses:
        '200':
          description: OK
          headers: {}
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Activities'
              examples:
                active_user:
                  summary: Active user — every bucket has activity
                  description: >-
                    Note where the top-level `all` comes from: no watchlist
                    block carries `2026-05-14T07:12:20Z` — it is
                    `custom_lists.lists.all`. Custom-list activity counts
                    towards `all` like everything else, so `all` moving does not
                    on its own mean the watchlist changed.
                  value:
                    all: '2026-05-14T07:12:20Z'
                    settings:
                      all: '2026-02-15T22:53:03Z'
                    tv_shows:
                      all: '2026-05-14T06:49:56Z'
                      rated_at: '2026-04-10T05:34:55Z'
                      playback: '2026-04-11T10:36:01Z'
                      plantowatch: '2026-04-10T05:42:42Z'
                      watching: '2026-05-04T19:40:58Z'
                      completed: '2026-04-11T11:50:21Z'
                      hold: '2026-05-14T06:49:56Z'
                      dropped: '2026-05-14T06:49:56Z'
                      removed_from_list: '2026-04-10T05:34:55Z'
                    anime:
                      all: '2026-05-14T06:50:38Z'
                      rated_at: '2026-04-10T05:34:55Z'
                      playback: '2026-05-14T06:50:38Z'
                      plantowatch: '2026-05-14T06:41:53Z'
                      watching: '2026-05-14T06:43:00Z'
                      completed: '2026-05-14T06:42:42Z'
                      hold: '2026-05-14T06:42:05Z'
                      dropped: '2026-05-14T06:49:56Z'
                      removed_from_list: '2026-04-10T05:34:55Z'
                    movies:
                      all: '2026-05-14T06:50:38Z'
                      rated_at: '2026-05-14T06:43:20Z'
                      playback: '2026-05-14T06:50:38Z'
                      plantowatch: '2026-05-14T06:43:11Z'
                      completed: '2026-05-14T06:43:15Z'
                      dropped: '2026-05-14T06:49:56Z'
                      removed_from_list: '2026-04-10T05:34:55Z'
                    custom_lists:
                      lists:
                        all: '2026-05-14T07:12:20Z'
                        regular: '2026-05-14T07:12:20Z'
                        favorites: '2026-05-14T06:58:02Z'
                        recommendations: '2026-05-13T21:04:39Z'
                        auto: '2026-05-14T07:05:11Z'
                fresh_user:
                  summary: Brand-new user — just authenticated, library empty
                  description: >-
                    A user who has just connected your app and hasn't touched
                    their Simkl library yet. Every timestamp is `null` because
                    no event has fired in any bucket. `settings.all` is also
                    null unless the user changed a setting during signup. This
                    is *Type 1* null — "never happened yet".
                  value:
                    all: null
                    settings:
                      all: null
                    tv_shows:
                      all: null
                      rated_at: null
                      playback: null
                      plantowatch: null
                      watching: null
                      completed: null
                      hold: null
                      dropped: null
                      removed_from_list: null
                    anime:
                      all: null
                      rated_at: null
                      playback: null
                      plantowatch: null
                      watching: null
                      completed: null
                      hold: null
                      dropped: null
                      removed_from_list: null
                    movies:
                      all: null
                      rated_at: null
                      playback: null
                      plantowatch: null
                      completed: null
                      dropped: null
                      removed_from_list: null
                    custom_lists:
                      lists:
                        all: null
                        regular: null
                        favorites: null
                        recommendations: null
                        auto: null
                partial_user:
                  summary: Mid-state user — TV-only, some buckets untouched
                  description: >-
                    A user who actively syncs TV shows but has never added an
                    anime or rated a movie. Demonstrates the common mix of
                    populated and null fields: the buckets they've used have
                    timestamps, the ones they haven't are null.
                  value:
                    all: '2024-08-19T12:34:56Z'
                    settings:
                      all: '2023-11-02T18:01:45Z'
                    tv_shows:
                      all: '2024-08-19T12:34:56Z'
                      rated_at: '2024-08-19T12:34:56Z'
                      playback: null
                      plantowatch: '2024-07-30T09:12:00Z'
                      watching: '2024-08-19T12:34:56Z'
                      completed: '2024-08-15T22:18:00Z'
                      hold: null
                      dropped: null
                      removed_from_list: '2024-08-10T19:45:13Z'
                    anime:
                      all: null
                      rated_at: null
                      playback: null
                      plantowatch: null
                      watching: null
                      completed: null
                      hold: null
                      dropped: null
                      removed_from_list: null
                    movies:
                      all: '2024-08-12T20:00:00Z'
                      rated_at: null
                      playback: null
                      plantowatch: '2024-08-12T20:00:00Z'
                      completed: null
                      dropped: null
                      removed_from_list: null
                    custom_lists:
                      lists:
                        all: '2024-08-14T08:20:11Z'
                        regular: null
                        favorites: '2024-08-14T08:20:11Z'
                        recommendations: null
                        auto: null
        '401':
          $ref: '#/components/responses/Unauthorized'
        '412':
          $ref: '#/components/responses/ClientIdFailed'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
      security:
        - clientId: []
          bearerAuth: []
        - simklApiKey: []
          bearerAuth: []
      x-codeSamples:
        - lang: curl
          label: cURL
          source: >-
            curl
            "https://api.simkl.com/sync/activities?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0"
            \
              -H "User-Agent: my-app-name/1.0" \
              -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
        - lang: JavaScript
          label: Node
          source: >-
            const params = new URLSearchParams({
              client_id:     CLIENT_ID,
              'app-name':    'my-app-name',
              'app-version': '1.0',
            });

            const activities = await
            fetch(`https://api.simkl.com/sync/activities?${params}`, {
              headers: {
                'User-Agent':    'my-app-name/1.0',
                'Authorization': `Bearer ${ACCESS_TOKEN}`,
              },
            }).then(r => r.json());
        - lang: Python
          label: Python
          source: |-
            import requests
            activities = requests.get(
                'https://api.simkl.com/sync/activities',
                params={
                    'client_id':   CLIENT_ID,
                    'app-name':    'my-app-name',
                    'app-version': '1.0',
                },
                headers={
                    'User-Agent':    'my-app-name/1.0',
                    'Authorization': f'Bearer {ACCESS_TOKEN}',
                },
            ).json()
components:
  parameters:
    ClientIdQuery:
      name: client_id
      in: query
      required: true
      description: >-
        Your **`client_id`** from your [Simkl developer
        settings](https://simkl.com/settings/developer/). Required on every
        request.
      schema:
        type: string
      example: YOUR_CLIENT_ID
    AppNameQuery:
      name: app-name
      in: query
      required: true
      description: >-
        Short, lowercase identifier for your app (e.g. `plex-scrobbler`,
        `kodi-bridge`). Helps Simkl identify which apps are using the API.
      schema:
        type: string
      example: my-app
    AppVersionQuery:
      name: app-version
      in: query
      required: true
      description: >-
        Your app's current version (e.g. `1.0`, `2.4.1`). Helps Simkl debug
        issues you report.
      schema:
        type: string
      example: '1.0'
    UserAgentHeader:
      name: User-Agent
      in: header
      required: true
      description: >-
        Descriptive identifier for your app, ideally `name/version`. Examples:
        `PlexMediaServer/1.43.1.10540`, `kodi-simkl/0.9.2`, `MyApp/2.4.1
        (https://myapp.com)`.
      schema:
        type: string
      example: my-app/1.0
  schemas:
    Activities:
      type: object
      description: >-
        Last-activity envelope returned by `GET /sync/activities`. Use `all` as
        the cheapest first-pass check, then drill into a per-domain block only
        when its `all` has moved. The top-level `all` now also moves when a
        custom list changes, so a loop that gates on it will wake for those as
        well.
      required:
        - all
        - settings
        - tv_shows
        - anime
        - movies
        - custom_lists
      properties:
        all:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Newest timestamp across
            every domain and bucket. Best first-level check — if this hasn't
            moved since your last sync, nothing has changed. This includes
            custom-list activity, so `all` can move when only a list changed.
        settings:
          $ref: '#/components/schemas/ActivitySettingsBlock'
        tv_shows:
          $ref: '#/components/schemas/ActivityShowBlock'
        anime:
          $ref: '#/components/schemas/ActivityShowBlock'
        movies:
          $ref: '#/components/schemas/ActivityMovieBlock'
        custom_lists:
          $ref: '#/components/schemas/ActivityCustomListsBlock'
    ActivitySettingsBlock:
      type: object
      description: >-
        Top-level settings change marker. Bumped when the user changes any
        setting at https://simkl.com/settings/ (display name, time zone,
        privacy, etc.).
      required:
        - all
      properties:
        all:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Most recent change to
            account settings, or `null` if the user has never changed any
            setting since signup.
    ActivityShowBlock:
      type: object
      description: >-
        Per-domain timestamps for TV shows and anime. Both types share the full
        five-status set (watching, plantowatch, hold, dropped, completed). Each
        timestamp is an ISO-8601 datetime, or `null` if the user has never had
        activity in that bucket — a *Type 1* null ("never happened yet", see
        [Null-value conventions](/conventions/null-values)).
      required:
        - all
        - rated_at
        - playback
        - plantowatch
        - watching
        - completed
        - hold
        - dropped
        - removed_from_list
      properties:
        all:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Latest update across this
            domain. Fast first-pass check before drilling into per-status
            fields.
        rated_at:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped on any rating
            add/change/remove for this domain. After a bump, call `GET
            /sync/ratings/{type}` with `date_from` and **no** rating segment:
            removed ratings come back as `user_rating: null`, and a rating
            segment would drop them. A rating-only change never appears in a
            `/sync/all-items` delta.
        playback:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped on any
            scrobble/playback activity. After a bump, call `GET
            /sync/playback/{type}` to refresh in-progress sessions.
        plantowatch:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped when items move
            into or out of the `plantowatch` bucket.
        watching:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped when items move
            into or out of the `watching` bucket, or when episodes are
            marked/unmarked watched.
        completed:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped when items move
            into or out of the `completed` bucket.
        hold:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped when items move
            into or out of the `hold` bucket.
        dropped:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped when items move
            into or out of the `dropped` bucket.
        removed_from_list:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped when items are
            removed from the user's library entirely. `date_from` won't surface
            removals — to reconcile, call [`GET
            /sync/all-items/{type}/{status}`](/api-reference/simkl/get-all-items)
            with `extended=simkl_ids_only` (cheapest payload — just the IDs) and
            diff against your local cache. Walkthrough: [Detecting
            deletions](/guides/sync#detecting-deletions).
    ActivityMovieBlock:
      type: object
      description: >-
        Per-domain timestamps for movies. Movies are single-session content, so
        this block **does not include `watching` or `hold`** — those keys are
        omitted entirely (not null). See [Watchlist
        statuses](/conventions/list-statuses) for the per-type matrix.
      required:
        - all
        - rated_at
        - playback
        - plantowatch
        - completed
        - dropped
        - removed_from_list
      properties:
        all:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Latest update across
            movies.
        rated_at:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped on any movie
            rating add/change/remove. After a bump, call `GET
            /sync/ratings/movies` with `date_from` and **no** rating segment:
            removed ratings come back as `user_rating: null`, and a rating
            segment would drop them. A rating-only change never appears in a
            `/sync/all-items` delta.
        playback:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped on any movie
            scrobble/playback activity.
        plantowatch:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped when movies move
            into or out of `plantowatch`.
        completed:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped when movies move
            into or out of `completed`.
        dropped:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped when movies move
            into or out of `dropped`.
        removed_from_list:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Bumped when movies are
            removed from the user's library entirely. `date_from` won't surface
            removals — call [`GET
            /sync/all-items/movies/{status}`](/api-reference/simkl/get-all-items)
            with `extended=simkl_ids_only` (cheapest payload — just the IDs) and
            diff against your local cache. Walkthrough: [Detecting
            deletions](/guides/sync#detecting-deletions).
    ActivityCustomListsBlock:
      type: object
      description: >-
        Custom Lists activity. The timestamps sit under `lists` rather than
        directly on this object, leaving room for other custom-list activity to
        be added alongside them later — so read `custom_lists.lists.all`, not
        `custom_lists.all`.
      required:
        - lists
      properties:
        lists:
          $ref: '#/components/schemas/ActivityCustomListsSet'
    ErrorResponse:
      type: object
      description: >-
        Standard error envelope for 4xx and 5xx responses. Branch on `error`
        (machine-readable identifier) — `message`, when present, is
        human-readable guidance and is **not stable across releases**.
      properties:
        error:
          type: string
          description: >-
            Machine-readable error identifier. Stable across responses — use
            this for programmatic branching in client code. Examples:
            `user_token_failed`, `client_id_failed`, `empty_field`,
            `wrong_parameter`, `id_err`, `rate_limit`.
          example: user_token_failed
        code:
          type: integer
          description: >-
            HTTP status code echoed in the body for convenience — same value as
            the response status line. Always an integer.
          example: 401
        message:
          type: string
          description: >-
            Human-readable error guidance. Optional — present on most errors,
            but not guaranteed. May reference the specific field or value that
            triggered the error. NOT stable; do not parse.
          example: Your client_id is wrong. Try another one
      required:
        - error
        - code
    ActivityCustomListsSet:
      type: object
      description: >-
        Last-change timestamps for the user's [Custom
        Lists](/guides/custom-lists), grouped by the kind of list. Each bucket
        moves when a list of that kind is created, renamed, reordered, deleted,
        or has items added or removed.
      required:
        - all
        - regular
        - favorites
        - recommendations
        - auto
      properties:
        all:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 1 null — no activity of this kind has ever been recorded for
            this user. See [Null and missing values](/conventions/null-values).
            Newest timestamp across the four buckets below. Check this first —
            if it has not moved, no custom list has changed and you can skip
            refetching them.
        regular:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 1 null — no activity of this kind has ever been recorded for
            this user. See [Null and missing values](/conventions/null-values).
            Hand-curated lists the user made themselves — the `regular` list
            type, and the specialised kinds that are not broken out separately
            below.
        favorites:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 1 null — no activity of this kind has ever been recorded for
            this user. See [Null and missing values](/conventions/null-values).
            The user's favourites. Note the spelling seam: a list's own `type`
            field reads `favorite` (singular), while this activity bucket is
            `favorites` (plural).
        recommendations:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 1 null — no activity of this kind has ever been recorded for
            this user. See [Null and missing values](/conventions/null-values).
            Recommendation lists. All recommendation kinds share this one
            bucket, so it cannot tell you which of them changed.
        auto:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Type 1 null — no activity of this kind has ever been recorded for
            this user. See [Null and missing values](/conventions/null-values).
            Auto lists — saved Discover filters. This moves only when the user
            changes an auto list's **settings**, not when its contents are
            regenerated. Simkl rebuilds auto-list contents about once a day and
            that refresh does **not** move this timestamp, so it cannot tell you
            an auto list's items are stale — refresh those on your own schedule.
  responses:
    Unauthorized:
      description: >-
        Missing or invalid user access token. Provide a valid `Authorization:
        Bearer <access_token>` header.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: user_token_failed
            code: 401
    ClientIdFailed:
      description: >-
        Your `client_id` is missing, wrong, disabled, or has hit a request
        limit. Verify in your [developer
        settings](https://simkl.com/settings/developer/).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: client_id_failed
            code: 412
            message: Your client_id is wrong. Try another one
    RateLimited:
      description: >-
        Too many requests in too short a window. Back off and retry with
        exponential backoff — see [Rate limits](/resources/rate-limits) for the
        playbook.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: rate_limit
            code: 429
    ServerError:
      description: >-
        Something is broken on Simkl's side. Retry after a short delay. If it
        persists, report on the [Simkl Discord](https://discord.gg/MJsWNE4).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: internal
            code: 500
  securitySchemes:
    clientId:
      type: apiKey
      in: query
      name: client_id
      description: >-
        Preferred form: your `client_id` as a URL query parameter on every
        request. Self-describing in logs and curl commands. See [Headers and
        required parameters](/conventions/headers).
      x-default: YOUR_CLIENT_ID
    simklApiKey:
      type: apiKey
      in: header
      name: simkl-api-key
      description: >-
        Optional alias for the `client_id` query parameter. Simkl accepts your
        `client_id` either as the `simkl-api-key` request header **or** as the
        `?client_id=…` query parameter — pick one. The query-parameter form is
        preferred because it makes the request fully self-describing in URL
        form.
      x-default: YOUR_CLIENT_ID
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        A user `access_token`, sent as `Authorization: Bearer ...`. Required for
        endpoints that read or modify the user's library, scrobble session,
        ratings, settings, or playbacks. Every flow returns the same kind of
        token. See [Set up authentication](/api-reference/auth).
      x-default: YOUR_ACCESS_TOKEN

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.