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

# Find items by external ID

> <Danger>
**Never call search before scrobbling or marking something watched.**

This is the most common wasted request we see. Apps look the title up here first to get a Simkl ID, then send that ID to the write endpoint. **The lookup is unnecessary.** Every write endpoint resolves the item itself, from whatever you already have:

```json
{
  "movie": {
    "title": "Dune: Part Two",
    "year": 2024,
    "ids": { "imdb": "tt15239678", "tmdb": "693134" }
  }
}
```

Pass any combination of IDs, plus `title` and `year` as fallbacks, in the **same request** that records the watch. Simkl matches it server-side. A Simkl ID is never required.

That applies to [`/scrobble/*`](/api-reference/scrobble), [`POST /sync/history`](/api-reference/simkl/add-to-history), [`POST /sync/add-to-list`](/api-reference/simkl/add-to-list) and [`POST /sync/ratings`](/api-reference/simkl/add-ratings) alike.

Searching first doubles your request count for no benefit, burns rate limit you'll want later, and picks the wrong title whenever the search ranking disagrees with the IDs you already hold. **One call, not two.**

Use search only when you have **no usable IDs at all**: a title the user typed, a file name, or a random pick.
</Danger>

<Warning>
**Resolving more than ~20 IDs in a loop? Stop — you're doing it wrong.**

A user's synced watchlist already carries every external ID (IMDB, TMDB, TVDB, MAL, and more) for every item they track. You do **not** need Simkl IDs to mark something watched, add it to a list, or scrobble it — send the external IDs you already have and Simkl matches them for you.

If you believe you genuinely need to batch-resolve IDs, [contact us on Discord](https://discord.gg/MJsWNE4) **first**. There's almost always a simpler path, and looping `/search/id` will hit rate limits fast.
</Warning>

> ## ⚠️ Prefer [`GET /redirect`](/api-reference/redirect) + a cached detail endpoint over `/search/id` for almost every external-ID lookup
>
> The recommended two-step flow is materially cheaper, faster, and edge-cached:
>
> **Step 1 — Resolve the external ID to a Simkl ID.** Call [`GET /redirect?to=simkl&<external_id>=…`](/api-reference/simkl/redirect) and **read** (don't follow) the `Location` header. Parse the Simkl ID out of the URL path. No JSON body to download, no JSON to parse — just HTTP headers.
>
> **Step 2 — Fetch the full record from the cached detail endpoint.** Use the parsed Simkl ID with the matching:
> - Movies → [`GET /movies/{simkl_id}`](/api-reference/simkl/get-movie)
> - TV shows → [`GET /tv/{simkl_id}`](/api-reference/simkl/get-tv-show)
> - Anime → [`GET /anime/{simkl_id}`](/api-reference/simkl/get-anime)
> - Episode lists → [`GET /tv/episodes/{simkl_id}`](/api-reference/simkl/get-tv-episodes) or [`GET /anime/episodes/{simkl_id}`](/api-reference/simkl/get-anime-episodes)
>
> These detail endpoints are **Cloudflare-cached by Simkl ID** with **automatic server-side cache invalidation** on metadata updates. Popular titles come straight from the edge cache and cost almost nothing.
>
> **Why this beats `/search/id`:**
> - `/redirect` returns just HTTP headers (no JSON body). `/search/id` returns JSON every call.
> - The detail endpoints are Cloudflare-cached. `/search/id` is a search query that hits origin every time.
> - Two requests both cheap > one request that always hits origin.
> - Concurrent / parallel lookups against the cached detail endpoints are explicitly allowed (see [Rate limits → Parallel requests](/resources/rate-limits#parallel-requests-when-allowed)). `/search/id` should be called sequentially.
>
> **When `/search/id` is still the right call** (rare):
> - You need the **legacy response shape** for a code path you can't change.
> - You need a type-agnostic lookup that returns the `type` field upfront without parsing the `Location` URL.

---

Look up Simkl records by any external ID — IMDB, TMDB, TVDB, MAL, AniDB, AniList, Kitsu, anisearch, anime-planet, livechart, letterboxd, Netflix, Trakt slug. Pass the ID as a query parameter (e.g. `?imdb=tt4574334`).

#### Response shape (per item)

```json
{
 "type": "anime",
 "title": "Attack on Titan",
 "poster": "39/396870bc78f2ba7e",
 "year": 2013,
 "status": "ended",
 "total_episodes": 75,
 "anime_type": "tv",
 "ids": {
 "simkl": 39687,
 "slug": "attack-on-titan"
 },
 "mal": {
 "id": 16498,
 "type": "tv"
 }
}
```

`status` is one of `released`, `upcoming`, `ended`, `aired`, `tba`. `total_episodes` is omitted for movies.

<Card title="Redirect & deep-linking — recommended alternative" icon="bolt" href="/api-reference/redirect" horizontal>
 Full walkthrough of the two-step `/redirect` → cached detail endpoint flow, with the stop-at-301 reference table for popular HTTP clients and worked recipes in bash, JavaScript, and Python.
</Card>

<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 get /search/id
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:
  /search/id:
    get:
      tags:
        - Search
      summary: Find items by external ID
      description: >-
        <Danger>

        **Never call search before scrobbling or marking something watched.**


        This is the most common wasted request we see. Apps look the title up
        here first to get a Simkl ID, then send that ID to the write endpoint.
        **The lookup is unnecessary.** Every write endpoint resolves the item
        itself, from whatever you already have:


        ```json

        {
          "movie": {
            "title": "Dune: Part Two",
            "year": 2024,
            "ids": { "imdb": "tt15239678", "tmdb": "693134" }
          }
        }

        ```


        Pass any combination of IDs, plus `title` and `year` as fallbacks, in
        the **same request** that records the watch. Simkl matches it
        server-side. A Simkl ID is never required.


        That applies to [`/scrobble/*`](/api-reference/scrobble), [`POST
        /sync/history`](/api-reference/simkl/add-to-history), [`POST
        /sync/add-to-list`](/api-reference/simkl/add-to-list) and [`POST
        /sync/ratings`](/api-reference/simkl/add-ratings) alike.


        Searching first doubles your request count for no benefit, burns rate
        limit you'll want later, and picks the wrong title whenever the search
        ranking disagrees with the IDs you already hold. **One call, not two.**


        Use search only when you have **no usable IDs at all**: a title the user
        typed, a file name, or a random pick.

        </Danger>


        <Warning>

        **Resolving more than ~20 IDs in a loop? Stop — you're doing it wrong.**


        A user's synced watchlist already carries every external ID (IMDB, TMDB,
        TVDB, MAL, and more) for every item they track. You do **not** need
        Simkl IDs to mark something watched, add it to a list, or scrobble it —
        send the external IDs you already have and Simkl matches them for you.


        If you believe you genuinely need to batch-resolve IDs, [contact us on
        Discord](https://discord.gg/MJsWNE4) **first**. There's almost always a
        simpler path, and looping `/search/id` will hit rate limits fast.

        </Warning>


        > ## ⚠️ Prefer [`GET /redirect`](/api-reference/redirect) + a cached
        detail endpoint over `/search/id` for almost every external-ID lookup

        >

        > The recommended two-step flow is materially cheaper, faster, and
        edge-cached:

        >

        > **Step 1 — Resolve the external ID to a Simkl ID.** Call [`GET
        /redirect?to=simkl&<external_id>=…`](/api-reference/simkl/redirect) and
        **read** (don't follow) the `Location` header. Parse the Simkl ID out of
        the URL path. No JSON body to download, no JSON to parse — just HTTP
        headers.

        >

        > **Step 2 — Fetch the full record from the cached detail endpoint.**
        Use the parsed Simkl ID with the matching:

        > - Movies → [`GET /movies/{simkl_id}`](/api-reference/simkl/get-movie)

        > - TV shows → [`GET /tv/{simkl_id}`](/api-reference/simkl/get-tv-show)

        > - Anime → [`GET /anime/{simkl_id}`](/api-reference/simkl/get-anime)

        > - Episode lists → [`GET
        /tv/episodes/{simkl_id}`](/api-reference/simkl/get-tv-episodes) or [`GET
        /anime/episodes/{simkl_id}`](/api-reference/simkl/get-anime-episodes)

        >

        > These detail endpoints are **Cloudflare-cached by Simkl ID** with
        **automatic server-side cache invalidation** on metadata updates.
        Popular titles come straight from the edge cache and cost almost
        nothing.

        >

        > **Why this beats `/search/id`:**

        > - `/redirect` returns just HTTP headers (no JSON body). `/search/id`
        returns JSON every call.

        > - The detail endpoints are Cloudflare-cached. `/search/id` is a search
        query that hits origin every time.

        > - Two requests both cheap > one request that always hits origin.

        > - Concurrent / parallel lookups against the cached detail endpoints
        are explicitly allowed (see [Rate limits → Parallel
        requests](/resources/rate-limits#parallel-requests-when-allowed)).
        `/search/id` should be called sequentially.

        >

        > **When `/search/id` is still the right call** (rare):

        > - You need the **legacy response shape** for a code path you can't
        change.

        > - You need a type-agnostic lookup that returns the `type` field
        upfront without parsing the `Location` URL.


        ---


        Look up Simkl records by any external ID — IMDB, TMDB, TVDB, MAL, AniDB,
        AniList, Kitsu, anisearch, anime-planet, livechart, letterboxd, Netflix,
        Trakt slug. Pass the ID as a query parameter (e.g. `?imdb=tt4574334`).


        #### Response shape (per item)


        ```json

        {
         "type": "anime",
         "title": "Attack on Titan",
         "poster": "39/396870bc78f2ba7e",
         "year": 2013,
         "status": "ended",
         "total_episodes": 75,
         "anime_type": "tv",
         "ids": {
         "simkl": 39687,
         "slug": "attack-on-titan"
         },
         "mal": {
         "id": 16498,
         "type": "tv"
         }
        }

        ```


        `status` is one of `released`, `upcoming`, `ended`, `aired`, `tba`.
        `total_episodes` is omitted for movies.


        <Card title="Redirect & deep-linking — recommended alternative"
        icon="bolt" href="/api-reference/redirect" horizontal>
         Full walkthrough of the two-step `/redirect` → cached detail endpoint flow, with the stop-at-301 reference table for popular HTTP clients and worked recipes in bash, JavaScript, and Python.
        </Card>


        <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: get-search-id
      parameters:
        - name: simkl
          in: query
          description: Simkl `id`.
          schema:
            type: integer
          example: '2090'
        - name: hulu
          in: query
          description: hulu_id. All other parameters can be empty if this one specified.
          schema:
            type: integer
          example: '752375'
        - name: netflix
          in: query
          description: Netflix `movieid`, this parameter is in beta and may not work.
          schema:
            type: integer
          example: '70210890'
        - name: mal
          in: query
          description: MyAnimeList `id`.
          schema:
            type: integer
          example: '4246'
        - name: tvdb
          in: query
          description: TVDB ID. All other parameters can be empty if this one specified.
          schema:
            type: string
          example: 153021, the-walking-dead
        - name: tmdb
          in: query
          description: >-
            The Movie Database (TMDb) ID. All other parameters can be empty if
            this one specified. `type` parameter is required if you want to
            search for TV Shows
          schema:
            type: integer
          example: '76757'
        - name: imdb
          in: query
          description: >-
            can be IMDB ID or full IMDB URL. All other parameters can be empty
            if this one specified.
          schema:
            type: string
            pattern: ^tt\d+$
          example: tt1972591
        - name: anidb
          in: query
          description: AniDB ID. All other parameters can be empty if this one specified.
          schema:
            type: integer
          example: '10846'
        - name: crunchyroll
          in: query
          description: Crunchyroll ID. You can pass episode ID or url ID(sword-art-online)
          schema:
            type: string
          example: '656641'
        - name: anilist
          in: query
          description: AniList ID
          schema:
            type: integer
          example: '21'
        - name: kitsu
          in: query
          description: Kitsu ID
          schema:
            type: integer
          example: '12'
        - name: livechart
          in: query
          description: LiveChart ID
          schema:
            type: integer
          example: '321'
        - name: anisearch
          in: query
          description: aniSearch ID
          schema:
            type: integer
          example: '2227'
        - name: animeplanet
          in: query
          description: Anime-Planet ID
          schema:
            type: string
          example: one-piece
        - name: type
          in: query
          description: Only used when sending tmdb.
          schema:
            type: string
            enum:
              - show
              - movie
        - name: title
          in: query
          description: >-
            TV show, anime, or movie title. If this title has more then 1 item
            then null will be returned, add more fields to narrow down the
            search to 1 item(such as type,year etc.)
          schema:
            type: string
          example: The Walking Dead
        - name: year
          in: query
          description: release year.
          schema:
            type: integer
          example: '2010'
        - $ref: '#/components/parameters/ClientIdQuery'
        - $ref: '#/components/parameters/AppNameQuery'
        - $ref: '#/components/parameters/AppVersionQuery'
        - $ref: '#/components/parameters/UserAgentHeader'
        - name: anfo
          in: query
          required: false
          schema:
            type: string
          example: '12345'
          description: >-
            AniFox / anfo.org ID. Returns the matching Simkl title(s). See
            [Standard media objects → Supported ID
            keys](/conventions/standard-media-objects#supported-id-keys).
        - name: ann
          in: query
          required: false
          schema:
            type: integer
          example: 4658
          description: >-
            Anime News Network (ANN) ID. Returns the matching Simkl title(s).
            See [Standard media objects → Supported ID
            keys](/conventions/standard-media-objects#supported-id-keys).
        - name: tvcom
          in: query
          required: false
          schema:
            type: string
          example: '12345'
          description: >-
            TV.com ID (legacy). Returns the matching Simkl title(s). See
            [Standard media objects → Supported ID
            keys](/conventions/standard-media-objects#supported-id-keys).
        - name: zap2it
          in: query
          required: false
          schema:
            type: string
          example: SH00726133
          description: >-
            Zap2it (TVScheduleDirect) ID. Returns the matching Simkl title(s).
            See [Standard media objects → Supported ID
            keys](/conventions/standard-media-objects#supported-id-keys).
        - name: traktslug
          in: query
          required: false
          schema:
            type: string
          example: stranger-things
          description: >-
            Trakt URL slug. Returns the matching Simkl title(s). See [Standard
            media objects → Supported ID
            keys](/conventions/standard-media-objects#supported-id-keys).
        - name: letterboxd
          in: query
          required: false
          schema:
            type: string
          example: parasite-2019
          description: >-
            Letterboxd film slug (movies). Returns the matching Simkl title(s).
            See [Standard media objects → Supported ID
            keys](/conventions/standard-media-objects#supported-id-keys).
        - name: boxd
          in: query
          required: false
          schema:
            type: string
          example: parasite-2019
          description: >-
            Letterboxd alias — same as `letterboxd`. Returns the matching Simkl
            title(s). See [Standard media objects → Supported ID
            keys](/conventions/standard-media-objects#supported-id-keys).
        - name: mdl
          in: query
          required: false
          schema:
            type: string
          example: crash-landing-on-you
          description: >-
            MyDramaList slug or ID (Korean / Asian dramas). Returns the matching
            Simkl title(s). See [Standard media objects → Supported ID
            keys](/conventions/standard-media-objects#supported-id-keys).
      responses:
        '200':
          description: >-
            Array of matching catalog records — `[]` when no record matches the
            supplied IDs. There is no `404` for unknown IDs; an empty array is
            the not-found shape (Type 3 null — see [Null and missing
            values](/conventions/null-values)).
          headers: {}
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SearchByIdResultItem'
              examples:
                imdb_movie:
                  summary: IMDB ID → movie (Inception)
                  description: >-
                    The most common use case: a tracker app has an IMDB id from
                    its local catalog and wants the Simkl id to deep-link or
                    sync against. Pass `?imdb=tt…` — Simkl returns the canonical
                    movie record.
                  value:
                    - type: movie
                      title: Inception
                      poster: 14/14017865947c9d3d0d
                      year: 2010
                      status: released
                      ids:
                        simkl: 472214
                        slug: inception
                tmdb_movie:
                  summary: TMDB ID + `?type=movie` → movie (Inception)
                  description: >-
                    TMDB indexes movies and TV in separate id sequences, so the
                    same numeric id can refer to either. Always pair `?tmdb=…`
                    with `?type=movie` or `?type=tv` to disambiguate. This
                    example resolves Inception's TMDB id 27205 as a movie.
                  value:
                    - type: movie
                      title: Inception
                      poster: 14/14017865947c9d3d0d
                      year: 2010
                      status: released
                      ids:
                        simkl: 472214
                        slug: inception
                tmdb_tv:
                  summary: TMDB ID + `?type=tv` → TV show (Game of Thrones)
                  description: >-
                    Same TMDB disambiguation pattern as `tmdb_movie` above, but
                    for a TV show. TV results additionally carry
                    `total_episodes`.
                  value:
                    - type: tv
                      title: Game of Thrones
                      poster: 57/5742576cd8f59fcb0
                      year: 2011
                      status: ended
                      ids:
                        simkl: 17465
                        slug: game-of-thrones
                      total_episodes: 73
                tvdb_tv:
                  summary: TVDB ID → TV show (The Walking Dead)
                  description: >-
                    TVDB has no movie type, so the response always shapes as
                    `type: tv` (or `type: anime` for anime catalogued at TVDB).
                  value:
                    - type: tv
                      title: The Walking Dead
                      poster: 16/16913426086fc13
                      year: 2010
                      status: ended
                      ids:
                        simkl: 2090
                        slug: the-walking-dead
                      total_episodes: 177
                mal_anime:
                  summary: >-
                    MAL ID → anime (Demon Slayer; carries `anime_type` + `mal`
                    blocks)
                  description: >-
                    Anime results carry two extra fields the other types don't:
                    `anime_type` (catalog format — `tv`, `movie`, `ova`, `ona`,
                    `special`, `music video`) and `mal` (the MyAnimeList id +
                    MAL's own type taxonomy).
                  value:
                    - type: anime
                      title: Kimetsu no Yaiba
                      poster: 85/85964029165a0e752
                      year: 2019
                      status: ended
                      ids:
                        simkl: 831411
                        slug: kimetsu-no-yaiba
                      total_episodes: 26
                      anime_type: tv
                      mal:
                        id: 38000
                        type: tv
                simkl_id_roundtrip:
                  summary: Simkl ID → same record (round-trip)
                  description: >-
                    Useful for validating that a Simkl id you cached is still
                    resolvable. Same shape as the IMDB-lookup case.
                  value:
                    - type: movie
                      title: Inception
                      poster: 14/14017865947c9d3d0d
                      year: 2010
                      status: released
                      ids:
                        simkl: 472214
                        slug: inception
                unknown_id_empty_array:
                  summary: Unknown ID → `200 []` (Type 3 null — NOT a 404)
                  description: >-
                    When no Simkl record matches the supplied ID, the response
                    is `200` with an **empty array** — not a `404`. Apps must
                    inspect array length before reading the first element. Same
                    shape applies when the request has no ID parameters at all.
                  value: []
        '412':
          $ref: '#/components/responses/ClientIdFailed'
        '500':
          $ref: '#/components/responses/ServerError'
      security:
        - clientId: []
      x-codeSamples:
        - lang: Shell
          label: imdb_movie
          source: |-
            curl -H "User-Agent: my-app-name/1.0" \
              "https://api.simkl.com/search/id?imdb=tt1375666&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0"
        - lang: Shell
          label: tmdb_movie
          source: |-
            curl -H "User-Agent: my-app-name/1.0" \
              "https://api.simkl.com/search/id?tmdb=27205&type=movie&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0"
        - lang: Shell
          label: tmdb_tv
          source: |-
            curl -H "User-Agent: my-app-name/1.0" \
              "https://api.simkl.com/search/id?tmdb=1399&type=tv&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0"
        - lang: Shell
          label: tvdb_tv
          source: |-
            curl -H "User-Agent: my-app-name/1.0" \
              "https://api.simkl.com/search/id?tvdb=153021&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0"
        - lang: Shell
          label: mal_anime
          source: |-
            curl -H "User-Agent: my-app-name/1.0" \
              "https://api.simkl.com/search/id?mal=38000&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0"
        - lang: Shell
          label: simkl_id_roundtrip
          source: |-
            curl -H "User-Agent: my-app-name/1.0" \
              "https://api.simkl.com/search/id?simkl=472214&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0"
        - lang: Shell
          label: unknown_id_empty_array
          source: |-
            curl -H "User-Agent: my-app-name/1.0" \
              "https://api.simkl.com/search/id?imdb=tt99999999&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0"
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:
    SearchByIdResultItem:
      type: object
      description: >-
        Result item from `GET /search/id`. Returned inside the top-level
        `SearchByIdResponse` array.
      required:
        - type
        - title
        - status
        - ids
      properties:
        type:
          type: string
          enum:
            - movie
            - tv
            - anime
          description: >-
            Catalog category. Determines which detail endpoint to call next
            (`/movies/{id}` vs `/tv/{id}` vs `/anime/{id}`).
        title:
          type: string
          description: >-
            Display title in the canonical (often non-English) form. For an
            English-localized title use the per-type detail endpoint.
        poster:
          type:
            - string
            - 'null'
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values). Poster image path. See
            [Images](/conventions/images) for how to build the URL.
        year:
          type:
            - integer
            - 'null'
          description: >-
            Type 4 null — data not on file in that field's slot. See [Null and
            missing values](/conventions/null-values).
        status:
          type: string
          enum:
            - released
            - upcoming
            - ended
            - aired
            - tba
          description: >-
            Release / airing status. `released` / `upcoming` apply to movies;
            `ended` / `aired` / `tba` apply to TV and anime. Note this enum is
            broader than the closed `{tba, ended, airing}` set the detail
            endpoints (`/tv/{id}`, `/anime/{id}`) use — `/search/id` is built on
            a different code path.
        total_episodes:
          type: integer
          description: >-
            Total episode count. **Omitted for movies** (only present on `type:
            tv` and `type: anime`).
        anime_type:
          $ref: '#/components/schemas/AnimeFormat'
          description: >-
            Only present on `type: anime` items. Distinguishes the anime catalog
            format (`tv`, `movie`, `ova`, `ona`, `special`, `music video`).
        mal:
          type: object
          description: >-
            Only present on `type: anime` items when Simkl has MAL metadata on
            file. `{id, type}` echoes the MyAnimeList record this entry maps to.
          properties:
            id:
              type: integer
              description: MyAnimeList numeric id.
            type:
              type: string
              description: MAL's own type taxonomy (e.g. `tv`, `movie`, `ova`, `special`).
        ids:
          $ref: '#/components/schemas/SearchByIdResultIds'
    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.
    SearchByIdResultIds:
      type: object
      description: >-
        Identifiers returned inside each `/search/id` result item. The server
        returns ONLY `simkl` and `slug` here — even when you queried by `imdb`,
        `tmdb`, `tvdb`, `mal`, etc., the response does NOT echo the input ID
        back in this block. To get the full canonical external-ID set for the
        matched record, follow up with the per-type detail endpoint ([`GET
        /movies/{simkl}`](/api-reference/simkl/get-movie), [`GET
        /tv/{simkl}`](/api-reference/simkl/get-tv-show), [`GET
        /anime/{simkl}`](/api-reference/simkl/get-anime)) — those carry the full
        ID set.
      required:
        - simkl
        - slug
      properties:
        simkl:
          type: integer
          description: Canonical Simkl id of the matched record.
          example: 472214
        slug:
          type: string
          description: URL slug for `https://simkl.com/<type>/<simkl>/<slug>` deep links.
          example: inception
    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
  responses:
    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

````

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