> ## 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.

# Check-in

> A **fire-and-forget version of [`/scrobble/start`](/api-reference/simkl/scrobble-start)**. Same effect on the user's [dashboard](https://simkl.com/) — the title appears in the **"Watching now"** widget with an animated, runtime-extrapolated progress bar — but you don't need to follow up with `pause` / `stop` events. Simkl computes progress server-side from `(now − checkin time) ÷ runtime`; when that reaches 100%, the title is auto-marked watched.

> **Auto-completion timing:** Once the computed progress reaches 100%, marking the item as watched can take anywhere from **0 to 2 minutes**. Some check-ins finalize instantly; others sit at 100% briefly while the background worker picks them up. Don't treat the delay as a failure — if you need to know exactly when it lands, check [`GET /sync/activities`](/api-reference/simkl/get-activities) after the runtime expires; when the relevant `completed` / `watching` timestamp bumps, refresh via [`GET /sync/all-items/{type}/{status}?date_from=…`](/api-reference/simkl/get-all-items). That's the same incremental loop documented in the [Sync guide](/guides/sync) — no extra calls beyond what a normal sync would already do.

The user can browse and clean up active check-ins at the [Playback progress manager](https://simkl.com/my/history/playback-progress-manager/).

#### When to use checkin vs the start / pause / stop loop

| Situation | Use |
|---|---|
| You have real player events (play / pause / stop) and want exact progress | [`/scrobble/start`](/api-reference/simkl/scrobble-start) → [`/pause`](/api-reference/simkl/scrobble-pause) → [`/stop`](/api-reference/simkl/scrobble-stop) loop |
| You can't reliably hook into pause / stop (some embedded players, casting flows, hardware AV-out, social "I'm watching this" buttons) | `checkin` |
| You just want to record a watch after the fact, no live status | [`POST /sync/history`](/api-reference/simkl/add-to-history) |

#### Seek and scrub behavior

No progress to update — the user can scrub or seek freely after check-in. The server's runtime extrapolation doesn't track real player position, so a user who checks in and then walks away is also auto-marked watched at the calculated runtime expiry. That's a feature, not a bug, for fire-and-forget integrations.

> **Note:** A 20-second per-user lock collision returns HTTP `400` with `RATE_LIMIT`, not `429` — the lock failure is treated as a malformed request from a duplicate-fire client.

<Card title="Scrobble guide — full walkthrough" icon="play" href="/guides/scrobble" horizontal>
 Real-time playback tracking — `/start`, `/pause`, `/stop` lifecycle, paused-playback resumption across devices, when scrobble auto-completes, and the difference between `/scrobble/checkin` (fire-and-forget) and `/scrobble/start` (active tracking).
</Card>

Alternative to `episode.season` + `episode.number`: pass `episode.ids` with `tvdb` or `anidb` to identify the exact episode by external episode ID. Useful for media-server integrations that have a TVDB or AniDB episode ID but not the season/number mapping. (Episode-level `imdb` and `tmdb` IDs are **not** accepted — those exist only at the show/movie level. Use the `show`/`anime` object's `ids` for those.) If both forms are sent, `episode.ids` takes precedence.

<Tip>
**Which IDs can I send/expect?** All accepted input identifiers and the keys you'll see echoed back in responses are listed at [**Standard media objects → Supported ID keys**](/conventions/standard-media-objects#supported-id-keys). Send every ID you have on writes — Simkl picks the first that resolves and ignores the rest. Reminder: `slug` is **response-only** (never send it on a request).
</Tip>



## OpenAPI

````yaml /openapi.json post /scrobble/checkin
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 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 Simkl marks the item as watched automatically; below 80 %
      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.
externalDocs:
  description: Simkl API documentation
  url: https://api.simkl.org
paths:
  /scrobble/checkin:
    post:
      tags:
        - Scrobble
      summary: Check-in
      description: >-
        A **fire-and-forget version of
        [`/scrobble/start`](/api-reference/simkl/scrobble-start)**. Same effect
        on the user's [dashboard](https://simkl.com/) — the title appears in the
        **"Watching now"** widget with an animated, runtime-extrapolated
        progress bar — but you don't need to follow up with `pause` / `stop`
        events. Simkl computes progress server-side from `(now − checkin time) ÷
        runtime`; when that reaches 100%, the title is auto-marked watched.


        > **Auto-completion timing:** Once the computed progress reaches 100%,
        marking the item as watched can take anywhere from **0 to 2 minutes**.
        Some check-ins finalize instantly; others sit at 100% briefly while the
        background worker picks them up. Don't treat the delay as a failure — if
        you need to know exactly when it lands, check [`GET
        /sync/activities`](/api-reference/simkl/get-activities) after the
        runtime expires; when the relevant `completed` / `watching` timestamp
        bumps, refresh via [`GET
        /sync/all-items/{type}/{status}?date_from=…`](/api-reference/simkl/get-all-items).
        That's the same incremental loop documented in the [Sync
        guide](/guides/sync) — no extra calls beyond what a normal sync would
        already do.


        The user can browse and clean up active check-ins at the [Playback
        progress
        manager](https://simkl.com/my/history/playback-progress-manager/).


        #### When to use checkin vs the start / pause / stop loop


        | Situation | Use |

        |---|---|

        | You have real player events (play / pause / stop) and want exact
        progress | [`/scrobble/start`](/api-reference/simkl/scrobble-start) →
        [`/pause`](/api-reference/simkl/scrobble-pause) →
        [`/stop`](/api-reference/simkl/scrobble-stop) loop |

        | You can't reliably hook into pause / stop (some embedded players,
        casting flows, hardware AV-out, social "I'm watching this" buttons) |
        `checkin` |

        | You just want to record a watch after the fact, no live status |
        [`POST /sync/history`](/api-reference/simkl/add-to-history) |


        #### Seek and scrub behavior


        No progress to update — the user can scrub or seek freely after
        check-in. The server's runtime extrapolation doesn't track real player
        position, so a user who checks in and then walks away is also
        auto-marked watched at the calculated runtime expiry. That's a feature,
        not a bug, for fire-and-forget integrations.


        > **Note:** A 20-second per-user lock collision returns HTTP `400` with
        `RATE_LIMIT`, not `429` — the lock failure is treated as a malformed
        request from a duplicate-fire client.


        <Card title="Scrobble guide — full walkthrough" icon="play"
        href="/guides/scrobble" horizontal>
         Real-time playback tracking — `/start`, `/pause`, `/stop` lifecycle, paused-playback resumption across devices, when scrobble auto-completes, and the difference between `/scrobble/checkin` (fire-and-forget) and `/scrobble/start` (active tracking).
        </Card>


        Alternative to `episode.season` + `episode.number`: pass `episode.ids`
        with `tvdb` or `anidb` to identify the exact episode by external episode
        ID. Useful for media-server integrations that have a TVDB or AniDB
        episode ID but not the season/number mapping. (Episode-level `imdb` and
        `tmdb` IDs are **not** accepted — those exist only at the show/movie
        level. Use the `show`/`anime` object's `ids` for those.) If both forms
        are sent, `episode.ids` takes precedence.


        <Tip>

        **Which IDs can I send/expect?** All accepted input identifiers and the
        keys you'll see echoed back in responses are listed at [**Standard media
        objects → Supported ID
        keys**](/conventions/standard-media-objects#supported-id-keys). Send
        every ID you have on writes — Simkl picks the first that resolves and
        ignores the rest. Reminder: `slug` is **response-only** (never send it
        on a request).

        </Tip>
      operationId: post-scrobble-checkin
      parameters:
        - $ref: '#/components/parameters/ClientIdQuery'
        - $ref: '#/components/parameters/AppNameQuery'
        - $ref: '#/components/parameters/AppVersionQuery'
        - $ref: '#/components/parameters/UserAgentHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScrobbleBody'
            examples:
              checkin_movie_full_ids:
                summary: >-
                  Movie — kitchen-sink request: every ID + title + year +
                  progress
                description: >-
                  Recommended shape: send every ID you have (Simkl + IMDB + TMDB
                  + TVDB), plus `title` and `year` as a tie-breaker if any
                  single ID is wrong or stale. Simkl resolves to the canonical
                  record and echoes the full ID set in the response. `progress`
                  is optional on `/checkin` (the server ignores the number and
                  runtime-extrapolates instead) but apps usually still send it
                  for parity with `/scrobble/start`.
                value:
                  progress: 12.5
                  movie:
                    title: 'Dune: Part Two'
                    year: 2024
                    ids:
                      simkl: 1015859
                      imdb: tt15239678
                      tmdb: '693134'
                      tvdb: '353275'
              checkin_movie_external_ids_only:
                summary: Movie — IMDB + TMDB only (no Simkl ID known yet)
                description: >-
                  Tracker apps importing from third-party catalogs (Trakt, Plex,
                  Letterboxd) often have IMDB and/or TMDB IDs but no Simkl ID
                  yet. Send any combination — Simkl resolves to the canonical
                  record and echoes back the full ID set in the response so you
                  can cache the Simkl ID for next time.
                value:
                  progress: 25
                  movie:
                    title: Oppenheimer
                    year: 2023
                    ids:
                      imdb: tt15398776
                      tmdb: '872585'
              checkin_movie_title_year_fallback:
                summary: Movie — title + year ONLY (no IDs at all)
                description: >-
                  Fallback shape when you have nothing but the file name. Simkl
                  matches by title + year against the catalog. Less reliable
                  than passing an ID — two movies with the same name in the same
                  year (rare but happens) will pick one. Always prefer passing
                  at least one ID when you have it.
                value:
                  progress: 50
                  movie:
                    title: Parasite
                    year: 2019
              checkin_tv_episode_by_season_number:
                summary: TV episode — full show IDs + episode season/number + progress
                description: >-
                  Standard TV check-in. Send every show ID you have (Simkl +
                  IMDB + TMDB + TVDB) plus `title` and `year`, and the `episode`
                  block with `season` + `number`. Simkl maps season/number to
                  the canonical episode on its side.
                value:
                  progress: 5
                  show:
                    title: The Last of Us
                    year: 2023
                    ids:
                      simkl: 1411674
                      imdb: tt3581920
                      tmdb: '100088'
                      tvdb: '392256'
                  episode:
                    season: 2
                    number: 1
              checkin_tv_episode_via_episode_id:
                summary: TV episode — by `episode.ids.tvdb` (Plex / Sonarr / Jellyfin)
                description: >-
                  Media-server integrations (Plex, Sonarr, Jellyfin) often have
                  the TVDB episode ID directly, with no season/number mapping
                  needed. Pass it as `episode.ids.tvdb` — this takes precedence
                  over `season`+`number` if both are sent. Episode-level `imdb`
                  and `tmdb` IDs are NOT accepted (those only exist at
                  show/movie level — use the `show` block's `ids` for those).
                value:
                  progress: 32.4
                  show:
                    title: Breaking Bad
                    year: 2008
                    ids:
                      simkl: 41142
                      imdb: tt0903747
                      tmdb: '1396'
                      tvdb: '81189'
                  episode:
                    ids:
                      tvdb: 350289
              checkin_anime_episode_full_ids:
                summary: >-
                  Anime episode — every anime ID + episode season/number (AniDB
                  sequential)
                description: >-
                  Use the `anime` key (instead of `show`) when you have
                  anime-only IDs. Pass everything you have: `mal`, `anidb`,
                  `anilist`, `kitsu`, and even `simkl`/`imdb`/`tvdb` if you've
                  got them. AniDB numbering is single-season — `episode.season`
                  is always `1`, and `episode.number` is the absolute episode
                  index across the whole series. For TVDB-style per-season anime
                  numbering, send `use_tvdb_anime_seasons: true` on
                  `/sync/history` instead — scrobble endpoints always use AniDB
                  sequential.
                value:
                  progress: 8.2
                  anime:
                    title: Attack on Titan
                    year: 2013
                    ids:
                      simkl: 39115
                      mal: 16498
                      anidb: 9541
                      anilist: 16498
                      kitsu: 7442
                      imdb: tt2560140
                      tvdb: 267440
                  episode:
                    season: 1
                    number: 1
              checkin_anime_episode_via_episode_id:
                summary: Anime episode — by `episode.ids.anidb` (Taiga-style)
                description: >-
                  AniDB episode IDs are unique across the anime catalog — pass
                  `episode.ids.anidb` to identify the exact episode regardless
                  of season/number ambiguity. Works the same way as
                  `episode.ids.tvdb` does for TV, just for AniDB-sourced players
                  like Taiga or anime-only trackers.
                value:
                  progress: 47
                  anime:
                    title: Cowboy Bebop
                    year: 1998
                    ids:
                      simkl: 37089
                      mal: 1
                      anidb: 23
                      anilist: 1
                      kitsu: 1
                  episode:
                    ids:
                      anidb: 1565
              checkin_no_progress:
                summary: Fire-and-forget — `progress` omitted entirely
                description: >-
                  Cleanest call when you don't have a real progress value to
                  share. The `progress` field is OPTIONAL on `/checkin` and
                  IGNORED by the server either way — Simkl computes progress as
                  `(now − checkin time) ÷ runtime`. Sending the IDs + title +
                  year is still useful so Simkl can resolve the title reliably.
                value:
                  movie:
                    title: Spirited Away
                    year: 2001
                    ids:
                      simkl: 53538
                      imdb: tt0245429
                      tmdb: '129'
                      mal: 199
                      anidb: 23
      responses:
        '201':
          description: Created
          headers: {}
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrobbleResponse'
              examples:
                checkin_movie_full_ids:
                  summary: >-
                    Movie — kitchen-sink request: every ID + title + year +
                    progress
                  description: >-
                    Response echoes the canonical ID set (note `slug` appears in
                    the response — it's not something you send). Even when you
                    sent every ID you have, Simkl may add ones from its catalog
                    you didn't know about.
                  value:
                    id: 10916896
                    action: checkin
                    progress: 12.5
                    movie:
                      title: 'Dune: Part Two'
                      year: 2024
                      ids:
                        simkl: 1015859
                        slug: dune-part-two
                        imdb: tt15239678
                        tmdb: '693134'
                        tvdb: '353275'
                checkin_movie_external_ids_only:
                  summary: Movie — IMDB + TMDB only (no Simkl ID known yet)
                  description: >-
                    Response carries the resolved `simkl` id — cache it
                    client-side so the next call can send the full ID set.
                  value:
                    id: 10916896
                    action: checkin
                    progress: 25
                    movie:
                      title: Oppenheimer
                      year: 2023
                      ids:
                        simkl: 1015858
                        slug: oppenheimer
                        imdb: tt15398776
                        tmdb: '872585'
                checkin_movie_title_year_fallback:
                  summary: Movie — title + year ONLY (no IDs at all)
                  description: >-
                    Response fills in the canonical ID set Simkl matched
                    against. If the match was ambiguous, the `simkl` id here
                    tells you which catalog row Simkl picked.
                  value:
                    id: 10916896
                    action: checkin
                    progress: 50
                    movie:
                      title: Parasite
                      year: 2019
                      ids:
                        simkl: 752138
                        slug: parasite
                        imdb: tt6751668
                        tmdb: '496243'
                        tvdb: '41517'
                checkin_tv_episode_by_season_number:
                  summary: >-
                    TV episode — full show IDs + episode season/number +
                    progress
                  description: >-
                    Standard TV check-in. Send the show's ids/title/year plus
                    the `episode` block with `season` and `number`. Anime titles
                    can also use this shape under `show` if the only IDs you
                    have are TMDB/TVDB — Simkl auto-resolves to the anime
                    catalog.
                  value:
                    id: 10916896
                    action: checkin
                    progress: 5
                    show:
                      title: The Last of Us
                      year: 2023
                      ids:
                        simkl: 1411674
                        slug: the-last-of-us
                        imdb: tt3581920
                        tmdb: '100088'
                        tvdb: '392256'
                    episode:
                      season: 2
                      number: 1
                      title: Future Days
                      ids:
                        tvdb: 10515844
                        tmdb: 4524088
                checkin_tv_episode_via_episode_id:
                  summary: >-
                    TV episode — by `episode.ids.tvdb` (Plex / Sonarr /
                    Jellyfin)
                  description: >-
                    Media-server integrations (Plex, Sonarr, Jellyfin) often
                    have the TVDB episode ID but no season/number mapping. Pass
                    it as `episode.ids.tvdb` — this takes precedence over
                    `season`+`number` if both are sent. Episode-level `imdb` and
                    `tmdb` IDs are NOT accepted (those only exist at show/movie
                    level).
                  value:
                    id: 10916896
                    action: checkin
                    progress: 32.4
                    show:
                      title: Breaking Bad
                      year: 2008
                      ids:
                        simkl: 41142
                        slug: breaking-bad
                        imdb: tt0903747
                        tmdb: '1396'
                        tvdb: '81189'
                    episode:
                      season: 1
                      number: 1
                      title: Pilot
                      ids:
                        tvdb: 350289
                        tmdb: 62085
                checkin_anime_episode_full_ids:
                  summary: >-
                    Anime episode — every anime ID + episode season/number
                    (AniDB sequential)
                  description: >-
                    Response echoes the resolved anime catalog row including
                    `kitsu` if Simkl had it on file. The `episode` block adds
                    the resolved episode `title` and an `ids` block with
                    TVDB/AniDB episode-level IDs.
                  value:
                    id: 10916896
                    action: checkin
                    progress: 8.2
                    anime:
                      title: Attack on Titan
                      year: 2013
                      ids:
                        simkl: 39115
                        slug: attack-on-titan
                        mal: '16498'
                        anidb: '9541'
                        anilist: '16498'
                        kitsu: '7442'
                        imdb: tt2560140
                        tvdb: '267440'
                    episode:
                      season: 1
                      number: 1
                      title: 'To You, in 2000 Years: The Fall of Shiganshina, Part 1'
                      ids:
                        tvdb: 4543121
                        anidb: 96437
                checkin_anime_episode_via_episode_id:
                  summary: Anime episode — by `episode.ids.anidb` (Taiga-style)
                  description: >-
                    Response carries the resolved season/number even though the
                    request only sent `episode.ids.anidb` — handy when you want
                    to display the episode title alongside the check-in
                    confirmation.
                  value:
                    id: 10916896
                    action: checkin
                    progress: 47
                    anime:
                      title: Cowboy Bebop
                      year: 1998
                      ids:
                        simkl: 37089
                        slug: cowboy-bebop
                        mal: '1'
                        anidb: '23'
                        anilist: '1'
                        kitsu: '1'
                        imdb: tt0213338
                        tvdb: '76885'
                    episode:
                      season: 1
                      number: 1
                      title: Asteroid Blues
                      ids:
                        tvdb: 195266
                        anidb: 1565
                checkin_no_progress:
                  summary: Fire-and-forget — `progress` omitted entirely
                  description: >-
                    Response always carries a `progress` field (0 when you
                    didn't send one) so SDK type-generators don't have to make
                    it optional in the response model. The server still ignores
                    whatever was in the request and computes
                    runtime-extrapolated progress on the dashboard.
                  value:
                    id: 10916896
                    action: checkin
                    progress: 0
                    movie:
                      title: Spirited Away
                      year: 2001
                      ids:
                        simkl: 53538
                        slug: spirited-away
                        imdb: tt0245429
                        tmdb: '129'
                        mal: '199'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '412':
          $ref: '#/components/responses/ClientIdFailed'
        '500':
          $ref: '#/components/responses/ServerError'
      security:
        - clientId: []
          bearerAuth: []
        - simklApiKey: []
          bearerAuth: []
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:
    ScrobbleBody:
      type: object
      description: >-
        Request body for the four scrobble endpoints. Send exactly one of
        `movie`, `show`+`episode`, or `anime`+`episode` — all keys are singular
        objects (one item per request). For batch sync writes the keys are
        plural arrays: see
        [`/sync/history`](/api-reference/simkl/add-to-history) etc. `progress`
        is required for `/scrobble/start`, `/scrobble/pause`, and
        `/scrobble/stop`; on `/scrobble/checkin` it is optional and ignored
        server-side.


        **Anime under `show`?** Yes — if you don't know whether a title is anime
        (e.g. you only have TMDB/TVDB data), send it under `show` and Simkl
        resolves it to the correct catalog automatically. The `anime` key is
        only needed when you want to pass `anidb` / `mal` / `anilist` IDs that
        don't exist at the TV-show level.
      oneOf:
        - title: Movie
          required:
            - movie
        - title: TV episode
          required:
            - show
            - episode
        - title: Anime episode
          required:
            - anime
            - episode
      properties:
        progress:
          type: number
          format: float
          minimum: 0
          maximum: 100
          description: >-
            Playback percentage 0-100. Up to 2 decimals. Required for
            `/scrobble/start`, `/scrobble/pause`, `/scrobble/stop`. Optional
            (and ignored) for `/scrobble/checkin`.
        movie:
          type: object
          description: >-
            Movie reference. Use `ids` (any one external ID) and optionally
            `title` / `year`. Movies have no `episode` block.
          properties:
            title:
              type: string
              example: Inception
            year:
              type: integer
              example: 2010
            ids:
              $ref: '#/components/schemas/MovieIds'
          required:
            - ids
        show:
          type: object
          description: TV show reference (must be paired with `episode`).
          properties:
            title:
              type: string
              example: Stranger Things
            year:
              type: integer
              example: 2016
            ids:
              $ref: '#/components/schemas/ShowIds'
          required:
            - ids
        anime:
          type: object
          description: >-
            Anime reference. Pair with `episode` for series; an `anime` alone
            (no `episode`) is treated as an anime movie / OVA.
          properties:
            title:
              type: string
              example: Shingeki no Kyojin
            year:
              type: integer
              example: 2013
            ids:
              $ref: '#/components/schemas/AnimeIds'
          required:
            - ids
        episode:
          type: object
          description: >-
            Episode identifier. Use `season` + `number`, OR `ids` with a `tvdb`
            / `anidb` episode ID. If both are sent, `episode.ids` takes
            precedence (matches Plex-style integrations that have an episode ID
            but no season/number mapping).
          oneOf:
            - required:
                - season
                - number
              title: By season + number
            - required:
                - ids
              title: By episode ID
          properties:
            season:
              type: integer
              minimum: 0
              example: 1
              description: Season number. `0` is the specials season.
            number:
              type: integer
              minimum: 1
              example: 3
              description: Episode number within the season.
            ids:
              $ref: '#/components/schemas/EpisodeIds'
    ScrobbleResponse:
      type: object
      description: Response for `/scrobble/start`, `/scrobble/pause`, and `/scrobble/stop`.
      properties:
        action:
          type: string
          enum:
            - start
            - pause
            - scrobble
          description: >-
            `start` for /start, `pause` for /pause and for /stop with
            progress<80, `scrobble` for /stop with progress≥80 (item marked
            watched).
        progress:
          type: number
          description: Echo of the request progress, normalized.
        sid:
          type: string
          description: Internal session ID.
        movie:
          $ref: '#/components/schemas/Movie'
        show:
          $ref: '#/components/schemas/Show'
        anime:
          $ref: '#/components/schemas/Anime'
        episode:
          $ref: '#/components/schemas/Episode'
        tvdb_season:
          type: integer
          description: 'For anime: original TVDB season number when AniDB mapping differs.'
        tvdb_number:
          type: integer
          description: 'For anime: original TVDB episode number when AniDB mapping differs.'
    MovieIds:
      type: object
      description: >-
        External IDs for a movie. Pass any one or more — Simkl resolves the
        canonical record by walking these in priority order. `simkl` is the most
        reliable when you have it.
      properties:
        simkl:
          type: integer
          description: Simkl movie ID.
          example: 472214
        slug:
          type: string
          description: Simkl URL slug (echoed back in responses).
          example: inception
        imdb:
          type: string
          description: IMDb ID, e.g. `tt1375666`.
          example: tt1375666
        tmdb:
          type: integer
          description: TMDb movie ID.
          example: 27205
        netflix:
          type: integer
          description: Netflix movie ID.
        traktslug:
          type: string
          description: Trakt movie slug, e.g. `inception-2010`.
        letterboxd:
          type: string
          description: Letterboxd slug, e.g. `inception`.
        boxd:
          type: string
          description: Letterboxd numeric ID (alternative to `letterboxd`).
      additionalProperties: true
    ShowIds:
      type: object
      description: External IDs for a TV show. Pass any one or more.
      properties:
        simkl:
          type: integer
          description: Simkl show ID.
          example: 548312
        slug:
          type: string
          description: Simkl URL slug (echoed back in responses).
          example: stranger-things
        imdb:
          type: string
          description: IMDb ID, e.g. `tt4574334`.
          example: tt4574334
        tmdb:
          type: integer
          description: TMDb show ID.
          example: 66732
        tvdb:
          description: TVDB show ID (integer) or slug (string).
          oneOf:
            - type: integer
            - type: string
          example: 305288
        netflix:
          type: integer
          description: Netflix show ID.
        hulu:
          type: integer
          description: Hulu show ID.
        traktslug:
          type: string
          description: Trakt show slug.
        zap2it:
          type: string
          description: Zap2it ID.
        tvcom:
          type: string
          description: TV.com ID.
        mdl:
          type: string
          description: MyDramaList slug or ID.
      additionalProperties: true
    AnimeIds:
      type: object
      description: >-
        External IDs for an anime. Any one is enough; `mal` / `anidb` /
        `anilist` / `kitsu` are most useful for anime-only sources, while
        `simkl`, `imdb`, `tmdb`, and `tvdb` work for the cross-domain mapping.
      properties:
        simkl:
          type: integer
          description: Simkl anime ID.
          example: 39687
        slug:
          type: string
          description: Simkl URL slug.
          example: shingeki-no-kyojin
        imdb:
          type: string
          description: IMDb ID.
          example: tt2560140
        tmdb:
          type: integer
          description: TMDb show or movie ID (depending on anime_type).
          example: 1429
        tvdb:
          description: TVDB show ID (integer) or slug (string).
          oneOf:
            - type: integer
            - type: string
          example: 267440
        mal:
          type: integer
          description: MyAnimeList ID.
          example: 16498
        anidb:
          type: integer
          description: AniDB ID. Specifying just this is enough for anime lookups.
          example: 9541
        anilist:
          type: integer
          description: AniList ID.
          example: 16498
        kitsu:
          type: integer
          description: Kitsu ID.
          example: 7442
        anisearch:
          type: integer
          description: aniSearch ID.
        animeplanet:
          type: string
          description: Anime-Planet slug.
        livechart:
          type: integer
          description: LiveChart ID.
        anfo:
          type: integer
          description: AnimeNewsNetwork-style anfo ID.
        ann:
          type: integer
          description: AnimeNewsNetwork ID.
      additionalProperties: true
    EpisodeIds:
      type: object
      description: >-
        External IDs for an episode. Only `tvdb` and `anidb` are accepted as
        scrobble episode-ID lookups. Pass either; if both are sent, `tvdb` is
        tried first.
      properties:
        tvdb:
          type: integer
          description: TVDB episode ID.
          example: 4274616
        anidb:
          type: integer
          description: AniDB episode ID.
          example: 142278
      additionalProperties: false
    Movie:
      type: object
      description: >-
        Standard movie object. See the [Standard Media
        Objects](/conventions/standard-media-objects) guide.
      properties:
        title:
          type: string
          example: 'Terminator 3: Rise of the Machines'
        year:
          type: integer
          example: 2003
        ids:
          $ref: '#/components/schemas/Ids'
      required:
        - ids
    Show:
      type: object
      description: >-
        Standard show object. May include nested seasons/episodes for partial
        sync.
      properties:
        title:
          type: string
          example: The Walking Dead
        year:
          type: integer
          example: 2010
        ids:
          $ref: '#/components/schemas/Ids'
        seasons:
          type: array
          items:
            type: object
            properties:
              number:
                type: integer
              episodes:
                type: array
                items:
                  $ref: '#/components/schemas/Episode'
      required:
        - ids
    Anime:
      type: object
      description: >-
        Standard anime object. Like Show, but may include `anime_type`. Episode
        numbering follows AniDB.
      properties:
        title:
          type: string
          example: Attack on Titan
        year:
          type: integer
          example: 2013
        anime_type:
          $ref: '#/components/schemas/AnimeFormat'
        ids:
          $ref: '#/components/schemas/Ids'
        episodes:
          type: array
          items:
            $ref: '#/components/schemas/Episode'
      required:
        - ids
    Episode:
      type: object
      description: Episode reference. Use `season` + `number`, or `ids`.
      properties:
        season:
          type: integer
          minimum: 0
          example: 1
        number:
          type: integer
          minimum: 1
          example: 2
        watched_at:
          type: string
          format: date-time
          example: '2014-09-01T09:10:11Z'
          description: ISO-8601 GMT timestamp.
        ids:
          $ref: '#/components/schemas/Ids'
    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
    Ids:
      type: object
      description: >-
        External and internal identifiers for an item. Pass as many as you have
        — Simkl resolves to the canonical record.
      properties:
        simkl:
          type: integer
          description: Simkl internal ID. Most reliable.
          example: 53536
        slug:
          type: string
          description: URL-safe slug returned in responses.
          example: attack-on-titan
        imdb:
          type: string
          description: IMDb ID.
          example: tt0181852
        tmdb:
          type: string
          description: TMDb ID.
          example: '296'
        tvdb:
          oneOf:
            - type: integer
            - type: string
          description: TVDB ID or slug.
          example: 153021
        mal:
          type: string
          description: MyAnimeList ID.
          example: '4246'
        anidb:
          type: string
          description: AniDB ID. Specifying just this is enough for anime lookups.
          example: '10846'
        anilist:
          type: string
          description: AniList ID.
          example: '21'
        kitsu:
          type: string
          description: Kitsu ID.
          example: '12'
        anisearch:
          type: string
          description: aniSearch ID.
          example: '2227'
        animeplanet:
          type: string
          description: Anime-Planet slug.
          example: one-piece
        livechart:
          type: string
          description: LiveChart ID.
          example: '321'
        letterboxd:
          type: string
          description: Letterboxd slug.
          example: the-truman-show
        netflix:
          type: string
          description: Netflix movie ID.
          example: '70210890'
        hulu:
          type: string
          description: Hulu episode ID.
        crunchyroll:
          type: string
          description: Crunchyroll episode ID.
        traktslug:
          type: string
          description: Trakt slug.
          example: john-wick-chapter-4-2023
      additionalProperties: true
      example:
        simkl: 53536
        imdb: tt0181852
        tmdb: 296
    AnimeFormat:
      type: string
      enum:
        - tv
        - movie
        - special
        - ova
        - ona
        - music video
      description: >-
        Anime production format. `tv` is the common case; movies, OVAs, ONAs,
        and music videos all surface through the `/anime/*` endpoints with the
        same response shape.
  responses:
    BadRequest:
      description: Bad request — a required field is missing or has the wrong shape.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: empty_field
            code: 400
            message: Missed "to" parameter
    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
    NotFound:
      description: The requested item ID or URL does not exist.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: id_err
            code: 404
    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
    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: >-
        OAuth 2.0 or PIN-flow `access_token`. Required for endpoints that read
        or modify the user's library, scrobble session, ratings, settings, or
        playbacks. See [Authentication](/authentication).
      x-default: YOUR_ACCESS_TOKEN

````