{
  "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.\n\nAll requests use HTTPS and return JSON. The base URL is `https://api.simkl.com`.\n\n**Every request needs three URL parameters and a `User-Agent` header:**\n\n```\n/endpoint?client_id=YOUR_CLIENT_ID&app-name=my-app&app-version=1.0\n```\n\nSee [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).\n\n> ⚠️ **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.\n\n**Get started**\n\n- [Quickstart](/quickstart) — first request in 60 seconds\n- [API rules](/api-rules) — what's allowed, what isn't\n- [Standard media objects](/conventions/standard-media-objects) — the shapes every endpoint speaks\n- [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."
    }
  ],
  "paths": {
    "/anime/airing": {
      "get": {
        "operationId": "get-anime-airing-date",
        "summary": "Anime airing today, tomorrow, or on a specific date",
        "description": "Currently airing anime — same data that powers the [Simkl anime calendar](https://simkl.com/anime/airing/). No `access_token` required.\n\nSame shape and parameters as [`/tv/airing`](/api-reference/simkl/get-tv-airing) but for the anime catalog: each item includes an `anime_type` field (`tv`, `ona`, `ova`, `movie`, `special`, `music`), and the `episode` block omits `season` (anime numbering is single-season — AniDB sequential).\n\n<Warning>\n**Prefer the cached calendar endpoints for high-traffic use cases.** `/anime/airing` is **uncached** — every request hits the origin. For widgets, mobile-app home screens, or anything that fetches this on app launch / wake / timer, use the CDN-cached [Calendar data files](/api-reference/calendar) on `data.simkl.in` — `/calendar/anime.json` (rolling window: yesterday + next 33 days) or `/calendar/{year}/{month}/anime.json` (monthly archive) serve the same per-day airing data, edge-cached so most requests don't even reach origin. Reserve `/anime/airing` for ad-hoc queries by a specific date that the calendar files don't pre-bake.\n\nBoth forms still need the standard URL params on every request — `client_id`, `app-name`, `app-version` (and the `User-Agent` header) — same as every other Simkl endpoint. See [Headers and required parameters](/conventions/headers).\n</Warning>\n\n#### Query parameters\n\n| Param | Default | Notes |\n|---|---|---|\n| `date` | `today` | `today`, `tomorrow`, or `DD-MM-YYYY`. Bogus values silently fall back to `today`. |\n| `sort` | `time` | `time`, `rank`, `popularity`. Bogus values silently fall back to `time`. |\n\n#### Item shape\n\n```json\n{\n  \"title\": \"string\",\n  \"year\": \"integer | null\",\n  \"date\": \"ISO-8601 string with -05:00 offset | null\",\n  \"poster\": \"string  (relative path; prepend https://simkl.in/posters/ + size)\",\n  \"rank\": \"integer | null\",\n  \"url\": \"string  (relative simkl.com URL)\",\n  \"ids\": {\n    \"simkl_id\": \"integer\",\n    \"slug\": \"string\"\n  },\n  \"episode\": {\n    \"episode\": \"integer\",\n    \"url\": \"string\"\n  },\n  \"anime_type\": \"tv | ona | ova | movie | special | music\"\n}\n```\n\n#### Nulls — what they mean\n\n| Field | When null | Type |\n|---|---|---|\n| `date` | Catalog has no `Airs_Time` on file for this episode (older / low-data titles) | [Type 4](/conventions/null-values#type-4) |\n| `rank` | Item not yet ranked, or rank value >= 999999 sentinel | [Type 4](/conventions/null-values#type-4) |\n| `episode.season` | Always omitted on anime — single-season AniDB numbering. | [Type 2](/conventions/null-values#type-2) |\n\n#### Error responses\n\n| Status | When |\n|---|---|\n| `412 client_id_failed` | Missing or invalid `client_id` |\n| `500` | Server error |\n\nNo `400` — invalid `date`/`sort` values silently fall back to defaults. No `404` — empty result is `[]` with status `200`.\n\n> For broader catalog browsing, see [Anime by genre](/api-reference/simkl/get-anime-genres).\n",
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "description": "only data within this date",
            "schema": {
              "type": "string",
              "pattern": "^(today|tomorrow|\\d{2}-\\d{2}-\\d{4})$"
            },
            "example": "22-08-2026",
            "required": false
          },
          {
            "name": "sort",
            "in": "query",
            "description": "sort the results by the specified option",
            "schema": {
              "type": "string",
              "enum": [
                "time",
                "rank",
                "popularity"
              ]
            },
            "example": "time"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "year": {
                        "type": [
                          "integer",
                          "null"
                        ],
                        "description": "Year extracted from the episode's `Airs_Time`. Type 4 null when no air time on file. See [Null and missing values](/conventions/null-values)."
                      },
                      "date": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "format": "date-time",
                        "description": "Episode air time as ISO-8601 with `-05:00` offset (Simkl's server timezone). Type 4 null — catalog has no `Airs_Time` for this episode. See [Null and missing values](/conventions/null-values)."
                      },
                      "poster": {
                        "type": "string",
                        "description": "Image path fragment. Combine with the prefixes in [Image conventions](/conventions/images) — for example `https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`."
                      },
                      "rank": {
                        "type": [
                          "integer",
                          "null"
                        ],
                        "description": "Simkl popularity rank. Type 4 null when not yet ranked or sentinel value (>= 999999). See [Null and missing values](/conventions/null-values)."
                      },
                      "url": {
                        "type": "string",
                        "description": "Relative simkl.com URL."
                      },
                      "ids": {
                        "type": "object",
                        "properties": {
                          "simkl_id": {
                            "type": "integer"
                          },
                          "slug": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "simkl_id",
                          "slug"
                        ]
                      },
                      "episode": {
                        "type": "object",
                        "description": "AniDB-sequential numbering — `season` is NEVER present on anime (Type 2 omission).",
                        "properties": {
                          "episode": {
                            "type": "integer",
                            "description": "Episode number (AniDB sequential)."
                          },
                          "url": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "episode",
                          "url"
                        ]
                      },
                      "anime_type": {
                        "type": "string",
                        "enum": [
                          "tv",
                          "ona",
                          "ova",
                          "movie",
                          "special",
                          "music"
                        ],
                        "description": "Anime catalog type. Always lowercase."
                      }
                    },
                    "required": [
                      "title",
                      "year",
                      "date",
                      "poster",
                      "rank",
                      "url",
                      "ids",
                      "episode",
                      "anime_type"
                    ]
                  }
                },
                "example": [
                  {
                    "title": "Ascendance of a Bookworm: Adopted Daughter of an Archduke",
                    "year": 2026,
                    "date": "2026-05-16T05:30:00-04:00",
                    "poster": "19/19402710cc7c44dab3",
                    "rank": 747,
                    "url": "/anime/2316218/honzuki-no-gekokujou-shisho-ni-naru-tame-ni-wa-shudan-o-erande-iraremasen---ryoushu-no-youjo",
                    "ids": {
                      "simkl_id": 2316218,
                      "slug": "honzuki-no-gekokujou-shisho-ni-naru-tame-ni-wa-shudan-o-erande-iraremasen---ryoushu-no-youjo"
                    },
                    "episode": {
                      "episode": 6,
                      "url": "/anime/2316218/honzuki-no-gekokujou-shisho-ni-naru-tame-ni-wa-shudan-o-erande-iraremasen---ryoushu-no-youjo/episode-6/"
                    },
                    "anime_type": "tv"
                  }
                ]
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Anime"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-anime-airing",
          "metadata": {
            "sidebarTitle": "Airing anime"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/anime/best/{filter}": {
      "get": {
        "summary": "Top-rated anime",
        "operationId": "get-best-anime",
        "description": "Top-rated anime. Mirrors the [Simkl Best Anime](https://simkl.com/anime/best-anime/) pages. No `access_token` required.\n\nSame behavior as [`/tv/best/{filter}`](/api-reference/simkl/get-best-tv) with one difference: items carry `ratings.mal` instead of `ratings.imdb`. Items do **not** carry `anime_type` here — for format-aware browsing use [`GET /anime/genres/...`](/api-reference/simkl/get-anime-genres).\n\nPick a bucket via the `{filter}` path segment:\n\n| Filter | What you get |\n|---|---|\n| `all` | All-time top-rated. |\n| `year` | Top-rated for the current year. |\n| `month` | Top-rated for the current month. |\n| `voted` | Most-voted titles (sorted by total MAL votes). Items also include a `votes` count. |\n| `watched` | Most-watched this month. Items also include a `watched` count. |\n\nUnknown filter values fall back to `all`.\n\nOptionally narrow by `type=all`, `tv`, `movies`, `ovas`, `onas`, or `music`. Unknown values are ignored.\n\n<Note>\n**60 items, no pagination.** The endpoint always returns up to 60 items in one call. The `page` and `limit` query parameters are accepted but ignored. For paginated browsing use [`GET /anime/genres/...`](/api-reference/simkl/get-anime-genres).\n</Note>\n\n#### Errors\n\n| Status | When |\n|---|---|\n| `412` | Missing or invalid `client_id` |\n| `500` | Server error |\n\nUnknown `filter` or `type` values silently fall back — no `400`. The endpoint never returns `404`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BestFilterParam"
          },
          {
            "$ref": "#/components/parameters/BestAnimeTypeParam"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK — array of items, or bare `null` when a `?type=` filter zeroes the result set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BestResponse"
                },
                "examples": {
                  "All-time top": {
                    "summary": "All-time top",
                    "value": [
                      {
                        "title": "Sousou no Frieren",
                        "year": 2023,
                        "poster": "14/1430387937a6ef6167",
                        "url": "/anime/1990194/sousou-no-frieren",
                        "ids": {
                          "simkl_id": 1990194,
                          "slug": "sousou-no-frieren"
                        },
                        "ratings": {
                          "simkl": {
                            "rating": 9.2,
                            "votes": 4636
                          },
                          "mal": {
                            "rating": 9.3,
                            "votes": 886825
                          }
                        }
                      }
                    ]
                  },
                  "Most voted": {
                    "summary": "Most voted",
                    "value": [
                      {
                        "title": "Shingeki no Kyojin",
                        "year": 2013,
                        "poster": "23/23563e7856a42e5",
                        "url": "/anime/39687/shingeki-no-kyojin",
                        "votes": 3069367,
                        "ids": {
                          "simkl_id": 39687,
                          "slug": "shingeki-no-kyojin"
                        },
                        "ratings": {
                          "simkl": {
                            "rating": 8.7,
                            "votes": 12291
                          },
                          "mal": {
                            "rating": 8.6,
                            "votes": 3069367
                          }
                        }
                      }
                    ]
                  },
                  "Most watched this month": {
                    "summary": "Most watched this month",
                    "value": [
                      {
                        "title": "Tongari Boushi no Atelier",
                        "year": 2026,
                        "poster": "19/194379733cd8095db8",
                        "url": "/anime/1885096/tongari-boushi-no-atelier",
                        "watched": 2080,
                        "ids": {
                          "simkl_id": 1885096,
                          "slug": "tongari-boushi-no-atelier"
                        },
                        "ratings": {
                          "simkl": {
                            "rating": 8.7,
                            "votes": 184
                          },
                          "mal": {
                            "rating": 8.8,
                            "votes": 43850
                          }
                        }
                      }
                    ]
                  },
                  "Anime movies only": {
                    "summary": "Anime movies only",
                    "value": [
                      {
                        "title": "Gekijouban Chainsaw Man: Reze Hen",
                        "year": 2025,
                        "poster": "19/191243317ee3118881",
                        "url": "/anime/2325162/gekijouban-chainsaw-man-reze-hen",
                        "ids": {
                          "simkl_id": 2325162,
                          "slug": "gekijouban-chainsaw-man-reze-hen"
                        },
                        "ratings": {
                          "simkl": {
                            "rating": 8.8,
                            "votes": 1762
                          },
                          "mal": {
                            "rating": 9.1,
                            "votes": 304714
                          }
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Anime"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-best-anime",
          "metadata": {
            "sidebarTitle": "Best of"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "All-time top",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/anime/best/all?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "curl",
            "label": "Most voted",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/anime/best/voted?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "curl",
            "label": "Most watched this month",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/anime/best/watched?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "curl",
            "label": "Anime movies only",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/anime/best/all?type=movies&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/anime/episodes/{id}": {
      "get": {
        "operationId": "get-anime-episodes-id",
        "summary": "List episodes for an anime",
        "description": "Returns the full episode list for a Simkl anime ID, including specials. For anime, season is omitted in regular episodes (anime is treated as a single canonical season per AniDB); specials use `type: \"special\"` and lack a `season`/`episode` pair.\n\n#### Item shape\n\n```json\n{\n  \"title\": \"To You, in 2000 Years\",\n  \"description\": \"...\",\n  \"episode\": 1,\n  \"type\": \"episode\",\n  \"aired\": true,\n  \"img\": \"https://wsrv.nl/?url=https://simkl.in/episodes/...&q=90\",\n  \"date\": \"2013-04-07T00:00:00+09:00\",\n  \"ids\": {\n    \"simkl_id\": 1010234\n  },\n  \"tvdb\": {\n    \"season\": 1,\n    \"episode\": 1\n  }\n}\n```\n\n`tvdb.season` / `tvdb.episode` reflect the original TVDB numbering when AniDB mapping diverges.\n\nResponses are **Cloudflare-cached by Simkl ID**, so repeat lookups of popular anime are near-free. Parallel requests against this endpoint are explicitly allowed (see [Rate limits → Parallel requests](/resources/rate-limits#parallel-requests-when-allowed)).\n\n**Cache invalidation is automatic.** When Simkl updates the underlying episode list (new episode airs, airdate change, title edit, image swap, etc.), the corresponding Cloudflare cache entry is purged server-side. The next call returns the fresh data — there's no TTL to wait out. Your own app-level cache, if any, still has to be invalidated by your client.\n\nUse the parent anime's Simkl ID. If you only have an external ID (MAL, AniDB, AniList, Kitsu, …), resolve it via [`GET /redirect`](/api-reference/redirect) first.\n\nErrors: `400 empty_id` if `id` is missing.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "**Simkl ID of the anime** — the parent anime's Simkl ID (not an individual episode ID). The endpoint returns the full episode list for that anime. Use a Simkl ID directly when you have one — the response is Cloudflare-cached.\n\n**If you only have an external ID** (MAL, AniDB, AniList, Kitsu, etc.), resolve it to a Simkl ID first via [`GET /redirect`](/api-reference/redirect).",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Array of anime episode entries. Regular episodes are numbered sequentially (AniDB style — no `season` field); specials and movies in the listing carry `type: \"special\"`. When a TVDB mapping exists, a `tvdb` object pins down the corresponding TVDB season/episode for cross-referencing. Empty array `[]` for an unknown anime ID (Type 3 null).",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AnimeEpisodeDetail"
                  }
                },
                "examples": {
                  "demon_slayer_first_episode": {
                    "summary": "Modern anime, regular episodes with TVDB mapping (Demon Slayer)",
                    "description": "Live data from `GET /anime/episodes/831411`. Note `season` is **omitted** (Type 2 — doesn't apply to anime); `tvdb` carries the TVDB mapping for the same episode.",
                    "value": [
                      {
                        "title": "Cruelty",
                        "description": "It is the Taisho Period. Tanjiro Kamado is living a modest but blissful life in the mountains with his family. One day, when he returns from selling charcoal in town, he finds his family slaughtered in pools of blood after a demon attack.",
                        "episode": 1,
                        "type": "episode",
                        "aired": true,
                        "img": "83/8351897a97a89d0e7",
                        "date": "2019-04-06T23:30:00+09:00",
                        "ids": {
                          "simkl_id": 4170591
                        },
                        "tvdb": {
                          "season": 1,
                          "episode": 1
                        }
                      },
                      {
                        "title": "Trainer Sakonji Urokodaki",
                        "description": "Tanjiro encounters a man named Giyu Tomioka who recommends he learn from a man named Sakonji Urokodaki.",
                        "episode": 2,
                        "type": "episode",
                        "aired": true,
                        "img": "83/8362c0d76f3a3a7f",
                        "date": "2019-04-13T23:30:00+09:00",
                        "ids": {
                          "simkl_id": 4170592
                        },
                        "tvdb": {
                          "season": 1,
                          "episode": 2
                        }
                      }
                    ]
                  },
                  "attack_on_titan_with_special": {
                    "summary": "Anime listing including a special / picture drama",
                    "description": "Older series where `description` and `img` may be `null` (Type 4) and specials follow the numbered episodes. Picture-drama entries carry `type: \"special\"` with no `episode` number.",
                    "value": [
                      {
                        "title": "To You, 2000 Years in the Future: The Fall of Zhiganshina (1)",
                        "description": null,
                        "episode": 1,
                        "type": "episode",
                        "aired": true,
                        "img": "26/26148581d640c58b8",
                        "date": "2013-04-06T15:00:00+09:00",
                        "ids": {
                          "simkl_id": 958466
                        }
                      },
                      {
                        "title": "Picture Drama 3",
                        "description": null,
                        "type": "special",
                        "aired": true,
                        "img": "68/689124d248604d0d",
                        "date": "2013-09-17T15:00:00+09:00",
                        "ids": {
                          "simkl_id": 979612
                        }
                      }
                    ]
                  },
                  "unknown_id_empty": {
                    "summary": "Unknown anime ID — empty array (Type 3 null)",
                    "description": "When the parent anime's Simkl ID doesn't match any record, the response is `200 []`.",
                    "value": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "Empty path segment — the path was hit as `/tv/episodes/` or `/anime/episodes/` (no `id`). Provide a Simkl ID for the parent show or anime in the path. See [Standard media objects -> Supported ID keys](/conventions/standard-media-objects#supported-id-keys).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "empty_id": {
                    "summary": "Empty `id` path segment",
                    "value": {
                      "error": "empty_id",
                      "code": 400
                    }
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Anime"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-anime-episodes",
          "metadata": {
            "sidebarTitle": "Anime episodes"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/anime/genres/{genre}/{type}/{network}/{year}/{sort}": {
      "get": {
        "operationId": "get-anime-genres",
        "summary": "Anime by genre",
        "description": "<Warning>\n**Not for TV / console / 10-foot apps.** The V1 genre-browse endpoints return a thin per-item shape (`title`, `year`, `poster`, `ids`, `ratings`, `rank`). Building a TV-app grid that shows overview text, full ratings, networks, runtimes, recommendations, or trailers would force one per-item refetch against the detail endpoint per visible card. **Wait for the V2 Beta API**, which returns the richer per-item shape TV-app surfaces need in a single call. If you're targeting TV / console / streaming-box clients, please hold off integrating these endpoints.\n</Warning>\n\nBrowse anime filtered by genre, type, network, year, and sort order. Path is `/anime/genres/{genre}/{type}/{network}/{year}/{sort}` — all segments **required** (use `all` as the wildcard).\n\nThis is the **5-segment** variant (no `country` segment — anime is dominated by Japanese productions, country filtering isn't useful here).\n\n| Path param | Values |\n|---|---|\n| `genre` | `all`, `action`, `adventure`, `comedy`, `drama`, `ecchi`, `educational`, `fantasy`, `gag-humor`, `gore`, `harem`, `historical`, `horror`, `idol`, `isekai`, `josei`, `kids`, `magic`, `martial-arts`, `mecha`, `military`, `music`, `mystery`, `mythology`, `parody`, `psychological`, `racing`, `reincarnation`, `romance`, `samurai`, `school`, `sci-fi`, `seinen`, `shoujo`, `shoujo-ai`, `shounen`, `shounen-ai`, `slice-of-life`, `space`, `sports`, `strategy-game`, `super-power`, `supernatural`, `thriller`, `vampire`, `yaoi`, `yuri` |\n| `type` | `all`, `tv`, `movies`, `ovas`, `onas`, `specials`, `music` |\n| `network` | `all` or a network slug (`tv-tokyo`, `crunchyroll`, …) |\n| `year` | `all`, single year, or decade |\n| `sort` | `popular-this-week`, `popular-this-month`, `popular-all-time`, `rank`, `release-date`, `voted`, `watched` |\n\nItems carry an additional `anime_type` field (`tv` / `movie` / `ova` / `ona` / `special` / `music`).\n\n#### Pagination\n\n| Param | Default | Notes |\n|---|---|---|\n| `page` | `1` | Hard-capped server-side at `20`. Higher values clamp silently. |\n| `limit` | `60` | Hard-capped server-side at `60`. Higher values clamp silently. Returned `X-Pagination-Limit` reflects the clamped value. |\n\n`X-Pagination-*` headers on every response — see [Pagination](/conventions/pagination).\n\n#### Silent fallbacks\n\nBad path segments DO NOT return errors:\n\n| Bad input | What happens |\n|---|---|\n| Unknown `genre` slug (`zzz`) | Top-level response is `null` (NOT `[]`). |\n| Unknown `year` (e.g. `zzz`) | Silently treated as `all` — full result set. |\n| Unknown `sort` (`zzzsortzzz`) | Silently treated as default sort order. |\n| Unknown `country` / `network` | Silently treated as `all`. |\n\n#### Errors\n\n| Status | When |\n|---|---|\n| `412 client_id_failed` | Missing or invalid `client_id` |\n| `500` | Server error |\n\nNo `400` or `404` — bad segments fall back silently or return `null`.\n",
        "parameters": [
          {
            "name": "genre",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "action",
            "description": "Anime genre slug, or `all`. See description for the full set."
          },
          {
            "name": "type",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "tv",
                "movies",
                "ovas",
                "onas",
                "specials",
                "music"
              ]
            },
            "example": "tv"
          },
          {
            "name": "network",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "all",
            "description": "Network slug (`tv-tokyo`, `crunchyroll`, …) or `all`."
          },
          {
            "name": "year",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "2010s",
            "description": "`all`, single year, or decade."
          },
          {
            "name": "sort",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "popular-this-week",
                "popular-this-month",
                "popular-all-time",
                "rank",
                "release-date",
                "voted",
                "watched"
              ]
            },
            "example": "popular-this-month"
          },
          {
            "$ref": "#/components/parameters/PageParam"
          },
          {
            "$ref": "#/components/parameters/LimitGenresParam"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Pagination-Page": {
                "schema": {
                  "type": "string"
                },
                "description": "Current page (after clamp)."
              },
              "X-Pagination-Limit": {
                "schema": {
                  "type": "string"
                },
                "description": "Items per page (after clamp; max 60)."
              },
              "X-Pagination-Page-Count": {
                "schema": {
                  "type": "string"
                },
                "description": "Total number of pages."
              },
              "X-Pagination-Item-Count": {
                "schema": {
                  "type": "string"
                },
                "description": "Total number of items across all pages."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenresResponse"
                },
                "examples": {
                  "anime_all_popular_month": {
                    "summary": "All-genre anime, popular this month (top 1; `anime_type` present)",
                    "value": [
                      {
                        "title": "Shingeki no Kyojin",
                        "year": 2013,
                        "date": "2013-04-07T00:00:00+09:00",
                        "url": "/anime/39687/shingeki-no-kyojin",
                        "poster": "23/23563e7856a42e5",
                        "fanart": "73/735850821d68e7e94",
                        "ids": {
                          "simkl_id": 39687,
                          "slug": "shingeki-no-kyojin"
                        },
                        "anime_type": "tv",
                        "rank": 120,
                        "ratings": {
                          "simkl": {
                            "rating": 8.7,
                            "votes": 12291
                          },
                          "mal": {
                            "rating": 8.6,
                            "votes": 3069367
                          }
                        }
                      }
                    ]
                  },
                  "anime_action_tv": {
                    "summary": "Action anime, TV-only filter",
                    "value": [
                      {
                        "title": "Shingeki no Kyojin",
                        "year": 2013,
                        "date": "2013-04-07T00:00:00+09:00",
                        "url": "/anime/39687/shingeki-no-kyojin",
                        "poster": "23/23563e7856a42e5",
                        "fanart": "73/735850821d68e7e94",
                        "ids": {
                          "simkl_id": 39687,
                          "slug": "shingeki-no-kyojin"
                        },
                        "anime_type": "tv",
                        "rank": 120,
                        "ratings": {
                          "simkl": {
                            "rating": 8.7,
                            "votes": 12291
                          },
                          "mal": {
                            "rating": 8.6,
                            "votes": 3069367
                          }
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Anime"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-anime-genres",
          "metadata": {
            "sidebarTitle": "Genres"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "anime_all_popular_month",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/anime/genres/all/all/all/all/popular-this-month?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0&limit=10\""
          },
          {
            "lang": "Shell",
            "label": "anime_action_tv",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/anime/genres/action/tv/all/all/popular-this-month?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0&limit=10\""
          }
        ]
      }
    },
    "/anime/premieres/{param}": {
      "get": {
        "summary": "Anime premieres (new + upcoming)",
        "operationId": "get-anime-premieres",
        "description": "Anime premieres — recently aired or upcoming new anime. Mirrors the [Simkl Anime Premieres](https://simkl.com/anime/premieres/) page. No `access_token` required.\n\nPass `new` for anime that already aired (newest first), or `soon` for anime airing in the next few weeks (soonest first). Any path value other than `new` is treated as `soon`.\n\nThe two shapes differ slightly: items in the `new` response include `rank` and `ratings`; items in the `soon` response don't carry those fields at all (the title hasn't aired enough to be ranked or rated yet). Every item carries an `anime_type` field (`tv` / `ona` / `ova` / `movie` / `special` / `music`).\n\nSame behavior as [`/tv/premieres`](/api-reference/simkl/get-tv-premieres) but **without the US/CA filter** — the anime catalog is served globally. Dates use a `+09:00` offset (Japan time).\n\n#### Query parameters\n\n| Param | Default | Notes |\n|---|---|---|\n| `type` | (any) | Optional. `all`, `tv`, `movies`, `ovas`, `onas`, or `music`. Anything else is ignored. |\n| `page` | `1` | 1 to 20. Higher values are reduced to 20. |\n| `limit` | `60` | 1 to 60. Higher values are reduced to 60. |\n\n`X-Pagination-*` headers on every response — see [Pagination](/conventions/pagination).\n\nThe full per-item shape is in the **Response** panel on the right.\n\n#### Errors\n\n| Status | When |\n|---|---|\n| `412` | Missing or invalid `client_id` |\n| `500` | Server error |\n\nBogus `param` or `type` values silently fall back — no `400`. The endpoint never returns `404`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PremieresParam"
          },
          {
            "$ref": "#/components/parameters/PremieresAnimeTypeParam"
          },
          {
            "$ref": "#/components/parameters/PremieresPageParam"
          },
          {
            "$ref": "#/components/parameters/PremieresLimitParam"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK — array of items. Shape depends on `{param}` (see `oneOf` branches).",
            "headers": {
              "X-Pagination-Page": {
                "schema": {
                  "type": "string"
                },
                "description": "Current page (after clamp)."
              },
              "X-Pagination-Limit": {
                "schema": {
                  "type": "string"
                },
                "description": "Items per page (after clamp; max 60)."
              },
              "X-Pagination-Page-Count": {
                "schema": {
                  "type": "string"
                },
                "description": "Total number of pages."
              },
              "X-Pagination-Item-Count": {
                "schema": {
                  "type": "string"
                },
                "description": "Total number of items across all pages."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PremieresResponse"
                },
                "examples": {
                  "Recent releases": {
                    "summary": "Recent releases",
                    "value": [
                      {
                        "title": "Kidou Keisatsu Patlabor EZY",
                        "year": 2026,
                        "date": "2026-05-15T00:00:00+09:00",
                        "url": "/anime/693329/kidou-keisatsu-patlabor-ezy",
                        "poster": "19/193846462efc60a35a",
                        "ids": {
                          "simkl_id": 693329,
                          "slug": "kidou-keisatsu-patlabor-ezy"
                        },
                        "anime_type": "movie",
                        "rank": null,
                        "ratings": {
                          "simkl": {
                            "rating": 10,
                            "votes": 1
                          },
                          "mal": {
                            "rating": 0,
                            "votes": 0
                          }
                        }
                      }
                    ]
                  },
                  "Upcoming": {
                    "summary": "Upcoming",
                    "value": [
                      {
                        "title": "Super no Ura de Yani Suu Futari",
                        "year": 2026,
                        "date": "2026-06-03T00:00:00+09:00",
                        "url": "/anime/2838478/super-no-ura-de-yani-suu-futari",
                        "poster": "19/193640953d812c9e9a",
                        "ids": {
                          "simkl_id": 2838478,
                          "slug": "super-no-ura-de-yani-suu-futari"
                        },
                        "anime_type": "ona"
                      }
                    ]
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Anime"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-anime-premieres",
          "metadata": {
            "sidebarTitle": "Premieres"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "Recent releases",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/anime/premieres/new?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "curl",
            "label": "Upcoming",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/anime/premieres/soon?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/anime/{id}": {
      "get": {
        "operationId": "get-anime-id",
        "summary": "Anime details",
        "description": "Full detail record for one anime — title, overview, year, runtime, network, status, genres, studios (list of `{id, name}`), related titles, ratings, posters, fanart, external IDs, alternate titles, trailers, episode count, AniDB-mapped TVDB seasons, user recommendations. The default response is already complete; no flags needed.\n\nResponses are **Cloudflare-cached by Simkl ID**, so repeat lookups of popular titles are near-free. Parallel requests against this endpoint are explicitly allowed (see [Rate limits → Parallel requests](/resources/rate-limits#parallel-requests-when-allowed)).\n\n**Cache invalidation is automatic.** When Simkl updates the underlying record (admin edits, automated metadata refresh, image swap, related-titles change, etc.), the corresponding Cloudflare cache entry is purged server-side. The next call to this endpoint returns the fresh data — there's no TTL to wait out and no client-side cache-busting needed. Your own app-level cache, if any, still has to be invalidated by your client.\n\nUse a Simkl ID for the lookup. If you only have an external ID, resolve it via [`GET /redirect`](/api-reference/redirect) first.\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "**Simkl ID** for the item. Simkl IDs are stable, unambiguous, and the response is Cloudflare-cached by Simkl ID, so repeat lookups are very fast.\n\n**If you only have an external ID** (IMDb, TMDB, TVDB, MAL, AniDB, etc.), resolve it to a Simkl ID first via [`GET /redirect`](/api-reference/redirect) — it returns the Simkl ID in the `Location` header without a JSON payload, and the follow-up detail call is Cloudflare-cached.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "831411"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/AnimeDetail"
                    },
                    {
                      "type": "array",
                      "items": {},
                      "maxItems": 0,
                      "title": "Empty (unknown Simkl ID)",
                      "description": "Empty array `[]` — see `unknown_id_empty` example below."
                    }
                  ]
                },
                "examples": {
                  "demon_slayer": {
                    "summary": "Modern shounen (Demon Slayer, simkl 831411)",
                    "description": "Modern ongoing anime. Has the canonical anime ID set (`mal`, `anidb`, `anilist`, `kitsu`) alongside the shared external IDs. Ratings carry `simkl` + `mal` but **no `imdb`** — most modern anime aren't catalogued there. Exercises `anime_type: tv`, `studios`, `mapped_tvdb_seasons`.",
                    "value": {
                      "title": "Kimetsu no Yaiba",
                      "en_title": "Demon Slayer: Kimetsu no Yaiba",
                      "year": 2019,
                      "type": "anime",
                      "anime_type": "tv",
                      "ids": {
                        "simkl": 831411,
                        "slug": "kimetsu-no-yaiba",
                        "imdb": "tt9335498",
                        "mal": "38000",
                        "tvdb": "348545",
                        "tvdbslug": "demon-slayer-kimetsu-no-yaiba",
                        "tmdb": "85937",
                        "anilist": "101922",
                        "kitsu": "41370",
                        "traktslug": "demon-slayer-kimetsu-no-yaiba",
                        "anidb": "14107"
                      },
                      "rank": 14,
                      "droprate": "0.8%",
                      "poster": "10/108215c95bbe0c40c",
                      "fanart": "11/11108654def22b4f7",
                      "runtime": 25,
                      "certification": "TV-MA",
                      "country": "JP",
                      "overview": "It is the Taisho Period in Japan. Tanjiro, a kindhearted boy who sells charcoal for a living, finds his family slaughtered by a demon. To make matters worse, his younger sister Nezuko, the sole survivor, has been transformed into a demon herself.",
                      "genres": [
                        "Action",
                        "Adventure",
                        "Fantasy"
                      ],
                      "network": "Fuji TV",
                      "status": "ended",
                      "first_aired": "2019-04-06",
                      "last_aired": "2024-06-30",
                      "airs": {
                        "day": "Sunday",
                        "time": "23:15",
                        "timezone": "Asia/Tokyo"
                      },
                      "total_episodes": 55,
                      "year_start_end": "2019-",
                      "season_name_year": "Spring 2019",
                      "mapped_tvdb_seasons": [
                        1
                      ],
                      "studios": [
                        {
                          "name": "ufotable"
                        }
                      ],
                      "relations": {},
                      "alt_titles": [
                        {
                          "name": "Demon Slayer: Kimetsu no Yaiba",
                          "lang": 22,
                          "type": "official"
                        },
                        {
                          "name": "鬼滅の刃",
                          "lang": 25,
                          "type": "original"
                        }
                      ],
                      "ratings": {
                        "simkl": {
                          "rating": 8.7,
                          "votes": 1850
                        },
                        "mal": {
                          "rating": 8.6,
                          "votes": 1620000
                        }
                      },
                      "trailers": [
                        {
                          "name": "PV",
                          "youtube": "VQGCKyvzIM4",
                          "size": 1080
                        }
                      ],
                      "users_recommendations": [
                        {
                          "title": "Jujutsu Kaisen",
                          "year": 2020,
                          "poster": "73/73892ec77b6c7e9d",
                          "type": "anime",
                          "ids": {
                            "simkl": 1110742,
                            "slug": "jujutsu-kaisen"
                          }
                        }
                      ]
                    }
                  },
                  "classic_with_triple_ratings": {
                    "summary": "Classic anime with imdb+mal+simkl ratings (Death Note, simkl 40190)",
                    "description": "Established classic that pre-dates the MAL-only era of recent anime catalogs. Has the **rare triple-rating** (`simkl` + `mal` + `imdb`). Demonstrates `en_title` as an empty string — Type 4 null (data not on file in that exact slot, but a non-null fallback was returned for back-compat). Use this to test code that handles both `null` and empty-string for the same semantic.",
                    "value": {
                      "title": "Death Note",
                      "en_title": null,
                      "year": 2006,
                      "type": "anime",
                      "anime_type": "tv",
                      "ids": {
                        "simkl": 40190,
                        "slug": "death-note",
                        "imdb": "tt0877057",
                        "mal": "1535",
                        "tvdb": "79481",
                        "tvdbslug": "death-note",
                        "tmdb": "13916",
                        "anilist": "1535",
                        "kitsu": "1376",
                        "anidb": "4563"
                      },
                      "rank": 5,
                      "poster": "60/60822040ab21d22b",
                      "runtime": 25,
                      "country": "JP",
                      "genres": [
                        "Mystery",
                        "Psychological",
                        "Supernatural",
                        "Thriller"
                      ],
                      "network": "Nippon TV",
                      "status": "Ended",
                      "first_aired": "2006-10-04",
                      "last_aired": "2007-06-27",
                      "total_episodes": 37,
                      "year_start_end": "2006-2007",
                      "season_name_year": "Fall 2006",
                      "studios": [
                        {
                          "name": "Madhouse"
                        }
                      ],
                      "ratings": {
                        "simkl": {
                          "rating": 9.0,
                          "votes": 4200
                        },
                        "mal": {
                          "rating": 8.6,
                          "votes": 3700000
                        },
                        "imdb": {
                          "rating": 9.0,
                          "votes": 410000
                        }
                      }
                    }
                  },
                  "unknown_id_empty": {
                    "summary": "Unknown Simkl ID — empty array (Type 3 null)",
                    "description": "When the path Simkl ID is well-formed (numeric) but no catalog record exists at that ID, the response is `200 []`, not `404`. Treat as 'not found' — see [Null and missing values · Type 3](/conventions/null-values#type-3).",
                    "value": []
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Anime"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-anime",
          "metadata": {
            "sidebarTitle": "Anime details"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/movies/genres/{genre}/{type}/{country}/{year}/{sort}": {
      "get": {
        "operationId": "get-movies-genres",
        "summary": "Movies by genre",
        "description": "<Warning>\n**Not for TV / console / 10-foot apps.** The V1 genre-browse endpoints return a thin per-item shape (`title`, `year`, `poster`, `ids`, `ratings`, `rank`). Building a TV-app grid that shows overview text, full ratings, networks, runtimes, recommendations, or trailers would force one per-item refetch against the detail endpoint per visible card. **Wait for the V2 Beta API**, which returns the richer per-item shape TV-app surfaces need in a single call. If you're targeting TV / console / streaming-box clients, please hold off integrating these endpoints.\n</Warning>\n\nBrowse movies filtered by genre, country, year, and sort order. Path is `/movies/genres/{genre}/{type}/{country}/{year}/{sort}` — all segments **required** (use `all` as the wildcard).\n\nThe `type` segment is reserved — always pass the literal value `movies`.\n\n| Path param | Values |\n|---|---|\n| `genre` | `all`, `action`, `adventure`, `animation`, `comedy`, `crime`, `documentary`, `drama`, `erotica`, `family`, `fantasy`, `history`, `horror`, `music`, `mystery`, `romance`, `science-fiction`, `thriller`, `tv-movie`, `war`, `western` |\n| `type` | `movies` (literal) |\n| `country` | `all` or ISO 3166-1 alpha-2 (`us`, `gb`, `jp`, …) |\n| `year` | `all`, single year (`2019`), or decade (`2010s`, `2000s`) |\n| `sort` | `popular-this-week`, `popular-this-month`, `popular-all-time`, `rank`, `release-date`, `voted`, `watched` |\n\nItems always carry `ids.tmdb` — the discover query filters out movies without a TMDB-linked record.\n\n#### Pagination\n\n| Param | Default | Notes |\n|---|---|---|\n| `page` | `1` | Hard-capped server-side at `20`. Higher values clamp silently. |\n| `limit` | `60` | Hard-capped server-side at `60`. Higher values clamp silently. Returned `X-Pagination-Limit` reflects the clamped value. |\n\n`X-Pagination-*` headers on every response — see [Pagination](/conventions/pagination).\n\n#### Silent fallbacks\n\nBad path segments DO NOT return errors:\n\n| Bad input | What happens |\n|---|---|\n| Unknown `genre` slug (`zzz`) | Top-level response is `null` (NOT `[]`). |\n| Unknown `year` (e.g. `zzz`) | Silently treated as `all` — full result set. |\n| Unknown `sort` (`zzzsortzzz`) | Silently treated as default sort order. |\n| Unknown `country` / `network` | Silently treated as `all`. |\n\n#### Errors\n\n| Status | When |\n|---|---|\n| `412 client_id_failed` | Missing or invalid `client_id` |\n| `500` | Server error |\n\nNo `400` or `404` — bad segments fall back silently or return `null`.\n",
        "parameters": [
          {
            "name": "genre",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "action",
            "description": "Movie genre slug, or `all`. See description for the full set."
          },
          {
            "name": "type",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "movies"
              ]
            },
            "example": "movies",
            "description": "Reserved — always pass the literal value `movies`."
          },
          {
            "name": "country",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "us",
            "description": "ISO 3166-1 alpha-2 country code (e.g. `us`, `gb`, `jp`) or `all`."
          },
          {
            "name": "year",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "2010s",
            "description": "`all`, single year (`2019`), or decade (`2010s`, `2000s`). Bogus values silently fall back to `all`."
          },
          {
            "name": "sort",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "popular-this-week",
                "popular-this-month",
                "popular-all-time",
                "rank",
                "release-date",
                "voted",
                "watched"
              ]
            },
            "example": "popular-this-month"
          },
          {
            "$ref": "#/components/parameters/PageParam"
          },
          {
            "$ref": "#/components/parameters/LimitGenresParam"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Pagination-Page": {
                "schema": {
                  "type": "string"
                },
                "description": "Current page (after clamp)."
              },
              "X-Pagination-Limit": {
                "schema": {
                  "type": "string"
                },
                "description": "Items per page (after clamp; max 60)."
              },
              "X-Pagination-Page-Count": {
                "schema": {
                  "type": "string"
                },
                "description": "Total number of pages."
              },
              "X-Pagination-Item-Count": {
                "schema": {
                  "type": "string"
                },
                "description": "Total number of items across all pages."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenresResponse"
                },
                "examples": {
                  "movies_action_us_popular_month": {
                    "summary": "Action movies, US, popular this month (top 2)",
                    "value": [
                      {
                        "title": "Avengers: Endgame",
                        "year": 2019,
                        "date": "2019-04-24T00:00:00-05:00",
                        "url": "/movies/430306/avengers-endgame",
                        "poster": "78/7850544702b693f1f",
                        "fanart": "78/7867760c274aa5240",
                        "ids": {
                          "simkl_id": 430306,
                          "slug": "avengers-endgame",
                          "tmdb": "299534"
                        },
                        "rank": 126,
                        "ratings": {
                          "simkl": {
                            "rating": 8.3,
                            "votes": 10198
                          },
                          "imdb": {
                            "rating": 8.4,
                            "votes": 1446869
                          }
                        }
                      },
                      {
                        "title": "Interstellar",
                        "year": 2014,
                        "date": "2014-11-05T00:00:00-05:00",
                        "url": "/movies/250822/interstellar",
                        "poster": "20/2052598c2716ef054",
                        "fanart": "17/1720484cee8bec79f",
                        "ids": {
                          "simkl_id": 250822,
                          "slug": "interstellar",
                          "tmdb": "157336"
                        },
                        "rank": 31,
                        "ratings": {
                          "simkl": {
                            "rating": 8.7,
                            "votes": 12036
                          },
                          "imdb": {
                            "rating": 8.7,
                            "votes": 2530240
                          }
                        }
                      }
                    ]
                  },
                  "movies_drama_gb_2010s_rank": {
                    "summary": "British dramas from the 2010s sorted by rank (top 1)",
                    "value": [
                      {
                        "title": "The Phantom of the Opera at the Royal Albert Hall",
                        "year": 2011,
                        "date": "2011-09-27T00:00:00-05:00",
                        "url": "/movies/161614/the-phantom-of-the-opera-at-the-royal-albert-hall",
                        "poster": "15/15249069a77e4555e5",
                        "fanart": "12/12549615b75d07856e",
                        "ids": {
                          "simkl_id": 161614,
                          "slug": "the-phantom-of-the-opera-at-the-royal-albert-hall",
                          "tmdb": "76115"
                        },
                        "rank": 37,
                        "ratings": {
                          "simkl": {
                            "rating": 8.5,
                            "votes": 128
                          },
                          "imdb": {
                            "rating": 8.8,
                            "votes": 10845
                          }
                        }
                      }
                    ]
                  },
                  "movies_bogus_genre_returns_null": {
                    "summary": "Unknown genre slug — top-level `null` (NOT `[]`)",
                    "value": null
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Movies"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-movies-genres",
          "metadata": {
            "sidebarTitle": "Genres"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "movies_action_us_popular_month",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/movies/genres/action/movies/us/all/popular-this-month?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0&limit=10\""
          },
          {
            "lang": "Shell",
            "label": "movies_drama_gb_2010s_rank",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/movies/genres/drama/movies/gb/2010s/rank?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0&limit=10\""
          }
        ]
      }
    },
    "/movies/{id}": {
      "get": {
        "operationId": "get-movies-id",
        "summary": "Movie details",
        "description": "Full detail record for one movie — title, overview, year, runtime, country, language, certification, genres, director, ratings, posters, fanart, external IDs, alternate titles, release-date list per region, budget, revenue, trailers, similar-movie recommendations. The default response is already complete; no flags needed.\n\nResponses are **Cloudflare-cached by Simkl ID**, so repeat lookups of popular titles are near-free. Parallel requests against this endpoint are explicitly allowed (see [Rate limits → Parallel requests](/resources/rate-limits#parallel-requests-when-allowed)).\n\n**Cache invalidation is automatic.** When Simkl updates the underlying record (admin edits, automated metadata refresh, image swap, related-titles change, etc.), the corresponding Cloudflare cache entry is purged server-side. The next call to this endpoint returns the fresh data — there's no TTL to wait out and no client-side cache-busting needed. Your own app-level cache, if any, still has to be invalidated by your client.\n\nUse a Simkl ID for the lookup. If you only have an external ID, resolve it via [`GET /redirect`](/api-reference/redirect) first.\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "**Simkl ID** for the item. Simkl IDs are stable, unambiguous, and the response is Cloudflare-cached by Simkl ID, so repeat lookups are very fast.\n\n**If you only have an external ID** (IMDb, TMDB, TVDB, MAL, AniDB, etc.), resolve it to a Simkl ID first via [`GET /redirect`](/api-reference/redirect) — it returns the Simkl ID in the `Location` header without a JSON payload, and the follow-up detail call is Cloudflare-cached.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "472214"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/MovieDetail"
                    },
                    {
                      "type": "array",
                      "items": {},
                      "maxItems": 0,
                      "title": "Empty (unknown Simkl ID)",
                      "description": "Empty array `[]` — see `unknown_id_empty` example below."
                    }
                  ]
                },
                "examples": {
                  "inception": {
                    "summary": "Modern blockbuster (Inception, simkl 472214)",
                    "description": "Full record for a popular modern movie. Carries the standard `simkl`/`imdb` ratings, the common social-media IDs (`fb`, `letterslug`, `traktmslug`, `jwslug`, `tvdbm`, etc.), an extensive `release_dates` timeline per ISO 3166-1 country, and the recommended-titles list. Examples below are truncated to keep the doc compact; live responses carry the full arrays.",
                    "value": {
                      "title": "Inception",
                      "year": 2010,
                      "type": "movie",
                      "ids": {
                        "simkl": 472214,
                        "slug": "inception",
                        "tmdb": "27205",
                        "imdb": "tt1375666",
                        "tvdbslug": "inception",
                        "tvdb": "113",
                        "fb": "inception",
                        "offen": "http://inceptionmovie.warnerbros.com/",
                        "letterboxd": "inception",
                        "traktslug": "inception-2010"
                      },
                      "rank": 20,
                      "droprate": "0.1%",
                      "poster": "14/14017865947c9d3d0d",
                      "fanart": "27/2745964f37d66f1bb",
                      "released": "2010-07-15",
                      "runtime": 148,
                      "director": "Christopher Nolan",
                      "certification": "PG-13",
                      "budget": 160000000,
                      "revenue": 839030630,
                      "overview": "Cobb, a skilled thief who commits corporate espionage by infiltrating the subconscious of his targets is offered a chance to regain his old life as payment for a task considered to be impossible: \"inception\", the implantation of another person's idea into a target's subconscious.",
                      "genres": [
                        "Action",
                        "Adventure",
                        "Science Fiction",
                        "Thriller"
                      ],
                      "country": "US",
                      "language": "EN",
                      "alt_titles": [
                        {
                          "name": "Origine",
                          "lang": 17,
                          "type": "official"
                        },
                        {
                          "name": "Inception",
                          "lang": 22,
                          "type": "official"
                        },
                        {
                          "name": "Origine",
                          "lang": 7,
                          "type": "synonym"
                        }
                      ],
                      "ratings": {
                        "simkl": {
                          "rating": 8.6,
                          "votes": 11454
                        },
                        "imdb": {
                          "rating": 8.8,
                          "votes": 2816410
                        }
                      },
                      "trailers": [
                        {
                          "name": "Official Trailer",
                          "youtube": "Jvurpf91omw",
                          "size": 1080
                        },
                        {
                          "name": "Official New UK Trailer",
                          "youtube": "JE9z-gy4De4",
                          "size": 1080
                        }
                      ],
                      "release_dates": [
                        {
                          "iso_3166_1": "US",
                          "results": [
                            {
                              "type": 1,
                              "release_date": "2010-07-13"
                            },
                            {
                              "type": 3,
                              "release_date": "2010-07-16"
                            },
                            {
                              "type": 5,
                              "release_date": "2010-12-07"
                            }
                          ]
                        },
                        {
                          "iso_3166_1": "GB",
                          "results": [
                            {
                              "type": 1,
                              "release_date": "2010-07-08"
                            },
                            {
                              "type": 3,
                              "release_date": "2010-07-16"
                            }
                          ]
                        }
                      ],
                      "users_recommendations": [
                        {
                          "title": "Interstellar",
                          "year": 2014,
                          "poster": "20/2052598c2716ef054",
                          "type": "movie",
                          "ids": {
                            "simkl": 250822,
                            "slug": "interstellar"
                          }
                        },
                        {
                          "title": "The Dark Knight",
                          "year": 2008,
                          "poster": "16/16943077cdd27f0cc6",
                          "type": "movie",
                          "ids": {
                            "simkl": 53282,
                            "slug": "the-dark-knight"
                          }
                        },
                        {
                          "title": "Fight Club",
                          "year": 1999,
                          "poster": "53/53342766816af5a20",
                          "type": "movie",
                          "ids": {
                            "simkl": 53894,
                            "slug": "fight-club"
                          }
                        }
                      ]
                    }
                  },
                  "classic_with_social_ids": {
                    "summary": "Classic film with extended social IDs (The Godfather, simkl 53434)",
                    "description": "A pre-internet classic. Notable because `ids` includes `instagram` and `tw` (Twitter/X) handles that newer titles often don't carry. Most fields are otherwise identical in shape to the modern example.",
                    "value": {
                      "title": "The Godfather",
                      "year": 1972,
                      "type": "movie",
                      "ids": {
                        "simkl": 53434,
                        "slug": "the-godfather",
                        "tmdb": "238",
                        "imdb": "tt0068646",
                        "fb": "TheGodfather",
                        "instagram": "TheGodfather",
                        "tw": "thegodfather",
                        "letterboxd": "the-godfather",
                        "traktslug": "the-godfather-1972"
                      },
                      "country": "US",
                      "language": "EN",
                      "released": "1972-03-14",
                      "runtime": 175,
                      "director": "Francis Ford Coppola",
                      "certification": "R",
                      "genres": [
                        "Drama",
                        "Crime"
                      ],
                      "ratings": {
                        "simkl": {
                          "rating": 8.9,
                          "votes": 3500
                        },
                        "imdb": {
                          "rating": 9.2,
                          "votes": 2000000
                        }
                      }
                    }
                  },
                  "unknown_id_empty": {
                    "summary": "Unknown Simkl ID — empty array (Type 3 null)",
                    "description": "When the path Simkl ID is well-formed (numeric) but no catalog record exists at that ID, the response is `200 []`, not `404`. Treat as 'not found' — see [Null and missing values · Type 3](/conventions/null-values#type-3). Empty results are also cached.",
                    "value": []
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Movies"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-movie",
          "metadata": {
            "sidebarTitle": "Movie details"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/oauth/authorize": {
      "get": {
        "operationId": "get-oauth-authorize",
        "summary": "Authorize a user",
        "description": "Step 1 of the OAuth 2.0 authorization-code flow. Redirect the user's browser to this URL on **simkl.com** (not api.simkl.com). Simkl shows a consent screen and, once the user approves, redirects to your `redirect_uri` with `?code=…`.\n\n> ⚠️ **Do not use a WebView on mobile.** Use the system browser or a Custom Tab. WebViews are blocked for security reasons.\n\n#### Parameters\n\n| Param | Required | Notes |\n|---|---|---|\n| `response_type` | yes | Must be `code`. |\n| `client_id` | yes | Your app's `client_id`. |\n| `redirect_uri` | conditional | Required for confidential clients and for any app that has a redirect URI registered. Optional only when using **PKCE** *and* your app has no registered redirect URI — in that case Simkl completes the consent flow on simkl.com itself. When sent, must match the URL registered for the app **byte-for-byte**. |\n| `state` | no | Random string you generate; echoed back to your `redirect_uri` for **CSRF protection**. Strongly recommended. |\n| `code_challenge` | conditional | Required for **PKCE** (public clients without `client_secret`). Base64url-encoded SHA-256 of your `code_verifier`. See the [Public PKCE walkthrough](/api-reference/oauth-pkce). |\n| `code_challenge_method` | no | `S256` (default, recommended) or `plain`. Case-sensitive — lowercase variants are silently ignored and your token exchange will then fail with `Wrong Secret`. |\n\nThe user is redirected to:\n\n```\nYOUR_REDIRECT_URI?code=AUTHORIZATION_CODE&state=YOUR_STATE\n```\n\nExchange the `code` for an `access_token` via [`POST /oauth/token`](/api-reference/simkl/exchange-token). Codes are short-lived; exchange immediately.\n\n<CardGroup cols={2}>\n  <Card title=\"OAuth 2.0 walkthrough\" icon=\"lock\" href=\"/api-reference/oauth\" horizontal>\n    Confidential-client (server-side) flow with `client_secret`.\n  </Card>\n  <Card title=\"Public PKCE walkthrough\" icon=\"shield-keyhole\" href=\"/api-reference/oauth-pkce\" horizontal>\n    Public-client (mobile / SPA / desktop) flow with `code_verifier` + `code_challenge`.\n  </Card>\n</CardGroup>",
        "parameters": [
          {
            "name": "response_type",
            "in": "query",
            "description": "must be \"code\"",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "code"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "name": "redirect_uri",
            "in": "query",
            "description": "Where Simkl sends the user back after they approve consent. Must match a URI pre-registered in your [app settings](https://simkl.com/settings/developer/) **byte-for-byte** (scheme, host, port, path, trailing slash, casing — all of it). Required for confidential-client flows. Optional when using PKCE *and* your app has no registered redirect URI — in that case the consent page completes the flow on simkl.com directly.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "http://yourdomain.com/oauth.html"
          },
          {
            "name": "state",
            "in": "query",
            "description": "Random string you generate; Simkl echoes it back unchanged on the redirect to your `redirect_uri`. Use this for CSRF protection — verify on the redirect that the value matches what you originally sent. Strongly recommended for browser-based clients.",
            "schema": {
              "type": "string"
            },
            "example": "state"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          },
          {
            "name": "code_challenge",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
            "description": "PKCE code challenge — base64url-encoded SHA-256 hash of the code verifier. Required for the PKCE flow (mobile/desktop/SPA clients without `client_secret`). Pair with the matching `code_verifier` when exchanging at [`POST /oauth/token`](/api-reference/simkl/exchange-token)."
          },
          {
            "name": "code_challenge_method",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "S256",
                "plain"
              ],
              "default": "S256"
            },
            "example": "S256",
            "description": "Hash method used to derive `code_challenge`. `S256` (SHA-256, default) is recommended; `plain` is accepted for legacy clients but discouraged."
          }
        ],
        "responses": {
          "302": {
            "description": "User approved. Browser is redirected to `redirect_uri?code=…&state=…`. Exchange the `code` immediately via [`POST /oauth/token`](/api-reference/simkl/exchange-token).",
            "headers": {
              "Location": {
                "description": "Your registered `redirect_uri` with `code` and (if you sent it) `state` appended.",
                "schema": {
                  "type": "string",
                  "format": "uri",
                  "example": "https://yourdomain.com/oauth.html?code=AUTHORIZATION_CODE&state=YOUR_STATE"
                }
              }
            }
          }
        },
        "tags": [
          "OAuth 2.0"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/authorize",
          "metadata": {
            "sidebarTitle": "OAuth authorize"
          }
        },
        "servers": [
          {
            "url": "https://simkl.com",
            "description": "Authorization is hosted on simkl.com (not api.simkl.com)."
          }
        ],
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/oauth/pin": {
      "get": {
        "operationId": "get-oauth-pin",
        "summary": "Request a PIN code",
        "description": "Step 1 of the **PIN flow** (also called the device flow). Best for TVs, consoles, smart watches, CLI tools — anywhere typing a URL is hard. You don't need `client_secret` for this flow.\n\nThe response contains a 5-character `user_code` to display, a `verification_uri` for the user to visit, an `expires_in` lifetime (15 minutes), and an `interval` you must respect when polling (5 seconds).\n\n#### Parameters\n\n| Param | Required | Notes |\n|---|---|---|\n| `client_id` | yes | Sent as `?client_id=…` URL query parameter. The `simkl-api-key` header is also accepted but the URL-parameter form is preferred. |\n| `redirect` | no | URL the simkl.com/pin page sends the user to **after they approve**. Must match a URL pre-registered in your app's developer settings. Mostly relevant for browser-extension and web-flavoured PIN integrations. |\n\n#### About the `device_code` response field\n\nThe response includes a `device_code` field whose value is the literal string `\"DEVICE_CODE\"` — it's a placeholder kept for compatibility with the OAuth 2.0 Device Authorization Grant response shape. Clients only need `user_code` (what you display, and what you poll on). You can ignore `device_code` entirely.\n\n<Warning>\n**Not the RFC 8628 device flow.** Simkl's PIN flow is *conceptually* similar to [RFC 8628 (OAuth Device Authorization Grant)](https://datatracker.ietf.org/doc/html/rfc8628) but the wire format differs in several spots:\n\n- `device_code` is a hardcoded placeholder, not a real opaque token.\n- Polling happens at `GET /oauth/pin/{user_code}` instead of `POST /oauth/token` with `grant_type=urn:ietf:params:oauth:grant-type:device_code`.\n- Pending poll responses are `{\"result\": \"KO\", \"message\": \"Authorization pending\"}` instead of `400 + {\"error\": \"authorization_pending\"}`.\n\nGeneric device-flow libraries (e.g. `openid-client` device-flow extension) won't work out of the box. Either write a custom client for the wire format above, or follow the [PIN flow walkthrough](/api-reference/pin) which uses the documented endpoints directly.\n</Warning>\n\n<Card title=\"PIN flow walkthrough\" icon=\"key\" href=\"/api-reference/pin\" horizontal>\n Device authorization for TVs, consoles, smart watches, and CLI tools — show a 5-character code, the user enters it at simkl.com/pin, the app polls for the access token.\n</Card>",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "name": "redirect",
            "in": "query",
            "description": "URL the simkl.com/pin page sends the user to **after they approve** the connection. Must match a URL pre-registered in your [app settings](https://simkl.com/settings/developer/). Optional — most PIN-flow clients (TVs, consoles, CLIs) don't need this since the user authorizes on a separate device and the app polls for the result.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "http://yourdomain.com/welcome"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PinCodeResponse"
                },
                "example": {
                  "result": "OK",
                  "device_code": "DEVICE_CODE",
                  "user_code": "5G6JAH",
                  "verification_uri": "https://simkl.com/pin",
                  "verification_url": "https://simkl.com/pin",
                  "expires_in": 900,
                  "interval": 5
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "tags": [
          "PIN"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-pin",
          "metadata": {
            "sidebarTitle": "Request PIN"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/oauth/token": {
      "post": {
        "operationId": "post-oauth-token",
        "summary": "Exchange an authorization code for an access token",
        "description": "Step 2 of OAuth 2.0. POST your authorization `code` here to receive an `access_token`. The success response carries `{access_token, token_type: \"bearer\", scope: \"public\", expires_in: 157680000}` — about 5 years. Save the token securely. **No refresh token is issued**; if a 401 arrives before that lifetime (user revoked from [Connected Apps](https://simkl.com/settings/connected-apps/)), send the user back through `/oauth/authorize` for a fresh consent.\n\n#### Wire format\n\nThe endpoint accepts both `application/x-www-form-urlencoded` (the RFC 6749 §3.2 default that most OAuth libraries use) and `application/json` — pick whichever your HTTP client prefers. Client credentials can be sent in **either** the request body (`client_id` + `client_secret`) **or** the `Authorization: Basic <base64(client_id:client_secret)>` header (RFC 6749 §2.3.1). All four combinations are equivalent. **Off-the-shelf OAuth libraries work out-of-the-box** with default configuration; see [OAuth client libraries](/api-reference/oauth-libraries) for live-tested examples across every popular runtime.\n\nTwo flows share this endpoint, distinguished by which secret you send:\n\n- **Confidential clients** (server-side web apps) send `client_secret` + `redirect_uri`.\n- **Public clients** (mobile, SPA, desktop, browser extensions) send `code_verifier` instead — no secret required. See the [Public PKCE walkthrough](/api-reference/oauth-pkce).\n\n#### Body fields\n\n| Field | Required | Notes |\n|---|---|---|\n| `grant_type` | yes | Must be `authorization_code`. |\n| `code` | yes | Authorization code returned to your `redirect_uri` (or, for PKCE-without-registered-URI, displayed on simkl.com). |\n| `client_id` | yes (in body or Basic Auth header) | Your app's `client_id`. |\n| `client_secret` | conditional | Confidential flow only. Mutually exclusive with `code_verifier`. May be sent in the body or in the `Authorization: Basic` header. |\n| `code_verifier` | conditional | PKCE flow only. The original verifier you generated locally; Simkl re-derives the challenge and matches it against what you sent on `/oauth/authorize`. |\n| `redirect_uri` | conditional | Required on the confidential flow (must match the URL registered for your app **byte-for-byte**). On PKCE, required only if you sent one to `/oauth/authorize` — and then it must match that one. |\n\n#### Errors\n\nAll failures return JSON with an `error` field (and usually a `message` field too). 401 responses additionally carry an RFC 6750 §3 `WWW-Authenticate: Bearer realm=\"api.simkl.com\", error=\"...\"` header.\n\n| Status | `error` | When |\n|---|---|---|\n| 403 | `empty_field` | A required body field is missing (`code`, `client_id`, `grant_type`, or both `client_secret`/`code_verifier`). |\n| 403 | `redirect_failed` | `redirect_uri` doesn't match the URL registered for the app. |\n| 401 | `secret_error` | Wrong `client_secret` (confidential flow) **or** PKCE verification failed (`message: \"PKCE verification failed\"`). |\n| 401 | `grant_error` | The `code` is invalid, expired, or already used. Codes are single-use — restart from `/oauth/authorize`. |\n\n<CardGroup cols={2}>\n  <Card title=\"OAuth 2.0 walkthrough\" icon=\"lock\" href=\"/api-reference/oauth\" horizontal>\n    Confidential-client (server-side) flow.\n  </Card>\n  <Card title=\"Public PKCE walkthrough\" icon=\"shield-keyhole\" href=\"/api-reference/oauth-pkce\" horizontal>\n    Public-client flow with `code_verifier`.\n  </Card>\n</CardGroup>",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "code": "d7be48f1559a6d794w1925237c626326c7dddfsa559a6d794w1925137c626313",
                "client_id": "c7be48f1559a6d794w1925237c626326c7bsdfsa559a6d794w1925137c626352",
                "client_secret": "a9be48f1529a2d794w1925237c626326c7dddfsa559a6d794w1925137c626321",
                "redirect_uri": "https://yourdomain.com/oauth.html",
                "grant_type": "authorization_code"
              },
              "schema": {
                "$ref": "#/components/schemas/OAuthTokenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Valid `code` will generate you the `access_token`",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthTokenResponse"
                },
                "example": {
                  "access_token": "YOUR_ACCESS_TOKEN",
                  "token_type": "bearer",
                  "scope": "public"
                }
              }
            }
          },
          "401": {
            "description": "Invalid code will give you a 401 error",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "grant_error",
                  "message": "Bad code provided."
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "tags": [
          "OAuth 2.0"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/exchange-token",
          "metadata": {
            "sidebarTitle": "OAuth token"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST https://api.simkl.com/oauth/token \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"code\":          \"AUTHORIZATION_CODE\",\n    \"client_id\":     \"YOUR_CLIENT_ID\",\n    \"client_secret\": \"YOUR_CLIENT_SECRET\",\n    \"redirect_uri\":  \"https://yourdomain.com/oauth.html\",\n    \"grant_type\":    \"authorization_code\"\n  }'"
          },
          {
            "lang": "curl",
            "label": "cURL (PKCE)",
            "source": "# Public clients (mobile / SPA / desktop) — PKCE variant.\n# Replace YOUR_CODE_VERIFIER with the verifier you generated locally\n# (the same one whose SHA-256 you sent as code_challenge in step 1).\ncurl -X POST https://api.simkl.com/oauth/token \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"code\":          \"AUTHORIZATION_CODE\",\n    \"client_id\":     \"YOUR_CLIENT_ID\",\n    \"code_verifier\": \"YOUR_CODE_VERIFIER\",\n    \"grant_type\":    \"authorization_code\"\n  }'"
          },
          {
            "lang": "JavaScript",
            "label": "Node",
            "source": "const res = await fetch('https://api.simkl.com/oauth/token', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\n    code:          'AUTHORIZATION_CODE',\n    client_id:     'YOUR_CLIENT_ID',\n    client_secret: 'YOUR_CLIENT_SECRET',\n    redirect_uri:  'https://yourdomain.com/oauth.html',\n    grant_type:    'authorization_code',\n  }),\n});\nconst { access_token } = await res.json();"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "import requests\nres = requests.post('https://api.simkl.com/oauth/token', json={\n    'code':          'AUTHORIZATION_CODE',\n    'client_id':     'YOUR_CLIENT_ID',\n    'client_secret': 'YOUR_CLIENT_SECRET',\n    'redirect_uri':  'https://yourdomain.com/oauth.html',\n    'grant_type':    'authorization_code',\n})\naccess_token = res.json()['access_token']"
          }
        ]
      }
    },
    "/ratings/{type}": {
      "get": {
        "operationId": "get-ratings-type",
        "summary": "Community ratings for items in the user's watchlist",
        "description": "<Note>\n**This endpoint returns Simkl's *community* ratings** (the public average + droprate + vote counts) for every item in the user's watchlist — not the user's own 1-10 scores. If you want **the user's own ratings**, every [`GET /sync/all-items`](/api-reference/simkl/get-all-items) response already carries `user_rating` (1-10 or `null`) per item — filter that client-side. For server-side filtering by score (e.g. \"give me only items I rated 9 or 10\"), see [`GET /sync/ratings/:type/:rating`](/api-reference/simkl/get-user-ratings).\n</Note>\n\nBulk Simkl-rating lookup for items across the user's watchlist. Useful for ranking the user's library against community ratings (e.g. \"what's the highest-community-rated movie in my Plan-to-Watch?\").\n\nReturns an array of `{id, simkl: {rating, votes, droprate}}` for every item in the requested watchlist statuses. Pair with [`GET /movies/{id}`](/api-reference/simkl/get-movie) / [`GET /tv/{id}`](/api-reference/simkl/get-tv-show) / [`GET /anime/{id}`](/api-reference/simkl/get-anime) (Cloudflare-cached) when you need the full record for any individual item.\n\n#### Path\n\n| Segment | Values | Notes |\n|---|---|---|\n| `type`  | `movies`, `tv`, `anime`, `all` | Required. Use `/ratings/all` to get every type in one response. |\n\n#### Query\n\n| Param | Required | Notes |\n|---|---|---|\n| `user_watchlist` | yes | Comma-separated list of watchlist statuses to include. Any of `watching`, `plantowatch`, `hold`, `completed`, `dropped`. Use `1` (or any non-empty value) as a shorthand for \"all statuses\". Without this param the request silently falls through to a different code path and returns `200 null` — always supply it. |\n| `fields` | no | Comma-separated extra blocks to include alongside the default `simkl` block. See the *Fields values* table below. |\n\n#### Fields values\n\n| `fields` value | Adds |\n|---|---|\n| `simkl` *(default)* | `simkl: {rating, votes, droprate}` per item. |\n| `ext`               | `imdb: {rating, votes}` and/or `mal: {rating, votes, rank}` (only the providers Simkl has on file for the title). |\n| `rank`              | `rank` integer — Simkl's catalog rank for the item. |\n| `release_status`    | Human-readable release status (e.g. `Ended`, `Continuing`). |\n| `year`              | `release_year` integer. |\n| `link`              | Canonical Simkl URL for the item. |\n\nCombine multiple with commas: `fields=simkl,ext,year,rank`. Unknown values (including `reactions` and `has_trailer`, which are valid on the hidden single-item rating endpoint but **not** here) are silently ignored.\n\n#### Auth\n\nRequires `Authorization: Bearer <access_token>` plus the standard `client_id` / `app-name` / `app-version` URL params.\n\nFor the user's **own** ratings (the 1-10 scores they've assigned), use [`GET /sync/ratings/:type/:rating`](/api-reference/simkl/get-user-ratings) instead — that's the user-rated-by-them endpoint, this one is community-rating-of-everything-in-their-list.\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "name": "type",
            "in": "path",
            "description": "Media-type slice. Use `all` to fetch every type in one response — this is the canonical \"I don't care which type\" form. The path segment is required because OpenAPI 3.1 does not permit optional path parameters.",
            "schema": {
              "type": "string",
              "enum": [
                "movies",
                "tv",
                "anime",
                "all"
              ],
              "example": "all"
            },
            "required": true,
            "examples": {
              "default_all_types": {
                "summary": "Default: every type, every status",
                "value": "all"
              },
              "movies_watching_returns_null": {
                "summary": "Sentinel: movies+watching returns null (movies have no `watching` bucket)",
                "value": "movies"
              },
              "tv_plan_to_watch": {
                "summary": "TV shows the user plans to watch",
                "value": "tv"
              },
              "anime_completed": {
                "summary": "Anime the user has finished",
                "value": "anime"
              },
              "active_library_csv": {
                "summary": "Active library only (CSV: plantowatch + watching + completed)",
                "value": "all"
              },
              "with_imdb_and_mal_ratings": {
                "summary": "Add external ratings (IMDb + MAL) via `fields=ext`",
                "value": "all"
              },
              "full_metadata_bundle": {
                "summary": "Full metadata: every optional field at once",
                "value": "all"
              }
            }
          },
          {
            "name": "user_watchlist",
            "in": "query",
            "description": "",
            "required": true,
            "schema": {
              "type": "string",
              "default": "all",
              "enum": [
                "all",
                "watching",
                "plantowatch",
                "completed",
                "dropped",
                "hold"
              ],
              "example": "1"
            },
            "examples": {
              "default_all_types": {
                "summary": "Default: every type, every status",
                "value": "1"
              },
              "movies_watching_returns_null": {
                "summary": "Sentinel: movies+watching returns null (movies have no `watching` bucket)",
                "value": "watching"
              },
              "tv_plan_to_watch": {
                "summary": "TV shows the user plans to watch",
                "value": "plantowatch"
              },
              "anime_completed": {
                "summary": "Anime the user has finished",
                "value": "completed"
              },
              "active_library_csv": {
                "summary": "Active library only (CSV: plantowatch + watching + completed)",
                "value": "plantowatch,watching,completed"
              },
              "with_imdb_and_mal_ratings": {
                "summary": "Add external ratings (IMDb + MAL) via `fields=ext`",
                "value": "1"
              },
              "full_metadata_bundle": {
                "summary": "Full metadata: every optional field at once",
                "value": "1"
              }
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "- A comma-separated list of additional fields to include in the response.\n - `simkl` – returns the Simkl rating and votes.\n - `ext` – includes external ratings such as IMDB or MAL if available.\n - `rank` – returns the rank within the Simkl service for that media type (movie, tv, anime).\n - `release_status` – includes the release status of the item.\n - `year` – includes the year of release.\n - Example: `fields=rank,droprate,simkl,ext,year`",
            "schema": {
              "type": "string",
              "enum": [
                "simkl",
                "ext",
                "rank",
                "release_status",
                "year",
                "link"
              ]
            },
            "examples": {
              "default_all_types": {
                "summary": "Default: every type, every status",
                "value": "simkl"
              },
              "movies_watching_returns_null": {
                "summary": "Sentinel: movies+watching returns null (movies have no `watching` bucket)",
                "value": "simkl"
              },
              "tv_plan_to_watch": {
                "summary": "TV shows the user plans to watch",
                "value": "simkl"
              },
              "anime_completed": {
                "summary": "Anime the user has finished",
                "value": "simkl"
              },
              "active_library_csv": {
                "summary": "Active library only (CSV: plantowatch + watching + completed)",
                "value": "simkl"
              },
              "with_imdb_and_mal_ratings": {
                "summary": "Add external ratings (IMDb + MAL) via `fields=ext`",
                "value": "simkl,ext"
              },
              "full_metadata_bundle": {
                "summary": "Full metadata: every optional field at once",
                "value": "simkl,ext,year,rank,droprate,link,release_status"
              }
            }
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "number"
                      },
                      "type": {
                        "type": "string"
                      },
                      "link": {
                        "type": "string"
                      },
                      "release_status": {
                        "type": "string"
                      },
                      "release_year": {
                        "type": "number"
                      },
                      "rank": {
                        "type": "number"
                      },
                      "simkl": {
                        "type": "object",
                        "properties": {
                          "rating": {
                            "type": "number"
                          },
                          "votes": {
                            "type": "number"
                          },
                          "droprate": {
                            "type": "string"
                          }
                        }
                      },
                      "imdb": {
                        "$ref": "#/components/schemas/ExternalRating"
                      },
                      "mal": {
                        "$ref": "#/components/schemas/RankedExternalRating"
                      }
                    },
                    "required": [
                      "id",
                      "type",
                      "link",
                      "release_status",
                      "release_year",
                      "rank",
                      "simkl"
                    ]
                  }
                },
                "example": [
                  {
                    "id": 268470,
                    "type": "movie",
                    "link": "https://simkl.com/movies/268470/tinker-bell-and-the-pirate-fairy",
                    "release_status": "released",
                    "release_year": 2014,
                    "rank": 10628,
                    "simkl": {
                      "rating": 7.1,
                      "votes": 151,
                      "droprate": "1%"
                    },
                    "imdb": {
                      "rating": 6.6,
                      "votes": 15119
                    }
                  },
                  {
                    "id": 2331788,
                    "type": "anime",
                    "link": "https://simkl.com/anime/2331788/kamonohashi-ron-no-kindan-suiri-2nd-season",
                    "release_status": "ongoing",
                    "release_year": 2024,
                    "rank": 1561,
                    "simkl": {
                      "rating": 7,
                      "votes": 19,
                      "droprate": "3.9%"
                    },
                    "mal": {
                      "rating": 7.6,
                      "votes": 4132,
                      "rank": 1693
                    }
                  }
                ],
                "examples": {
                  "default_all_types": {
                    "summary": "Default: every type, every status",
                    "description": "`GET /ratings/all?user_watchlist=1`\n\nThe simplest call — `?user_watchlist=1` is shorthand for \"all five statuses\". Each item carries the default `simkl: {rating, votes, droprate}` block.",
                    "value": [
                      {
                        "id": 297,
                        "type": "tv",
                        "simkl": {
                          "rating": 7.4,
                          "votes": 717,
                          "droprate": "3%"
                        }
                      },
                      {
                        "id": 1218,
                        "type": "tv",
                        "simkl": {
                          "rating": 8.2,
                          "votes": 2207,
                          "droprate": "7.4%"
                        }
                      },
                      {
                        "id": 1698,
                        "type": "tv",
                        "simkl": {
                          "rating": 7.2,
                          "votes": 70,
                          "droprate": "5.1%"
                        }
                      }
                    ]
                  },
                  "movies_watching_returns_null": {
                    "summary": "Sentinel: movies+watching returns null (movies have no `watching` bucket)",
                    "description": "`GET /ratings/movies?user_watchlist=watching`\n\nPer [list-status rules](/conventions/list-statuses), movies skip `watching` and `hold`. Asking for them returns `200 null` (Type 3 — empty result) — this is normal, not an error. Pinned here as a known-shape sentinel so client parsers handle it cleanly.",
                    "value": null
                  },
                  "tv_plan_to_watch": {
                    "summary": "TV shows the user plans to watch",
                    "description": "`GET /ratings/tv?user_watchlist=plantowatch`\n\nThe classic \"what should I watch next\" use case — community ratings for items in the user's Plan-to-Watch list, sortable client-side by `simkl.rating` desc.",
                    "value": [
                      {
                        "id": 297,
                        "simkl": {
                          "rating": 7.4,
                          "votes": 717,
                          "droprate": "3%"
                        }
                      },
                      {
                        "id": 1218,
                        "simkl": {
                          "rating": 8.2,
                          "votes": 2207,
                          "droprate": "7.4%"
                        }
                      },
                      {
                        "id": 1698,
                        "simkl": {
                          "rating": 7.2,
                          "votes": 70,
                          "droprate": "5.1%"
                        }
                      }
                    ]
                  },
                  "anime_completed": {
                    "summary": "Anime the user has finished",
                    "description": "`GET /ratings/anime?user_watchlist=completed`\n\nPer-type, per-status filter. Useful for retrospective analysis — how the user's completed library ranks against the wider community.",
                    "value": [
                      {
                        "id": 37089,
                        "simkl": {
                          "rating": 8.6,
                          "votes": 4606,
                          "droprate": "2.1%"
                        }
                      },
                      {
                        "id": 439744,
                        "simkl": {
                          "rating": 8.6,
                          "votes": 9124,
                          "droprate": "0.4%"
                        }
                      },
                      {
                        "id": 694485,
                        "simkl": {
                          "rating": 8.7,
                          "votes": 8150,
                          "droprate": "0.4%"
                        }
                      }
                    ]
                  },
                  "active_library_csv": {
                    "summary": "Active library only (CSV: plantowatch + watching + completed)",
                    "description": "`GET /ratings/all?user_watchlist=plantowatch,watching,completed`\n\n`user_watchlist` accepts a comma-separated list of statuses. This combo is the active library — everything the user is engaging with right now, excluding `hold` and `dropped`.",
                    "value": [
                      {
                        "id": 297,
                        "type": "tv",
                        "simkl": {
                          "rating": 7.4,
                          "votes": 717,
                          "droprate": "3%"
                        }
                      },
                      {
                        "id": 1218,
                        "type": "tv",
                        "simkl": {
                          "rating": 8.2,
                          "votes": 2207,
                          "droprate": "7.4%"
                        }
                      },
                      {
                        "id": 1698,
                        "type": "tv",
                        "simkl": {
                          "rating": 7.2,
                          "votes": 70,
                          "droprate": "5.1%"
                        }
                      }
                    ]
                  },
                  "with_imdb_and_mal_ratings": {
                    "summary": "Add external ratings (IMDb + MAL) via `fields=ext`",
                    "description": "`GET /ratings/all?user_watchlist=1&fields=simkl,ext`\n\n`fields=ext` adds `imdb: {rating, votes}` and/or `mal: {rating, votes, rank}` blocks per item — only the providers Simkl has on file. Live-action titles typically carry `simkl + imdb`; modern anime carry `simkl + mal`; classic anime sometimes carry all three.",
                    "value": [
                      {
                        "id": 297,
                        "type": "tv",
                        "simkl": {
                          "rating": 7.4,
                          "votes": 717,
                          "droprate": "3%"
                        },
                        "imdb": {
                          "rating": 7.2,
                          "votes": 98744
                        }
                      },
                      {
                        "id": 1218,
                        "type": "tv",
                        "simkl": {
                          "rating": 8.2,
                          "votes": 2207,
                          "droprate": "7.4%"
                        },
                        "imdb": {
                          "rating": 8.6,
                          "votes": 468647
                        }
                      },
                      {
                        "id": 1698,
                        "type": "tv",
                        "simkl": {
                          "rating": 7.2,
                          "votes": 70,
                          "droprate": "5.1%"
                        },
                        "imdb": {
                          "rating": 6.5,
                          "votes": 18350
                        }
                      }
                    ]
                  },
                  "full_metadata_bundle": {
                    "summary": "Full metadata: every optional field at once",
                    "description": "`GET /ratings/all?user_watchlist=1&fields=simkl,ext,year,rank,droprate,link,release_status`\n\nEvery supported `fields=` value at once: `simkl`, `ext` (imdb/mal), `year` (release_year), `rank`, `droprate`, `link` (canonical Simkl URL), `release_status` (human-readable e.g. `Ended`, `Continuing`). Useful for one-shot UIs that render the full row without a follow-up detail call.",
                    "value": [
                      {
                        "id": 297,
                        "type": "tv",
                        "link": "https://simkl.com/tv/297/charmed",
                        "release_status": "ended",
                        "release_year": 1998,
                        "rank": 5508,
                        "simkl": {
                          "rating": 7.4,
                          "votes": 717,
                          "droprate": "3%"
                        },
                        "imdb": {
                          "rating": 7.2,
                          "votes": 98744
                        }
                      },
                      {
                        "id": 1218,
                        "type": "tv",
                        "link": "https://simkl.com/tv/1218/the-simpsons",
                        "release_status": "returning series",
                        "release_year": 1989,
                        "rank": 273,
                        "simkl": {
                          "rating": 8.2,
                          "votes": 2207,
                          "droprate": "7.4%"
                        },
                        "imdb": {
                          "rating": 8.6,
                          "votes": 468647
                        }
                      },
                      {
                        "id": 1698,
                        "type": "tv",
                        "link": "https://simkl.com/tv/1698/the-ellen-degeneres-show",
                        "release_status": "ended",
                        "release_year": 2003,
                        "rank": 9664,
                        "simkl": {
                          "rating": 7.2,
                          "votes": 70,
                          "droprate": "5.1%"
                        },
                        "imdb": {
                          "rating": 6.5,
                          "votes": 18350
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Ratings"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-watchlist-ratings",
          "metadata": {
            "sidebarTitle": "Watchlist ratings"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "default_all_types",
            "source": "curl 'https://api.simkl.com/ratings/all?user_watchlist=1&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'User-Agent: my-app-name/1.0'"
          },
          {
            "lang": "curl",
            "label": "movies_watching_returns_null",
            "source": "curl 'https://api.simkl.com/ratings/movies?user_watchlist=watching&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'User-Agent: my-app-name/1.0'"
          },
          {
            "lang": "curl",
            "label": "tv_plan_to_watch",
            "source": "curl 'https://api.simkl.com/ratings/tv?user_watchlist=plantowatch&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'User-Agent: my-app-name/1.0'"
          },
          {
            "lang": "curl",
            "label": "anime_completed",
            "source": "curl 'https://api.simkl.com/ratings/anime?user_watchlist=completed&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'User-Agent: my-app-name/1.0'"
          },
          {
            "lang": "curl",
            "label": "active_library_csv",
            "source": "curl 'https://api.simkl.com/ratings/all?user_watchlist=plantowatch,watching,completed&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'User-Agent: my-app-name/1.0'"
          },
          {
            "lang": "curl",
            "label": "with_imdb_and_mal_ratings",
            "source": "curl 'https://api.simkl.com/ratings/all?user_watchlist=1&fields=simkl,ext&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'User-Agent: my-app-name/1.0'"
          },
          {
            "lang": "curl",
            "label": "full_metadata_bundle",
            "source": "curl 'https://api.simkl.com/ratings/all?user_watchlist=1&fields=simkl,ext,year,rank,droprate,link,release_status&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'User-Agent: my-app-name/1.0'"
          }
        ]
      }
    },
    "/changes": {
      "get": {
        "operationId": "get-changes",
        "summary": "Recently changed catalog items",
        "description": "Returns Simkl catalog IDs whose metadata changed in the last **N** days, grouped by type. Use it to keep the items already on a user's watchlist fresh — when a show airs a new episode, an upcoming title starts airing, or a movie's metadata is updated, the corresponding ID appears here.\n\n<Tip>\n**If all you need is \"which episodes are airing soon?\"** — use the [Calendar data files](/api-reference/calendar) on `data.simkl.in` instead. They're CDN-cached and give you every upcoming episode in a single fast call:\n\n- **Rolling window** (`/calendar/{type}.json`) — yesterday + the next ~33 days. The default for \"what's on now and next\".\n- **Monthly archive** (`/calendar/{year}/{month}/{type}.json`) — fetch previous, current, and next month separately when you need a wider calendar grid view (e.g. a 3-month strip).\n\nReserve `/changes` for the wider job of tracking catalog metadata updates (status flips, ratings, posters, runtimes) on items already on the user's watchlist.\n</Tip>\n\n#### How tracking apps use it\n\nYou already know which items the user is tracking from the [Sync guide](/guides/sync) loop ([`GET /sync/activities`](/api-reference/simkl/get-activities) + [`GET /sync/all-items`](/api-reference/simkl/get-all-items) with `date_from=`). That tells you when the **user** touched their lists. `/changes` is the complementary call — it tells you when **Simkl's catalog metadata** for any item moved, independent of whether the user touched their list. New episodes that just aired, a show whose status flipped from *upcoming* to *airing*, a movie whose runtime / poster / overview was updated.\n\n#### When to actually call it\n\nTreat it like Sync: **trigger on a user-visible event, never on a background timer.** The intended cadence is **at most once per day per user**, gated on a stored timestamp:\n\n| Trigger | What to do |\n|---|---|\n| App launch / wake-from-background | If `now() − last_changes_poll ≥ 24 h`, run the loop below and save `now()` as `last_changes_poll`. If less than 24 h, skip — the 14-day response window means the same IDs will still be there tomorrow. |\n| Manual refresh button | Always allow — bypasses the 24 h gate so the user can force a check. |\n| Never | Background `setInterval` timers, per-user crons, real-time loops, polling on every screen transition. These will get the `client_id` rate-limited. |\n\n#### The loop (when the trigger fires)\n\n1. Call `/changes?date_from=<last_changes_poll>`. Narrow with `type=` to only the catalogs the user has items in (skip `anime` if the user has no anime, etc.).\n2. **Intersect in your client:** `{IDs the response returned} ∩ {IDs the user has on any watchlist}`. You already have the user's watchlist locally from the Sync loop — this is a Set lookup, ~microseconds.\n3. **Apply the skip rules below** to the intersection. Most items get dropped here — only the ones where new metadata is plausible survive.\n4. For each surviving ID, refetch the matching cached endpoint:\n\n| Refetch for | Endpoint |\n|---|---|\n| Movie metadata (poster, overview, ratings, release date) | [`GET /movies/{id}`](/api-reference/simkl/get-movie) |\n| TV show metadata + new episode counts / status | [`GET /tv/{id}`](/api-reference/simkl/get-tv-show) and/or [`GET /tv/episodes/{id}`](/api-reference/simkl/get-tv-episodes) |\n| Anime metadata + new episodes | [`GET /anime/{id}`](/api-reference/simkl/get-anime) and/or [`GET /anime/episodes/{id}`](/api-reference/simkl/get-anime-episodes) |\n\nThe detail endpoints are edge-cached by Simkl ID, so popular titles come straight from Cloudflare without hitting origin. **When an item's metadata or episodes change, Simkl automatically purges its Cloudflare cache entry** — so a refetch right after `/changes` flagged the ID is guaranteed to return the fresh data, never a stale edge copy. After the refetch, save `now()` as `last_changes_poll`.\n\n#### Skip rules — when not to refetch\n\n**First, restrict the intersect to active lists.** Items on the user's `completed` and `dropped` lists are titles they're done with — there's no UX win in refreshing metadata for a show they're never opening again. Intersect `/changes` only against items on `watching`, `plantowatch`, and `hold` (plus their anime equivalents); drop the rest before you even consider a refetch.\n\nAfter that filter, the remaining items still benefit from status-based throttling. Cache the last-known `status` (TV/anime) or release state (movies) for each item in the user's watchlist, and track the last time you refetched each item. Use the rules below — most items will sit in a state where new metadata is implausible.\n\n| Last-known state | When to actually refetch |\n|---|---|\n| TV / anime, `status: airing` | Every time the ID appears in `/changes` — new episodes can drop any week. |\n| TV / anime, `status: tba` (upcoming) | Weekly — what matters is the moment the status flips to `airing` and the first real air date locks in. |\n| TV / anime, `status: ended`, ended **less than 30 days ago** | Every time the ID appears — late corrections to ratings / episode counts happen here. |\n| TV / anime, `status: ended`, ended **more than 30 days ago** | Skip. Refetch once a month at most. Metadata on a finished show is effectively frozen. |\n| Movie, released **less than 6 months ago** | Every time the ID appears — ratings / poster art / overview tend to churn early. |\n| Movie, released **more than 6 months ago** | Skip. Refetch quarterly at most. |\n| Movie, unreleased / `tba` | Weekly — you mostly care about the release-date update. |\n\nThe intersect + skip combination typically reduces a `/changes` response of tens of thousands of IDs down to a handful of detail-endpoint refetches per day per user — even for power users with very large libraries.\n\n#### Query parameters\n\n| Param | Default | Notes |\n|---|---|---|\n| `date_from` | 14 days ago | ISO date (e.g. `YYYY-MM-DD`). The server **clamps** to no older than 14 days ago — older values silently snap to the cap. Invalid values (e.g. `BOGUS`) silently fall back to the default. Future dates return `{}`. |\n| `type` | `anime,shows,movies` | CSV. Any combination of `anime`, `shows`, `movies`. Unknown values silently bucket as anime — keep the values in the listed set. Use it to skip catalogs the user doesn't have anything on. |\n\n#### Response shape\n\nAn object with up to three keys (`movies`, `shows`, `anime`), each an array of integer Simkl IDs. **Keys are omitted when their bucket is empty.** If nothing changed in the window, the response is `{}` (an empty object, NOT `[]`).\n\n```json\n{\n  \"movies\": [\n    56145,\n    1029384\n  ],\n  \"shows\": [\n    17465,\n    92834\n  ],\n  \"anime\": [\n    39687\n  ]\n}\n```\n\nIDs are returned in no particular order. Items modified in the **last 5 minutes are excluded** so partially-written records don't leak into the delta. **Each response contains at most 50,000 IDs** — if the catalog produces more (rare; only on very wide windows across all three types), narrow the call with `type=` to fit under the cap.\n",
        "parameters": [
          {
            "name": "date_from",
            "in": "query",
            "description": "ISO date (`YYYY-MM-DD`). Items modified at or after this timestamp are returned. **Server caps at 14 days ago** — older values silently snap to the cap. Invalid values (e.g. `BOGUS`) silently fall back to the default. Future dates return `{}`. Defaults to 14 days ago when omitted.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-05-11"
          },
          {
            "name": "type",
            "in": "query",
            "description": "CSV of types to include. Any combination of `anime`, `shows`, `movies`. Unknown values silently bucket as anime — keep the values in the listed set.",
            "schema": {
              "type": "string",
              "default": "anime,shows,movies"
            },
            "example": "shows,movies"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChangesResponse"
                },
                "examples": {
                  "since_last_sync_24h": {
                    "summary": "Daily poll — `date_from` set to the previous successful sync (~24 h ago)",
                    "value": {
                      "shows": [
                        2,
                        40,
                        500,
                        "... ~825 more"
                      ],
                      "anime": [
                        44822,
                        2017210,
                        2254562,
                        "... ~20 more"
                      ],
                      "movies": [
                        53078,
                        53080,
                        53082,
                        "... ~8,200 more"
                      ]
                    }
                  },
                  "type_movies_only": {
                    "summary": "type=movies — single-bucket filter (skip catalogs the user has nothing on)",
                    "value": {
                      "movies": [
                        53078,
                        53080,
                        53082,
                        "... ~8,200 more"
                      ]
                    }
                  },
                  "type_csv_two_buckets": {
                    "summary": "type=shows,movies — CSV, excludes anime",
                    "value": {
                      "shows": [
                        2,
                        40,
                        500,
                        "... ~825 more"
                      ],
                      "movies": [
                        53078,
                        53080,
                        53082,
                        "... ~8,200 more"
                      ]
                    }
                  },
                  "default_all_types_14_days": {
                    "summary": "No filters — full 14-day delta across all 3 buckets (use only for first-time backfill, not for routine polls)",
                    "value": {
                      "shows": [
                        1,
                        2,
                        40,
                        43,
                        "... ~5,200 more"
                      ],
                      "movies": [
                        2152693,
                        1875405,
                        2559003,
                        "... ~42,000 more"
                      ],
                      "anime": [
                        41314,
                        36602,
                        38636,
                        "... ~115 more"
                      ]
                    }
                  },
                  "unknown_type_buckets_as_anime": {
                    "summary": "Silent-fallback sentinel — type=foo buckets as anime",
                    "value": {
                      "anime": [
                        41314,
                        36602,
                        38636,
                        "... ~115 more"
                      ]
                    }
                  },
                  "future_date_returns_empty_object": {
                    "summary": "Future date_from — empty `{}` (NOT `[]`)",
                    "value": {}
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Changes"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-changes",
          "metadata": {
            "sidebarTitle": "Recent changes"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "since_last_sync_24h",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/changes?date_from=2026-05-17&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "type_movies_only",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/changes?date_from=2026-05-17&type=movies&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "type_csv_two_buckets",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/changes?date_from=2026-05-17&type=shows,movies&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "default_all_types_14_days",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/changes?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "unknown_type_buckets_as_anime",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/changes?type=foo&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "future_date_returns_empty_object",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/changes?date_from=2030-01-01&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/redirect": {
      "get": {
        "operationId": "redirect",
        "summary": "Resolve any ID and redirect to Simkl",
        "description": "A passive helper endpoint that **`301`-redirects** to a Simkl page (or an action) given any combination of IDs or a title.\n\nIt's designed for two situations:\n\n1. **Linking to Simkl when you don't have the Simkl ID** — turn an IMDB / TMDB / TVDB / MAL / AniDB ID, or a title + year, into a clickable Simkl URL.\n2. **Getting the Simkl ID with minimal info** — the cheapest way to translate an external ID into a Simkl ID. **Read the `Location` response header** and parse the `simkl_id` out of the URL path — no JSON to parse.\n\n> ⚠️ **Do not follow the 301.** Read the `Location` header directly. Use `curl -I`, `requests.get(..., allow_redirects=False)`, `fetch(..., { redirect: 'manual' })`, or your client's equivalent. The destination is a public-facing page (simkl.com HTML, YouTube, Twitter intent, or `/oauth/authorize`) and contains no API data — following the redirect wastes bandwidth and can break (CORS, auth, destination-host rate limits). This applies to **HTTP clients, scripts, automated tools, AI agents, and LLM-driven workflows alike**.\n>\n> **What to do next, after reading the `Location` header:**\n> - **If you only need the Simkl ID** — parse it out of the URL path (e.g. `https://simkl.com/tv/17465/...` → `17465`) and **stop**. Don't call anything else.\n> - **If you also need the full record** (title, overview, poster, fanart, ratings, trailers, etc.) — pass the parsed Simkl ID to the matching Cloudflare-cached detail endpoint: [`GET /movies/{id}`](/api-reference/simkl/get-movie), [`GET /tv/{id}`](/api-reference/simkl/get-tv-show), [`GET /anime/{id}`](/api-reference/simkl/get-anime), [`GET /tv/episodes/{id}`](/api-reference/simkl/get-tv-episodes), or [`GET /anime/episodes/{id}`](/api-reference/simkl/get-anime-episodes). Popular titles come straight from edge cache.\n>\n> Full reference table of stop-at-301 invocations for popular HTTP clients in the [Redirect overview](/api-reference/redirect#use-case-2).\n\nLike every Simkl endpoint, requests must include the [required URL parameters](/conventions/headers#required-url-parameters) (`client_id`, `app-name`, `app-version`) and a `User-Agent` header. No `Authorization` token is needed except for `to=watched`, which signs the user in if they aren't already.\n\n#### `to=` action modes\n\n| Mode | What the redirect points at |\n|---|---|\n| `simkl` *(default)* | The matching Simkl page (`https://simkl.com/movies/{id}/{slug}`, `tv/...`, `anime/...`). |\n| `trailer` | The trailer URL (typically YouTube). |\n| `twitter` | A `twitter.com/intent/tweet` URL with the title and a Simkl link prefilled. |\n| `watched` | Marks the item watched on the user's account. If the user isn't signed in, Simkl redirects to `/oauth/authorize` first. |\n\n#### Identifier parameters\n\nPass any combination — the more, the more accurate the match. Most can stand alone:\n\n| Param | Notes |\n|---|---|\n| `simkl` | Simkl ID. |\n| `imdb` | IMDB ID, or a full IMDB URL. |\n| `tmdb` | TMDB ID. **Requires `type=movie` or `type=tv`** to disambiguate — TMDB has no anime type (anime shows are filed under `tv` on TMDB; Simkl routes them to its anime catalog automatically once resolved). |\n| `tvdb` | TVDB ID. |\n| `mal`, `anidb`, `anilist`, `kitsu`, `livechart`, `anisearch`, `animeplanet` | Anime-specific IDs. |\n| `crunchyroll` | Crunchyroll show or episode ID/slug. |\n| `netflix`, `hulu` | Streaming-service IDs (beta). |\n| `title`, `year` | Title-based fallback. Pair with `type` for best results. |\n| `season`, `episode` | Episode targeting (`season` defaults to `1`). Movies are ignored when either is set. |\n| `ep_title` | Episode title used in the tweet text when `to=twitter`. |\n| `type` | `movie`, `tv`, or `anime`. Required for `tmdb`; optional otherwise (`show` matches both `tv` and `anime`). |\n\n#### Response\n\n- Status: **`301 Moved Permanently`**\n- `Location`: the resolved URL (Simkl page, YouTube, Twitter intent, or the OAuth authorize page when `to=watched` and the user isn't signed in).\n- `Cache-Control: no-store` — never cache the redirect itself; cache the resolved URL on your side if you need to.\n\n#### Why \"lowest cost\" for ID resolution\n\n`GET /redirect?to=simkl&imdb=…` returns a `Location` header like `https://simkl.com/movies/472214/inception`. The number after `/movies/`, `/tv/`, or `/anime/` is the Simkl ID. Compared to `GET /search/id`:\n\n- **No JSON parse** — read the `Location` header, regex out the ID.\n- **Tiny payload** — HTTP headers only, no response body.\n\nUse this for \"I have an IMDB ID, give me the Simkl ID\" lookups when you don't need the rest of the media object yet.\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "name": "to",
            "in": "query",
            "description": "Action mode. Determines the redirect target. Case-sensitive; must be lowercase. Allowed values: `simkl` (search fallback), `trailer`, `twitter`, `watched`.",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "simkl",
                "trailer",
                "twitter",
                "watched"
              ]
            }
          },
          {
            "name": "title",
            "in": "query",
            "description": "TV show, anime, or movie title.",
            "schema": {
              "type": "string"
            },
            "example": "The Walking Dead"
          },
          {
            "name": "year",
            "in": "query",
            "description": "release year.",
            "schema": {
              "type": "integer"
            },
            "example": "2010"
          },
          {
            "name": "season",
            "in": "query",
            "description": "if set, movies will be ignored. Anime do not have seasons.",
            "schema": {
              "type": "integer",
              "default": 1
            },
            "example": "1"
          },
          {
            "name": "episode",
            "in": "query",
            "description": "if set, movies will be ignored.",
            "schema": {
              "type": "integer"
            },
            "example": "4"
          },
          {
            "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": "integer"
            },
            "example": "153021, the-walking-dead"
          },
          {
            "name": "type",
            "in": "query",
            "description": "Required for tmdb, if is searching for a TV Show",
            "schema": {
              "type": "string",
              "enum": [
                "show",
                "tv",
                "movie",
                "anime"
              ]
            },
            "example": "show"
          },
          {
            "name": "tmdb",
            "in": "query",
            "description": "The Movie Database (TMDb) ID. To search TV Shows specify `type` parameter. All other parameters can be empty if this one specified.",
            "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",
              "enum": [
                "tt1520211",
                "http://www.imdb.com/title/tt1520211/"
              ]
            },
            "example": "tt1520211"
          },
          {
            "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": "integer"
            },
            "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": "ep_title",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Episode title used to compose tweet text when `to=twitter`. Ignored for other `to=` values."
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "301": {
            "description": "Permanent redirect to the resolved URL (the primary success path).",
            "headers": {
              "Location": {
                "description": "Target URL chosen by the server based on the `to` mode and inputs. Browsers (and most HTTP clients) follow this automatically.",
                "schema": {
                  "type": "string",
                  "format": "uri",
                  "example": "https://simkl.com/movies/53536/terminator-3-rise-of-the-machines"
                }
              },
              "Cache-Control": {
                "description": "Always `no-store` — the redirect resolves dynamically per-request and must not be cached by browsers or CDNs.",
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              }
            }
          },
          "302": {
            "description": "User will be redirected to the episode page plus ?mark=watched&client_id=***.\n\nIn this example user will be redirected to [Simkl: The Walking Dead S01E4](https://simkl.com/tv/2090/the-walking-dead/season-1/episode-4/?mark=watched&client_id=***)",
            "headers": {
              "Location": {
                "description": "Target URL chosen by the server based on the `to` mode and inputs. Browsers (and most HTTP clients) follow this automatically.",
                "schema": {
                  "type": "string",
                  "format": "uri",
                  "example": "https://simkl.com/movies/53536/terminator-3-rise-of-the-machines"
                }
              },
              "Cache-Control": {
                "description": "Always `no-store` — the redirect resolves dynamically per-request and must not be cached by browsers or CDNs.",
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              }
            },
            "content": {}
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          }
        },
        "tags": [
          "Redirect"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/redirect",
          "metadata": {
            "sidebarTitle": "Redirect"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/scrobble/checkin": {
      "post": {
        "operationId": "post-scrobble-checkin",
        "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.\n\n> **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.\n\nThe user can browse and clean up active check-ins at the [Playback progress manager](https://simkl.com/my/history/playback-progress-manager/).\n\n#### When to use checkin vs the start / pause / stop loop\n\n| Situation | Use |\n|---|---|\n| 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 |\n| You can't reliably hook into pause / stop (some embedded players, casting flows, hardware AV-out, social \"I'm watching this\" buttons) | `checkin` |\n| You just want to record a watch after the fact, no live status | [`POST /sync/history`](/api-reference/simkl/add-to-history) |\n\n#### Seek and scrub behavior\n\nNo 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.\n\n> **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.\n\n<Card title=\"Scrobble guide — full walkthrough\" icon=\"play\" href=\"/guides/scrobble\" horizontal>\n 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).\n</Card>\n\nAlternative 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.\n\n<Tip>\n**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).\n</Tip>",
        "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.0,
                    "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.0,
                    "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.0,
                    "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.0,
                      "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.0,
                      "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"
                      }
                    }
                  },
                  "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"
                      }
                    }
                  },
                  "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"
                      }
                    }
                  },
                  "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.0,
                      "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"
                      }
                    }
                  },
                  "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"
          }
        },
        "tags": [
          "Scrobble"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/scrobble-checkin",
          "metadata": {
            "sidebarTitle": "Check-in"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/scrobble/pause": {
      "post": {
        "operationId": "post-scrobble-pause",
        "summary": "Pause",
        "description": "Saves the current `progress` as a **resumable playback** that any signed-in device can fetch via [`GET /sync/playback/{type}`](/api-reference/simkl/get-playback-sessions) and resume with [`/scrobble/start`](/api-reference/simkl/scrobble-start). This is how Simkl powers cross-device \"Continue Watching.\" Does **not** mark the item watched. See the [Playback overview](/api-reference/playback) for retention rules and the user-facing manager.\n\nThe body shape is identical to [`/scrobble/start`](/api-reference/simkl/scrobble-start).\n\n#### Seek and scrub behavior\n\nThe `progress` you send is whatever the playhead is at the moment of pause — it doesn't have to be larger than the prior `start`'s progress. A user who scrubs backward and pauses sends a smaller `progress`; that's correct and the server stores it. Don't call this endpoint on seek events themselves.\n\n> **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.\n\n<Card title=\"Scrobble guide — full walkthrough\" icon=\"play\" href=\"/guides/scrobble\" horizontal>\n 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).\n</Card>\n\nAlternative to `episode.season` + `episode.number`: pass `episode.ids` with `tvdb` or `anidb` to identify the exact episode by external episode ID. Useful for Plex / 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.\n\n<Tip>\n**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).\n</Tip>",
        "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": {
                "scrobble_pause_movie": {
                  "summary": "Pause an in-progress movie scrobble at 50%",
                  "description": "Player paused; record the current position. Same body shape as /start. Use this on every UI pause event so /sync/playback can report a usable resume position.",
                  "value": {
                    "movie": {
                      "ids": {
                        "simkl": 472214
                      }
                    },
                    "progress": 50
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScrobbleResponse"
                },
                "examples": {
                  "scrobble_pause_movie": {
                    "summary": "Pause an in-progress movie scrobble at 50%",
                    "description": "Player paused; record the current position. Same body shape as /start. Use this on every UI pause event so /sync/playback can report a usable resume position.",
                    "value": {
                      "id": 10916886,
                      "action": "pause",
                      "progress": 50,
                      "movie": {
                        "title": "Inception",
                        "year": 2010,
                        "ids": {
                          "simkl": 472214,
                          "slug": "inception",
                          "imdb": "tt1375666",
                          "letterboxd": "inception",
                          "traktslug": "inception-2010",
                          "tmdb": "27205",
                          "tvdbslug": "inception",
                          "tvdb": "113"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "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"
          }
        },
        "tags": [
          "Scrobble"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/scrobble-pause",
          "metadata": {
            "sidebarTitle": "Pause"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/scrobble/start": {
      "post": {
        "operationId": "post-scrobble-start",
        "summary": "Start",
        "description": "Creates or replaces the user's active \"watching now\" session for the given item. Call this when playback begins, or to resume a previously paused session.\n\n#### Body shape\n\nSend `progress` plus exactly one of `movie`, `show`+`episode`, or `anime`+`episode`. See [Standard media objects](/conventions/standard-media-objects).\n\n| Field | Type | Notes |\n|---|---|---|\n| `progress` | float | 0–100, max 2 decimals. Response normalizes to `75` not `75.00`. |\n| `movie` / `show` / `anime` | object | Title + year + ids. `simkl` ID alone is enough. |\n| `episode` | object | `season` + `number`, or `ids`. Required for shows/anime. |\n\n#### Behavior\n\n- Replaces any existing session for this item and clears prior pauses.\n- Auto-expires after the calculated remaining runtime.\n- If a previous start/checkin reached **≥ 80 %** before this call, it is **auto-scrobbled** (marked watched) before the new session starts.\n- Response shape: `id`, `action`, `progress`, plus the media object with `ids` (incl. external links Simkl knows about) and an `episode` block. For anime, the response includes both AniDB-canonical `season`/`number` and original `tvdb_season`/`tvdb_number`.\n\n#### Seek and scrub behavior\n\nDon't call `/scrobble/start` on a seek event. Only call it when playback actually begins or resumes (typically the player's `play` event). When a user scrubs to a different position before pressing play, just update your local progress; the eventual `play` event fires the call with the new value.\n\n#### Errors\n\n| Code | When |\n|---|---|\n| `400empty_field` | No `movie`, `show`, or `anime` in the body. |\n| `400RATE_LIMIT` | A 20-second per-user lock collision — another scrobble write for this user landed within the window. Note: HTTP `400`, **not** `429` — the lock failure is treated as a malformed request from a duplicate-fire client. |\n| `401user_token_failed` | Missing / invalid bearer token. |\n| `404id_err` | Item could not be matched. |\n\n<Card title=\"Scrobble guide — full walkthrough\" icon=\"play\" href=\"/guides/scrobble\" horizontal>\n 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).\n</Card>\n\nAlternative to `episode.season` + `episode.number`: pass `episode.ids` with `tvdb` or `anidb` to identify the exact episode by external episode ID. Useful for Plex / 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.\n\n<Tip>\n**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).\n</Tip>",
        "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": {
                "negative_scrobble_empty_body": {
                  "summary": "REJECTED: empty body returns 400 empty_field",
                  "description": "Unlike `POST /sync/history` (which accepts `{}` and returns 201 with zero counts), the scrobble endpoints REQUIRE a media_type + ids in the body. Empty body returns the standard 400 envelope with `error: \"empty_field\"`.",
                  "value": {}
                },
                "negative_scrobble_unknown_id": {
                  "summary": "REJECTED: unknown Simkl ID returns 404 id_err",
                  "description": "Scrobble endpoints validate the `ids.simkl` against the catalog before recording the event. Unlike detail endpoints (which return `200 []` for unknown IDs — Type 3 null), the scrobble endpoints 404 with `error: \"id_err\"`.",
                  "value": {
                    "movie": {
                      "ids": {
                        "simkl": 999999999
                      }
                    },
                    "progress": 25
                  }
                },
                "scrobble_start_anime_episode": {
                  "summary": "Begin scrobbling an anime episode (episode 1)",
                  "description": "Anime scrobble bodies use `anime:` (not `show:`) at the outer level — different from /sync/all-items where anime entries wrap in `show:` for cross-catalog compat. The `episode.season` is `1` for AniDB-numbered anime; multi-season anime use explicit seasons here.",
                  "value": {
                    "anime": {
                      "ids": {
                        "simkl": 831411,
                        "mal": "38000",
                        "anidb": "14116",
                        "anilist": "101922"
                      }
                    },
                    "episode": {
                      "season": 1,
                      "number": 1
                    },
                    "progress": 25
                  }
                },
                "scrobble_start_movie": {
                  "summary": "Begin scrobbling a movie at 10% progress",
                  "description": "Tells Simkl that playback has started. The user appears as 'currently watching' on their profile. Update via /pause or finalize via /stop. `progress` is a 0-100 integer.",
                  "value": {
                    "movie": {
                      "ids": {
                        "simkl": 472214
                      }
                    },
                    "progress": 10
                  }
                },
                "scrobble_start_show_episode": {
                  "summary": "Begin scrobbling a TV episode (S01E01)",
                  "description": "TV scrobbles need both `show.ids` AND `episode.season` + `episode.number`. The episode is the unit of playback for scrobble; the show ID resolves the parent record. Anime use the same shape — see the next example.",
                  "value": {
                    "show": {
                      "ids": {
                        "simkl": 2090
                      }
                    },
                    "episode": {
                      "season": 1,
                      "number": 1
                    },
                    "progress": 25
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScrobbleResponse"
                },
                "examples": {
                  "scrobble_start_anime_episode": {
                    "summary": "Begin scrobbling an anime episode (episode 1)",
                    "description": "Anime scrobble bodies use `anime:` (not `show:`) at the outer level — different from /sync/all-items where anime entries wrap in `show:` for cross-catalog compat. The `episode.season` is `1` for AniDB-numbered anime; multi-season anime use explicit seasons here.",
                    "value": {
                      "id": 0,
                      "action": "start",
                      "progress": 25,
                      "episode": {
                        "season": 1,
                        "number": 1,
                        "title": "Cruelty",
                        "tvdb_season": 1,
                        "tvdb_number": 1
                      },
                      "anime": {
                        "title": "Kimetsu no Yaiba",
                        "year": 2019,
                        "anime_type": "tv",
                        "ids": {
                          "simkl": 831411,
                          "slug": "kimetsu-no-yaiba",
                          "imdb": "tt9335498",
                          "mal": "38000",
                          "tvdbslug": "demon-slayer-kimetsu-no-yaiba",
                          "anilist": "101922",
                          "kitsu": "41370",
                          "traktslug": "demon-slayer-kimetsu-no-yaiba",
                          "anidb": "14107",
                          "tvdb": "348545",
                          "tmdb": "85937"
                        }
                      }
                    }
                  },
                  "scrobble_start_movie": {
                    "summary": "Begin scrobbling a movie at 10% progress",
                    "description": "Tells Simkl that playback has started. The user appears as 'currently watching' on their profile. Update via /pause or finalize via /stop. `progress` is a 0-100 integer.",
                    "value": {
                      "id": 0,
                      "action": "start",
                      "progress": 10,
                      "movie": {
                        "title": "Inception",
                        "year": 2010,
                        "ids": {
                          "simkl": 472214,
                          "slug": "inception",
                          "imdb": "tt1375666",
                          "letterboxd": "inception",
                          "traktslug": "inception-2010",
                          "tmdb": "27205",
                          "tvdbslug": "inception",
                          "tvdb": "113"
                        }
                      }
                    }
                  },
                  "scrobble_start_show_episode": {
                    "summary": "Begin scrobbling a TV episode (S01E01)",
                    "description": "TV scrobbles need both `show.ids` AND `episode.season` + `episode.number`. The episode is the unit of playback for scrobble; the show ID resolves the parent record. Anime use the same shape — see the next example.",
                    "value": {
                      "id": 0,
                      "action": "start",
                      "progress": 25,
                      "episode": {
                        "season": 1,
                        "number": 1,
                        "title": "Days Gone Bye"
                      },
                      "show": {
                        "title": "The Walking Dead",
                        "year": 2010,
                        "ids": {
                          "simkl": 2090,
                          "slug": "the-walking-dead",
                          "imdb": "tt1520211",
                          "tvdbslug": "the-walking-dead",
                          "traktslug": "the-walking-dead",
                          "tvdb": "153021",
                          "tmdb": "1402"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest",
            "content": {
              "application/json": {
                "examples": {
                  "negative_scrobble_empty_body": {
                    "summary": "REJECTED: empty body returns 400 empty_field",
                    "description": "Unlike `POST /sync/history` (which accepts `{}` and returns 201 with zero counts), the scrobble endpoints REQUIRE a media_type + ids in the body. Empty body returns the standard 400 envelope with `error: \"empty_field\"`.",
                    "value": {
                      "error": "empty_field",
                      "code": 400
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound",
            "content": {
              "application/json": {
                "examples": {
                  "negative_scrobble_unknown_id": {
                    "summary": "REJECTED: unknown Simkl ID returns 404 id_err",
                    "description": "Scrobble endpoints validate the `ids.simkl` against the catalog before recording the event. Unlike detail endpoints (which return `200 []` for unknown IDs — Type 3 null), the scrobble endpoints 404 with `error: \"id_err\"`.",
                    "value": {
                      "error": "id_err",
                      "code": 404
                    }
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Scrobble"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/scrobble-start",
          "metadata": {
            "sidebarTitle": "Start"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/scrobble/stop": {
      "post": {
        "operationId": "post-scrobble-stop",
        "summary": "Stop",
        "description": "Finalizes the user's playback session. The `action` field in the response tells you what Simkl did:\n\n| `progress` | `action` | Result |\n|---|---|---|\n| **≥ 80** | `scrobble` | Item is marked watched. |\n| **< 80** | `pause` | Session is saved as a paused playback. |\n\nWhen `progress < 80`, the session is kept as a **resumable playback**, retrievable cross-device via [`GET /sync/playback/{type}`](/api-reference/simkl/get-playback-sessions). When `progress ≥ 80`, the item is marked watched and no playback is saved. See the [Playback overview](/api-reference/playback) for retention.\n\nBody shape is identical to [`/scrobble/start`](/api-reference/simkl/scrobble-start).\n\n#### Duplicate prevention\n\nStopping a session that's already been finalized within the past hour returns **`409 Conflict`** with `watched_at` and `expires_at` so you know when the prior scrobble expires:\n\n```json\n{\n  \"watched_at\": \"2024-05-01T18:00:00-05:00\",\n  \"expires_at\": \"2024-05-01T19:00:00-05:00\"\n}\n```\n\n#### Seek and scrub behavior\n\nThe ≥80% auto-scrobble rule applies to the `progress` you send with this call — not to anywhere the user temporarily scrubbed during playback. A user who scrubbed to 95% mid-watch but then rewinds and stops at 30% sends `progress: 30`, and the server stores `action: \"pause\"`. Only the value at the moment of `stop` matters.\n\n> **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.\n\n<Card title=\"Scrobble guide — full walkthrough\" icon=\"play\" href=\"/guides/scrobble\" horizontal>\n 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).\n</Card>\n\nAlternative to `episode.season` + `episode.number`: pass `episode.ids` with `tvdb` or `anidb` to identify the exact episode by external episode ID. Useful for Plex / 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.\n\n<Tip>\n**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).\n</Tip>",
        "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": {
                "scrobble_stop_409_repeat": {
                  "summary": "409 Conflict — re-scrobble within rate-limit window",
                  "description": "When the same item is scrobbled-as-watched within the rate-limit window (~1 hour observed live), repeat stops return `409` with `{watched_at, expires_at}` instead of another history entry. `watched_at` is when the original watch was logged; `expires_at` is when you can re-scrobble. Surface this in client UX as 'already watched a minute ago' rather than treating it as an error.",
                  "value": {
                    "movie": {
                      "ids": {
                        "simkl": 752138
                      }
                    },
                    "progress": 95
                  }
                },
                "scrobble_stop_movie_pause_threshold": {
                  "summary": "Stop with low progress (< 80%) — treated as pause, no history",
                  "description": "When `progress < 80`, /scrobble/stop is treated as a pause: the user's current playback position is recorded but the watch event is NOT added to history. Use this for accurate resume tracking when a user partially watches and then leaves. May return 409 if the same item was scrobbled too recently — see the 409 example for the rate-limit response shape.",
                  "value": {
                    "movie": {
                      "ids": {
                        "simkl": 53992
                      }
                    },
                    "progress": 30
                  }
                },
                "scrobble_stop_movie_watched": {
                  "summary": "Finalize a movie scrobble at 95% (counts as watched)",
                  "description": "/stop with `progress >= 80` writes a watch event to the user's history. With `progress < 80`, the same call is treated as a pause (no history entry). The threshold is server-side, not a request param.",
                  "value": {
                    "movie": {
                      "ids": {
                        "simkl": 472214
                      }
                    },
                    "progress": 95
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScrobbleResponse"
                },
                "examples": {
                  "scrobble_stop_movie_pause_threshold": {
                    "summary": "Stop with low progress (< 80%) — treated as pause, no history",
                    "description": "When `progress < 80`, /scrobble/stop is treated as a pause: the user's current playback position is recorded but the watch event is NOT added to history. Use this for accurate resume tracking when a user partially watches and then leaves. May return 409 if the same item was scrobbled too recently — see the 409 example for the rate-limit response shape.",
                    "value": {
                      "id": 10916890,
                      "action": "pause",
                      "progress": 30,
                      "movie": {
                        "title": "The Matrix",
                        "year": 1999,
                        "ids": {
                          "simkl": 53992,
                          "slug": "the-matrix",
                          "imdb": "tt0133093",
                          "letterboxd": "the-matrix",
                          "traktslug": "the-matrix-1999",
                          "tmdb": "603",
                          "tvdbslug": "the-matrix",
                          "tvdb": "169"
                        }
                      }
                    }
                  },
                  "scrobble_stop_movie_watched": {
                    "summary": "Finalize a movie scrobble at 95% (counts as watched)",
                    "description": "/stop with `progress >= 80` writes a watch event to the user's history. With `progress < 80`, the same call is treated as a pause (no history entry). The threshold is server-side, not a request param.",
                    "value": {
                      "id": 10916758,
                      "action": "scrobble",
                      "progress": 95,
                      "movie": {
                        "title": "Inception",
                        "year": 2010,
                        "ids": {
                          "simkl": 472214,
                          "slug": "inception",
                          "imdb": "tt1375666",
                          "letterboxd": "inception",
                          "traktslug": "inception-2010",
                          "tmdb": "27205",
                          "tvdbslug": "inception",
                          "tvdb": "113"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "if you are trying to stop an already completed scrobble session within an hour.",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "watched_at": {
                      "type": "string"
                    },
                    "expires_at": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "scrobble_stop_409_repeat": {
                    "summary": "409 Conflict — re-scrobble within rate-limit window",
                    "description": "When the same item is scrobbled-as-watched within the rate-limit window (~1 hour observed live), repeat stops return `409` with `{watched_at, expires_at}` instead of another history entry. `watched_at` is when the original watch was logged; `expires_at` is when you can re-scrobble. Surface this in client UX as 'already watched a minute ago' rather than treating it as an error.",
                    "value": {
                      "watched_at": "2026-05-14T23:46:29Z",
                      "expires_at": "2026-05-15T00:46:29Z"
                    }
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Scrobble"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/scrobble-stop",
          "metadata": {
            "sidebarTitle": "Stop"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/search/file": {
      "post": {
        "operationId": "post-search-file",
        "summary": "Find an item by file name",
        "description": "Identify a single video file the user just opened. Pass one filename and Simkl returns the matched movie, or the show + the specific episode the filename names. Built for desktop scrobblers and player overlays that need to recognize what the user is currently watching — apps that don't already have parsed metadata from a media server.\n\n<Warning>\n**Not for library scraping.** Calling `/search/file` for every file in a user's library is against the rate limits and will get the integration throttled. If you already have a media server (Plex, Kodi, Jellyfin, Emby, …) it already has parsed metadata for every file — use that. This endpoint is for ad-hoc, one-file-at-a-time identification.\n</Warning>\n\nThe server normalizes the filename (release tags, resolution, codec markers, group names) and matches it against the Simkl catalog — so messy real-world filenames like `Stranger.Things.S01E03.1080p.WEB.x264-GROUP.mkv` work fine.\n\n#### Body fields\n\n| Field | Required | Notes |\n|---|---|---|\n| `file` | yes | The file name or `/path/to/folder/file.mkv`. The alias `File` (capital F) is also accepted for legacy clients. |\n| `part` | no | 1-based part index for multi-part files (`S01E01E02.mkv` is two episodes — pass `part: 2` for the second). Default `1`. |\n| `process` | no | Optional pre-processing hint forwarded to the parser. Most clients can omit. |\n| `hash` | no | Optional file hash for additional disambiguation. |\n\n#### Response shape — discriminated by `type`\n\nThe top-level `type` field tells you which variant you got:\n\n| `type` | When | Top-level blocks present |\n|---|---|---|\n| `\"movie\"` | Filename matched a movie | `movie` |\n| `\"show\"` | Filename matched a TV/anime show but no specific episode | `show` |\n| `\"episode\"` | Filename matched a TV/anime episode | `show` + `episode` |\n\nMovies and shows carry an `ids` block populated by Simkl's link database — typically `simkl` + several external IDs (`imdb`, `tmdb`/`tmdbtv`, `tvdb`, anime sources like `mal` / `anidb` / `anilist` / `kitsu` / `crunchyroll`, plus slugs for Letterboxd / Trakt / TVDB). Anime episodes return as `type: \"episode\"` with the standard show+episode blocks — the file parser doesn't distinguish anime from TV at the top level.\n\n#### Edge responses (status 200)\n\n| Body | Meaning |\n|---|---|\n| `null` | Empty or malformed request body — no `file` field present. |\n| `[]` | Parser ran but couldn't match the filename to anything in the database. |\n\nBoth are 200 — there's no 404 or 400 for these cases. Treat both as \"no match\" in client code.\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "tv_episode_stranger_things": {
                  "summary": "TV episode match — Stranger Things S01E03",
                  "value": {
                    "file": "Stranger.Things.S01E03.1080p.WEB.x264.mkv"
                  }
                },
                "movie_inception": {
                  "summary": "Movie match — Inception 2010",
                  "value": {
                    "file": "Inception.2010.1080p.BluRay.x264.mkv"
                  }
                },
                "movie_path_form": {
                  "summary": "Path form — /Movies/.../file.mkv",
                  "value": {
                    "file": "/Movies/The Matrix (1999)/The.Matrix.1999.BluRay.mkv"
                  }
                },
                "anime_episode_demon_slayer": {
                  "summary": "Anime episode — folds under type:\"episode\" (show.ids carries mal, anidb, anilist, etc.)",
                  "value": {
                    "file": "Kimetsu.no.Yaiba.E01.1080p.mkv"
                  }
                },
                "multipart_second_episode": {
                  "summary": "Multipart filename — part=2 selects the second episode",
                  "value": {
                    "file": "Were.The.Fugawis.S01E01E02.WS.DSR.x264-NY2.mkv",
                    "part": 2
                  }
                },
                "legacy_capital_File_alias": {
                  "summary": "Legacy `File` (capital F) alias — accepted server-side",
                  "value": {
                    "File": "The.Office.S04E01.HDTV.x264-LOL.mkv"
                  }
                },
                "no_match_returns_empty_array": {
                  "summary": "Parser ran but no match — empty array (NOT 404)",
                  "value": {
                    "file": "ZZZ_no_such_show_QQQ_S99E99.mkv"
                  }
                },
                "empty_body_returns_null": {
                  "summary": "Empty request body or missing `file` — null (NOT 400)",
                  "value": {}
                }
              },
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "description": "Filename or path (with folders) to match against the Simkl catalog. Both bare filenames and `/path/to/show/SxxEyy.mkv` style paths are accepted. The alias `File` (capital F) is also accepted for legacy clients.",
                    "examples": [
                      "Were.The.Fugawis.S01E01E02.WS.DSR.x264-NY2.mkv",
                      "/series/The Office/Season 4/The Office [401] Fun Run.avi"
                    ]
                  },
                  "part": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "For multi-part filenames (e.g. `S01E01E02` = two episodes in one file), the 1-based part index you want metadata for. Default `1`.",
                    "example": 1
                  },
                  "hash": {
                    "type": "string",
                    "description": "Optional file hash for additional disambiguation. Pass through if your scrobble integration computes one; safe to omit."
                  },
                  "process": {
                    "type": "string",
                    "description": "Optional pre-processing hint for the filename parser. Most clients can omit."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/SearchByFileEpisodeMatch"
                    },
                    {
                      "$ref": "#/components/schemas/SearchByFileShowMatch"
                    },
                    {
                      "$ref": "#/components/schemas/SearchByFileMovieMatch"
                    },
                    {
                      "type": "array",
                      "maxItems": 0,
                      "description": "Empty array — parser ran but found no match."
                    },
                    {
                      "type": "null",
                      "description": "Null — request body was empty or missing `file`."
                    }
                  ],
                  "discriminator": {
                    "propertyName": "type",
                    "mapping": {
                      "episode": "#/components/schemas/SearchByFileEpisodeMatch",
                      "show": "#/components/schemas/SearchByFileShowMatch",
                      "movie": "#/components/schemas/SearchByFileMovieMatch"
                    }
                  }
                },
                "examples": {
                  "tv_episode_stranger_things": {
                    "summary": "TV episode match — Stranger Things S01E03",
                    "value": {
                      "type": "episode",
                      "episode": {
                        "title": "Chapter Three: Holly, Jolly",
                        "season": 1,
                        "episode": 3,
                        "multipart": false,
                        "ids": {
                          "simkl": 1865356
                        }
                      },
                      "show": {
                        "title": "Stranger Things",
                        "year": 2016,
                        "ids": {
                          "simkl": 548312,
                          "tvdbslug": "stranger-things",
                          "tmdb": "66732",
                          "imdb": "tt4574334",
                          "traktslug": "stranger-things",
                          "tvdb": "305288"
                        }
                      }
                    }
                  },
                  "movie_inception": {
                    "summary": "Movie match — Inception 2010",
                    "value": {
                      "type": "movie",
                      "movie": {
                        "title": "Inception",
                        "year": 2010,
                        "ids": {
                          "simkl": 472214,
                          "imdb": "tt1375666",
                          "letterboxd": "inception",
                          "tvdbslug": "inception",
                          "tvdb": "113",
                          "boxd": "1skk",
                          "traktslug": "inception-2010",
                          "moviedb": "27205"
                        }
                      }
                    }
                  },
                  "movie_path_form": {
                    "summary": "Path form — /Movies/.../file.mkv",
                    "value": {
                      "type": "movie",
                      "movie": {
                        "title": "The Matrix",
                        "year": 1999,
                        "ids": {
                          "simkl": 53992,
                          "imdb": "tt0133093",
                          "letterboxd": "the-matrix",
                          "tvdbslug": "the-matrix",
                          "tvdb": "169",
                          "boxd": "2a1m",
                          "traktslug": "the-matrix-1999",
                          "moviedb": "603"
                        }
                      }
                    }
                  },
                  "anime_episode_demon_slayer": {
                    "summary": "Anime episode — folds under type:\"episode\" (show.ids carries mal, anidb, anilist, etc.)",
                    "value": {
                      "type": "episode",
                      "episode": {
                        "title": "Cruelty",
                        "season": 1,
                        "episode": 1,
                        "multipart": false,
                        "ids": {
                          "simkl": 4170591
                        }
                      },
                      "show": {
                        "title": "Kimetsu no Yaiba",
                        "year": 2019,
                        "ids": {
                          "simkl": 831411,
                          "crunchyroll": "GY5P48XEY",
                          "tmdb": "85937",
                          "mal": "38000",
                          "imdb": "tt9335498",
                          "tvdbslug": "demon-slayer-kimetsu-no-yaiba",
                          "anilist": "101922",
                          "animeplanet": "demon-slayer-kimetsu-no-yaiba",
                          "anisearch": "13658",
                          "kitsu": "41370",
                          "livechart": "3311",
                          "traktslug": "demon-slayer-kimetsu-no-yaiba",
                          "anidb": "14107",
                          "tvdb": "348545"
                        }
                      }
                    }
                  },
                  "multipart_second_episode": {
                    "summary": "Multipart filename — part=2 selects the second episode",
                    "value": {
                      "type": "episode",
                      "episode": {
                        "title": "Fastest and Furious",
                        "season": 1,
                        "episode": 2,
                        "multipart": false,
                        "ids": {
                          "simkl": 967218
                        }
                      },
                      "show": {
                        "title": "We're the Fugawis",
                        "year": 2013,
                        "ids": {
                          "simkl": 43283,
                          "tmdb": "57690",
                          "tvdbslug": "were-the-fugawis",
                          "imdb": "tt3108490",
                          "traktslug": "we-re-the-fugawis-2013",
                          "tvdb": "272581"
                        }
                      }
                    }
                  },
                  "legacy_capital_File_alias": {
                    "summary": "Legacy `File` (capital F) alias — accepted server-side",
                    "value": {
                      "type": "show",
                      "show": {
                        "title": "The Office",
                        "year": 2005,
                        "ids": {
                          "simkl": 39823,
                          "imdb": "tt0386676",
                          "tmdb": "2316",
                          "tvdbslug": "the-office-us",
                          "tvdb": "73244"
                        }
                      }
                    }
                  },
                  "no_match_returns_empty_array": {
                    "summary": "Parser ran but no match — empty array (NOT 404)",
                    "value": []
                  },
                  "empty_body_returns_null": {
                    "summary": "Empty request body or missing `file` — null (NOT 400)",
                    "value": null
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Search"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/search-by-file",
          "metadata": {
            "sidebarTitle": "By file"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "tv_episode_stranger_things",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"file\":\"Stranger.Things.S01E03.1080p.WEB.x264.mkv\"}' \\\n  \"https://api.simkl.com/search/file?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "movie_inception",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"file\":\"Inception.2010.1080p.BluRay.x264.mkv\"}' \\\n  \"https://api.simkl.com/search/file?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "movie_path_form",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"file\":\"/Movies/The Matrix (1999)/The.Matrix.1999.BluRay.mkv\"}' \\\n  \"https://api.simkl.com/search/file?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "anime_episode_demon_slayer",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"file\":\"Kimetsu.no.Yaiba.E01.1080p.mkv\"}' \\\n  \"https://api.simkl.com/search/file?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "multipart_second_episode",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"file\":\"Were.The.Fugawis.S01E01E02.WS.DSR.x264-NY2.mkv\",\"part\":2}' \\\n  \"https://api.simkl.com/search/file?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "legacy_capital_File_alias",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"File\":\"The.Office.S04E01.HDTV.x264-LOL.mkv\"}' \\\n  \"https://api.simkl.com/search/file?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "no_match_returns_empty_array",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"file\":\"ZZZ_no_such_show_QQQ_S99E99.mkv\"}' \\\n  \"https://api.simkl.com/search/file?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "empty_body_returns_null",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}' \\\n  \"https://api.simkl.com/search/file?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/search/id": {
      "get": {
        "operationId": "get-search-id",
        "summary": "Find items by external ID",
        "description": "<Warning>\n**Resolving more than ~20 IDs in a loop? Stop — you're doing it wrong.**\n\nA 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.\n\nIf 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.\n</Warning>\n\n> ## ⚠️ Prefer [`GET /redirect`](/api-reference/redirect) + a cached detail endpoint over `/search/id` for almost every external-ID lookup\n>\n> The recommended two-step flow is materially cheaper, faster, and edge-cached:\n>\n> **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.\n>\n> **Step 2 — Fetch the full record from the cached detail endpoint.** Use the parsed Simkl ID with the matching:\n> - Movies → [`GET /movies/{simkl_id}`](/api-reference/simkl/get-movie)\n> - TV shows → [`GET /tv/{simkl_id}`](/api-reference/simkl/get-tv-show)\n> - Anime → [`GET /anime/{simkl_id}`](/api-reference/simkl/get-anime)\n> - 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)\n>\n> 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.\n>\n> **Why this beats `/search/id`:**\n> - `/redirect` returns just HTTP headers (no JSON body). `/search/id` returns JSON every call.\n> - The detail endpoints are Cloudflare-cached. `/search/id` is a search query that hits origin every time.\n> - Two requests both cheap > one request that always hits origin.\n> - 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.\n>\n> **When `/search/id` is still the right call** (rare):\n> - You need the **legacy response shape** for a code path you can't change.\n> - You need a type-agnostic lookup that returns the `type` field upfront without parsing the `Location` URL.\n\n---\n\nLook 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`).\n\n#### Response shape (per item)\n\n```json\n{\n  \"type\": \"anime\",\n  \"title\": \"Attack on Titan\",\n  \"poster\": \"39/396870bc78f2ba7e\",\n  \"year\": 2013,\n  \"status\": \"ended\",\n  \"total_episodes\": 75,\n  \"anime_type\": \"tv\",\n  \"ids\": {\n    \"simkl\": 39687,\n    \"slug\": \"attack-on-titan\"\n  },\n  \"mal\": {\n    \"id\": 16498,\n    \"type\": \"tv\"\n  }\n}\n```\n\n`status` is one of `released`, `upcoming`, `ended`, `aired`, `tba`. `total_episodes` is omitted for movies.\n\n<Card title=\"Redirect & deep-linking — recommended alternative\" icon=\"bolt\" href=\"/api-reference/redirect\" horizontal>\n 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.\n</Card>\n\n<Tip>\n**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).\n</Tip>",
        "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"
          }
        },
        "tags": [
          "Search"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/search-by-id",
          "metadata": {
            "sidebarTitle": "By ID"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "imdb_movie",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"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\" \\\n  \"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\" \\\n  \"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\" \\\n  \"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\" \\\n  \"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\" \\\n  \"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\" \\\n  \"https://api.simkl.com/search/id?imdb=tt99999999&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/search/random": {
      "post": {
        "operationId": "post-search-random",
        "summary": "Random pick",
        "description": "Returns a random title — perfect for \"What should I watch?\" features, daily-pick widgets, or seeding recommendation flows. Optionally filter by type, genre, year range, rating, popularity rank, or streaming service availability.\n\n#### Query / body parameters\n\nAll filters can be sent as either query parameters or a JSON body — both forms work. When `type` is omitted, the server picks one of `movie` / `tv` / `anime` at random first, then returns a random item from that domain.\n\n| Param | Notes |\n|---|---|\n| `service` | `simkl` (default), `netflix`, `crunchy`, `hulu`. When set to anything but `simkl`, results are restricted to titles available on that service AND the response includes `{service}_id` + `{service}_url` (e.g. `netflix_id`, `netflix_url`). |\n| `type` | `movie`, `tv`, or `anime`. **Omit to let the server pick a random domain first.** |\n| `genre` | Comma-separated genre slugs (e.g. `action,thriller`). Genre slugs differ by type — see the per-type lists below. |\n| `country` | ISO 3166-1 alpha-2 country code (movies / TV). |\n| `year_from` | Default `1990`. |\n| `year_to` | Optional. |\n| `rank_limit` | Maximum rank to consider (lower = more popular). |\n| `rating_from` | Floor rating, 0–10. For TV / movies this filters on IMDb; for anime, on MAL. |\n| `rating_to` | Ceiling rating, 0–10. |\n| `limit` | Number of items, capped at `50`. **Single object when omitted; array when set.** |\n\n#### Response shapes\n\n| Shape | When |\n|---|---|\n| `{ simkl_id, simkl_url }` | `limit` omitted → single random item. |\n| `[{ simkl_id, simkl_url }, ...]` | `limit` set → array of up to `limit` items. |\n| `{ error: \"not_found\" }` | Filters matched nothing. Still status `200` (no 404). |\n\nWhen `service != simkl` and a matching service link exists, the item gains `{service}_id` and `{service}_url`. When no link exists, the item still returns but without those extra keys.\n\n#### Genre slugs by type\n\nSlugs are lowercase with spaces normalized to hyphens.\n\n**Movies** (20): action, adventure, animation, comedy, crime, documentary, drama, erotica, family, fantasy, history, horror, music, mystery, romance, science-fiction, thriller, tv-movie, war, western\n\n**TV** (38): action, adventure, animation, awards-show, children, comedy, crime, documentary, drama, erotica, family, fantasy, food, game-show, history, home-and-garden, horror, indie, korean-drama, martial-arts, mini-series, musical, mystery, news, podcast, reality, romance, science-fiction, soap, special-interest, sport, suspense, talk-show, thriller, travel, video-game-play, war, western\n\n**Anime** (46): action, adventure, comedy, drama, ecchi, educational, fantasy, gag-humor, gore, harem, historical, horror, idol, isekai, josei, kids, magic, martial-arts, mecha, military, music, mystery, mythology, parody, psychological, racing, reincarnation, romance, samurai, school, sci-fi, seinen, shoujo, shoujo-ai, shounen, shounen-ai, slice-of-life, space, sports, strategy-game, super-power, supernatural, thriller, vampire, yaoi, yuri\n",
        "parameters": [
          {
            "name": "service",
            "in": "query",
            "description": "Finds random TV Show, Anime or Movie.",
            "schema": {
              "type": "string",
              "default": "simkl",
              "enum": [
                "simkl",
                "netflix",
                "crunchy",
                "hulu"
              ]
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Restricts the random pick to one domain. Omit to let the server pick a domain first (movie / tv / anime — uniform random across all three).",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "movie",
                "tv",
                "anime"
              ]
            },
            "example": "tv"
          },
          {
            "name": "genre",
            "in": "query",
            "description": "TV Shows, Anime and Movies have their own genres.\n\n**Movies**:\naction, adventure, animation, comedy, crime, documentary, drama, erotica, family, fantasy, foreign, history, horror, music, mystery, romance, science-fiction, thriller, tv-movie, war, western\n**TV:**\naction, adventure, animation, awards-show, children, comedy, crime, documentary, drama, erotica, family, fantasy, food, game-show, history, home-and-garden, horror, indie, korean-drama, martial-arts, mini-series, musical, mystery, news, podcast, reality, romance, science-fiction, soap, special-interest, sport, suspense, talk-show, thriller, travel, war, western\n**Anime:**\naction, adventure, cars, comedy, dementia, demons, drama, ecchi, fantasy, game, harem, historical, horror, josei, kids, magic, martial-arts, mecha, military, music, mystery, parody, police, psychological, romance, samurai, school, sci-fi, seinen, shoujo, shoujo-ai, shounen, shounen-ai, slice-of-life, space, sports, super-power, supernatural, thriller, vampire, yaoi, yuri",
            "schema": {
              "type": "string"
            },
            "example": "comedy"
          },
          {
            "name": "rating_from",
            "in": "query",
            "description": "max value is 10. Random search for TV Shows and Movies will be performed using IMDB ratings. Anime are based on MAL ratings.",
            "schema": {
              "type": "integer",
              "default": 1
            },
            "example": "5"
          },
          {
            "name": "rating_to",
            "in": "query",
            "description": "",
            "schema": {
              "type": "integer"
            },
            "example": "10"
          },
          {
            "name": "rank_limit",
            "in": "query",
            "description": "maximum rank allowed",
            "schema": {
              "type": "integer"
            },
            "example": "2000"
          },
          {
            "name": "year_from",
            "in": "query",
            "description": "First released movie starts from 1920.",
            "schema": {
              "type": "integer"
            },
            "example": "2004"
          },
          {
            "name": "year_to",
            "in": "query",
            "description": "",
            "schema": {
              "type": "integer"
            },
            "example": "2010"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "if >0 specified it returns 2 dimensional array with multiple results",
            "schema": {
              "type": "integer"
            },
            "example": "10"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO 3166-1 alpha-2 country code (e.g. `us`, `jp`). Restricts results to titles released in that country."
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK — single object (when `limit` omitted), array (when `limit` set), or not-found object.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/SearchRandomItem"
                    },
                    {
                      "$ref": "#/components/schemas/SearchRandomItemArray"
                    },
                    {
                      "$ref": "#/components/schemas/SearchRandomNotFound"
                    }
                  ],
                  "description": "Discriminator is shape-based (no `type` field on this endpoint): object with `simkl_id` → single item; array → multiple items; object with `error` → no match."
                },
                "examples": {
                  "default_no_params_random_domain": {
                    "summary": "No params — server picks a random domain (movie/tv/anime), returns single item",
                    "value": {
                      "simkl_id": 427406,
                      "simkl_url": "https://simkl.com/anime/427406/shimoneta-to-iu-gainen-ga-sonzai-shinai-taikutsu-na-sekai"
                    }
                  },
                  "type_movie": {
                    "summary": "type=movie — random movie",
                    "value": {
                      "simkl_id": 421160,
                      "simkl_url": "https://simkl.com/movies/421160/uninvited"
                    }
                  },
                  "type_tv": {
                    "summary": "type=tv — random TV show",
                    "value": {
                      "simkl_id": 2277797,
                      "simkl_url": "https://simkl.com/tv/2277797/compromising-situations"
                    }
                  },
                  "type_anime": {
                    "summary": "type=anime — random anime",
                    "value": {
                      "simkl_id": 2613914,
                      "simkl_url": "https://simkl.com/anime/2613914/kanpekisugite-kawaige-ga-nai-to-konyaku-haki-sareta-seijo-wa-ringoku-ni-urareru"
                    }
                  },
                  "limit_3_array_form": {
                    "summary": "limit=3 — array form (max 50)",
                    "value": [
                      {
                        "simkl_id": 2413564,
                        "simkl_url": "https://simkl.com/anime/2413564/nanatsu-no-taizai-mokushiroku-no-yonkishi"
                      },
                      {
                        "simkl_id": 36852,
                        "simkl_url": "https://simkl.com/anime/36852/silent-mobius"
                      },
                      {
                        "simkl_id": 40776,
                        "simkl_url": "https://simkl.com/anime/40776/sentou-yousei-yukikaze-faf-koukuu-senshi"
                      }
                    ]
                  },
                  "year_range_movie": {
                    "summary": "Genre + year-range filter",
                    "value": {
                      "simkl_id": 1360484,
                      "simkl_url": "https://simkl.com/movies/1360484/min-far-er-bokser"
                    }
                  },
                  "service_netflix_with_link": {
                    "summary": "service=netflix — adds netflix_id + netflix_url when the title has a Netflix link",
                    "value": {
                      "simkl_id": 30721,
                      "simkl_url": "https://simkl.com/tv/30721/ripper-street",
                      "netflix_id": "70270745",
                      "netflix_url": "http://www.netflix.com/title/70270745"
                    }
                  },
                  "filters_match_nothing_not_found": {
                    "summary": "Filters match nothing — `{error: \"not_found\"}` (still 200, NOT 404)",
                    "value": {
                      "error": "not_found"
                    }
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Search"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/search-random",
          "metadata": {
            "sidebarTitle": "Random"
          }
        },
        "security": [
          {
            "clientId": []
          },
          {
            "simklApiKey": []
          },
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Body is optional — pass filters as query parameters or as a JSON body.",
          "content": {
            "application/json": {
              "examples": {
                "default_no_params_random_domain": {
                  "summary": "No params — server picks a random domain (movie/tv/anime), returns single item",
                  "value": {}
                },
                "type_movie": {
                  "summary": "type=movie — random movie",
                  "value": {}
                },
                "type_tv": {
                  "summary": "type=tv — random TV show",
                  "value": {}
                },
                "type_anime": {
                  "summary": "type=anime — random anime",
                  "value": {}
                },
                "limit_3_array_form": {
                  "summary": "limit=3 — array form (max 50)",
                  "value": {}
                },
                "year_range_movie": {
                  "summary": "Genre + year-range filter",
                  "value": {}
                },
                "service_netflix_with_link": {
                  "summary": "service=netflix — adds netflix_id + netflix_url when the title has a Netflix link",
                  "value": {}
                },
                "filters_match_nothing_not_found": {
                  "summary": "Filters match nothing — `{error: \"not_found\"}` (still 200, NOT 404)",
                  "value": {}
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "default_no_params_random_domain",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/random?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "type_movie",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/random?type=movie&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "type_tv",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/random?type=tv&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "type_anime",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/random?type=anime&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "limit_3_array_form",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/random?limit=3&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "year_range_movie",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/random?type=movie&year_from=2000&year_to=2010&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "service_netflix_with_link",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/random?service=netflix&type=tv&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "filters_match_nothing_not_found",
            "source": "curl -X POST -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/random?type=movie&year_from=1900&year_to=1901&rating_from=10&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/search/{type}": {
      "get": {
        "operationId": "get-search-type",
        "summary": "Search by text query",
        "description": "Full-text search over the Simkl catalog. Pick a type (`movie`, `tv`, or `anime`) and pass a search term like `john wick` or `john wick 2014`.\n\n<Note>\n**Heads up: `movie` becomes `\"movies\"` in the response.**\n\nYou call `/search/movie` (no `s`) but each item in the response has `endpoint_type: \"movies\"` (with an `s`). TV and anime don't change.\n\n| You call | Each item's `endpoint_type` is |\n|---|---|\n| `/search/movie` | `\"movies\"` ← note the extra `s` |\n| `/search/tv` | `\"tv\"` |\n| `/search/anime` | `\"anime\"` |\n\nEvery item in a single response has the same `endpoint_type` — you never get a mixed list back.\n</Note>\n\n#### Path parameter\n\n| Param | Values |\n|---|---|\n| `type` | `movie`, `tv`, `anime` |\n\n#### Query parameters\n\n| Param | Default | Notes |\n|---|---|---|\n| `q` | — | **Required.** Text query (matches `title` and `all_titles[]`). For external-ID lookups (IMDb / TMDB / TVDB / etc.), use [`/redirect`](/api-reference/redirect) or [`/search/id`](/api-reference/simkl/search-by-id) instead. |\n| `page` | `1` | Hard-capped server-side at `20`. Higher values silently clamp. |\n| `limit` | `10` | Hard-capped server-side at `50`. Higher values silently clamp. |\n| `extended` | `simple` | `full` adds `all_titles[]`, `url`, `ep_count` (TV/anime), `rank` (nullable), `status` (TV/anime), and a `ratings` block. |\n\nReturns paginated results with `X-Pagination-*` headers — see [Pagination](/conventions/pagination) for the standard paginator pattern.\n\n#### Per-item fields by mode\n\n| Field | `simple` | `extended=full` | Notes |\n|---|---|---|---|\n| `title` | ✓ | ✓ | Display title in the user's locale. |\n| `title_en` | — | — | **Anime only**, optional even on anime — only when an English-localized title is on file. |\n| `title_romaji` | anime only | anime only | **Anime only**, always present on anime items. Currently mirrors `title` for the romaji slot. |\n| `year` | ✓ | ✓ | Premiere year. |\n| `endpoint_type` | ✓ | ✓ | `\"movies\"` / `\"tv\"` / `\"anime\"`. Same value on every item in one response. |\n| `type` | anime only | anime only | **Anime only**: `tv`, `movie`, `ova`, `ona`, `special`, `music`. |\n| `poster` | ✓ | ✓ | Image path fragment — see [Image conventions](/conventions/images) for the full URL pattern (`https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`). |\n| `ids` | ✓ | ✓ | `{ simkl_id, slug, tmdb? }`. `tmdb` only present when a TMDB link is on file. |\n| `all_titles` | — | movies/anime | Aliases / localized variants. Anime sees the most entries. TV items typically don't carry this even on `extended=full`. |\n| `url` | — | ✓ | Relative simkl.com URL (with slug). |\n| `ep_count` | — | TV/anime | Total episode count when known. |\n| `rank` | — | ✓ | Simkl popularity rank. **Nullable** — see below. |\n| `status` | — | TV/anime | Closed enum: `tba`, `ended`, `airing`. |\n| `ratings.simkl` | — | ✓ | `{ rating, votes }` — only present when votes > 0. |\n| `ratings.imdb` | — | ✓ | `{ rating, votes }` — only present when an IMDb rating record exists. |\n| `ratings.mal` | — | anime only | `{ rating, votes, rank }` — anime only, only when a MAL record exists. |\n\n#### Nulls — what they mean\n\n| Field | When null | Type |\n|---|---|---|\n| `rank` | Item not yet ranked, or rank value ≥ 999999 sentinel | [Type 4](/conventions/null-values#type-4) |\n| `ep_count` | TV/anime item with no episode count on file yet | [Type 4](/conventions/null-values#type-4) |\n| `poster` | No poster image on file | [Type 4](/conventions/null-values#type-4) |\n\n#### Error responses\n\n| Status | When |\n|---|---|\n| `412 client_id_failed` | Missing or invalid `client_id` |\n| `500` | Server error |\n\nNo `400` — invalid `page` / `limit` silently clamp to the server caps. No `404` — empty result is `[]` with status `200`.\n\n<Tip>\n**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).\n</Tip>\n",
        "parameters": [
          {
            "name": "type",
            "in": "path",
            "description": "Search type.",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "tv",
                "anime",
                "movie"
              ]
            },
            "example": "movie"
          },
          {
            "name": "q",
            "in": "query",
            "description": "Required. The search term — matches `title` and `all_titles[]` across the chosen catalog (movies / TV / anime).\n\nExamples: `john wick`, `john wick 2014`, `breaking bad`, `cowboy bebop`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "john wick"
          },
          {
            "$ref": "#/components/parameters/PageParam"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            },
            "description": "Items per page. Capped at 50."
          },
          {
            "name": "extended",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "simple",
                "full"
              ]
            },
            "description": "`full` adds overview, ratings, and genres to each match."
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Pagination-Page": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Pagination-Limit": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Pagination-Page-Count": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Pagination-Item-Count": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "description": "Search results — always a single array. The `endpoint_type` on each item mirrors the path's `:type` (in its plural form) and is constant within one response, so use it as the discriminator.",
                  "items": {
                    "oneOf": [
                      {
                        "$ref": "#/components/schemas/SearchByTextMovieItem"
                      },
                      {
                        "$ref": "#/components/schemas/SearchByTextTVItem"
                      },
                      {
                        "$ref": "#/components/schemas/SearchByTextAnimeItem"
                      }
                    ],
                    "discriminator": {
                      "propertyName": "endpoint_type",
                      "mapping": {
                        "movies": "#/components/schemas/SearchByTextMovieItem",
                        "tv": "#/components/schemas/SearchByTextTVItem",
                        "anime": "#/components/schemas/SearchByTextAnimeItem"
                      }
                    }
                  }
                },
                "examples": {
                  "movie_simple": {
                    "summary": "Movies (simple) — q=john wick, limit=2",
                    "value": [
                      {
                        "title": "John Wick",
                        "year": 2014,
                        "endpoint_type": "movies",
                        "poster": "30/3002370dbc564e5d8",
                        "ids": {
                          "simkl_id": 342994,
                          "slug": "john-wick",
                          "tmdb": "245891"
                        }
                      },
                      {
                        "title": "John Wick: Chapter 4",
                        "year": 2023,
                        "endpoint_type": "movies",
                        "poster": "13/13693559ce304eb6f6",
                        "ids": {
                          "simkl_id": 1098350,
                          "slug": "john-wick-chapter-4",
                          "tmdb": "603692"
                        }
                      }
                    ]
                  },
                  "movie_extended": {
                    "summary": "Movies (extended=full) — q=john wick, limit=1",
                    "value": [
                      {
                        "title": "John Wick",
                        "year": 2014,
                        "endpoint_type": "movies",
                        "poster": "30/3002370dbc564e5d8",
                        "all_titles": [
                          "John Wick",
                          "Джон Уик",
                          "존 윅",
                          "ジョン・ウィック",
                          "John Wick: Chapter 1"
                        ],
                        "url": "/movies/342994/john-wick",
                        "rank": 2429,
                        "ratings": {
                          "simkl": {
                            "rating": 7.8,
                            "votes": 8286
                          },
                          "imdb": {
                            "rating": 7.5,
                            "votes": 828209
                          }
                        },
                        "ids": {
                          "simkl_id": 342994,
                          "slug": "john-wick",
                          "tmdb": "245891"
                        }
                      }
                    ]
                  },
                  "tv_simple": {
                    "summary": "TV (simple) — q=breaking bad, limit=2",
                    "value": [
                      {
                        "title": "Breaking Bad",
                        "year": 2008,
                        "endpoint_type": "tv",
                        "poster": "97/978343d5161a724",
                        "ids": {
                          "simkl_id": 11121,
                          "slug": "breaking-bad",
                          "tmdb": "1396"
                        }
                      },
                      {
                        "title": "Breaking Bad Fortune Teller",
                        "year": 2016,
                        "endpoint_type": "tv",
                        "poster": "14/14429153ab8d3bf317",
                        "ids": {
                          "simkl_id": 1838137,
                          "slug": "breaking-bad-fortune-teller",
                          "tmdb": "232533"
                        }
                      }
                    ]
                  },
                  "tv_extended": {
                    "summary": "TV (extended=full) — q=breaking bad, limit=2 (second item has rank: null)",
                    "value": [
                      {
                        "title": "Breaking Bad",
                        "year": 2008,
                        "endpoint_type": "tv",
                        "poster": "97/978343d5161a724",
                        "url": "/tv/11121/breaking-bad",
                        "ep_count": 62,
                        "rank": 2,
                        "status": "ended",
                        "ratings": {
                          "simkl": {
                            "rating": 9.2,
                            "votes": 11657
                          },
                          "imdb": {
                            "rating": 9.5,
                            "votes": 2615761
                          }
                        },
                        "ids": {
                          "simkl_id": 11121,
                          "slug": "breaking-bad",
                          "tmdb": "1396"
                        }
                      },
                      {
                        "title": "Breaking Bad Fortune Teller",
                        "year": 2016,
                        "endpoint_type": "tv",
                        "poster": "14/14429153ab8d3bf317",
                        "url": "/tv/1838137/breaking-bad-fortune-teller",
                        "ep_count": 40,
                        "rank": null,
                        "status": "ended",
                        "ids": {
                          "simkl_id": 1838137,
                          "slug": "breaking-bad-fortune-teller",
                          "tmdb": "232533"
                        }
                      }
                    ]
                  },
                  "anime_simple": {
                    "summary": "Anime (simple) — q=cowboy bebop, limit=2",
                    "value": [
                      {
                        "title": "Cowboy Bebop",
                        "title_romaji": "Cowboy Bebop",
                        "year": 1998,
                        "endpoint_type": "anime",
                        "type": "tv",
                        "poster": "36/36842f1bceb6b39",
                        "ids": {
                          "simkl_id": 37089,
                          "slug": "cowboy-bebop",
                          "tmdb": "30991"
                        }
                      },
                      {
                        "title": "Cowboy Bebop: Tengoku no Tobira",
                        "title_en": "Cowboy Bebop: Knockin' on Heaven's Door",
                        "title_romaji": "Cowboy Bebop: Tengoku no Tobira",
                        "year": 2001,
                        "endpoint_type": "anime",
                        "type": "movie",
                        "poster": "11/113551180c5f0e82c1",
                        "ids": {
                          "simkl_id": 38382,
                          "slug": "cowboy-bebop-tengoku-no-tobira"
                        }
                      }
                    ]
                  },
                  "anime_extended": {
                    "summary": "Anime (extended=full) — q=cowboy bebop, limit=1 (ratings.mal carries rank)",
                    "value": [
                      {
                        "title": "Cowboy Bebop",
                        "title_romaji": "Cowboy Bebop",
                        "year": 1998,
                        "endpoint_type": "anime",
                        "type": "tv",
                        "poster": "36/36842f1bceb6b39",
                        "all_titles": [
                          "Cowboy Bebop",
                          "カウボーイビバップ",
                          "星际牛仔",
                          "Bebop"
                        ],
                        "url": "/anime/37089/cowboy-bebop",
                        "ep_count": 26,
                        "rank": 46,
                        "status": "ended",
                        "ratings": {
                          "simkl": {
                            "rating": 8.6,
                            "votes": 4611
                          },
                          "imdb": {
                            "rating": 8.8,
                            "votes": 27847
                          },
                          "mal": {
                            "rating": 8.8,
                            "votes": 1062607,
                            "rank": 49
                          }
                        },
                        "ids": {
                          "simkl_id": 37089,
                          "slug": "cowboy-bebop",
                          "tmdb": "30991"
                        }
                      }
                    ]
                  },
                  "empty_no_results": {
                    "summary": "No results — empty array, status 200",
                    "value": []
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Search"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/search-by-text",
          "metadata": {
            "sidebarTitle": "By text"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "movie_simple",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/movie?q=john+wick&limit=2&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "movie_extended",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/movie?q=john+wick&extended=full&limit=1&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "tv_simple",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/tv?q=breaking+bad&limit=2&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "tv_extended",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/tv?q=breaking+bad&extended=full&limit=2&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "anime_simple",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/anime?q=cowboy+bebop&limit=2&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "anime_extended",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/anime?q=cowboy+bebop&extended=full&limit=1&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "empty_no_results",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/search/movie?q=zzznoresultzzz&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/sync/activities": {
      "get": {
        "operationId": "get-sync-activities",
        "summary": "Get Last Activities",
        "description": "Returns the most recent update timestamps for each of the user's lists. **Always call this first** when syncing — compare against your last-saved timestamps and pull only the lists that have moved. This is the cheapest call in the API.\n\n#### Top-level fields\n\n| Field | Use |\n|---|---|\n| `all` | Latest update across every domain. Best first-level check. |\n| `settings.all` | Updates to account settings (name, time zone, …) at https://simkl.com/settings/. |\n| `tv_shows`, `anime`, `movies` | Per-domain timestamp groups. |\n\n#### Per-domain timestamps\n\n| Field | Meaning | Cheapest next call |\n|---|---|---|\n| `all` | Latest update in this domain. | — |\n| `rated_at` | A rating was added, changed, or removed. | [`GET /sync/ratings/{type}/{rating}`](/api-reference/simkl/get-user-ratings) with `date_from` — only the changed ratings. Walkthrough: [Phase 2 — Continuous sync](/guides/sync#phase-2-continuous-sync). |\n| `playback` | A paused playback was added, resumed, or cleared. | [`GET /sync/playback/{type}`](/api-reference/simkl/get-playback-sessions) with `date_from` — only the changed sessions. |\n| `plantowatch`, `watching`, `completed`, `hold`, `dropped` | Items moved into/out of these lists, or episodes were marked watched/unwatched. | [`GET /sync/all-items/{type}/{status}`](/api-reference/simkl/get-all-items) with `date_from` and `extended=full` — full delta of modified items. Walkthrough: [Phase 2 — Continuous sync](/guides/sync#phase-2-continuous-sync). |\n| `removed_from_list` | Items were deleted from the library entirely. `date_from` **won't surface removals** — you can only detect them by diffing. | [`GET /sync/all-items/{type}/{status}`](/api-reference/simkl/get-all-items) with `extended=simkl_ids_only` — cheapest possible payload (just the IDs) — and diff against your local cache. Walkthrough: [Detecting deletions](/guides/sync#phase-2-continuous-sync). |\n\n> Movies don't have `watching` or `hold` — movies are atomic, so those statuses don't apply.\n\n#### Auto-move side effects\n\nWhen a user **rates** an unrated item, Simkl auto-files it: movies → `Completed`, shows/anime → `Watching`. That auto-move bumps the corresponding list timestamp, so the rated item also appears in subsequent `/sync/all-itemsdate_from` queries.\n\n#### Recommended sync loop\n\n1. On first sync, store every timestamp returned and pull each list once with no `date_from`.\n2. Periodically poll this endpoint. If `all` hasn't changed, you're up to date.\n3. Otherwise, for each domain whose `all` moved, request only the lists whose per-list timestamp changed using `date_from` = your previously-saved value.\n4. Save the new timestamps and repeat.\n\n#### Removal cascade\n\nWhen `removed_from_list` moves, the user actively deleted items from their library. Refetch with `extended=simkl_ids_only` and diff against your local cache to detect deletions — `date_from` won't surface them. Also clear any local rating you stored for those items: Simkl wipes the rating when an item is removed, which is why removals can move both `removed_from_list` *and* `rated_at`.\n\n<Card title=\"Sync guide — full walkthrough\" icon=\"arrows-rotate\" href=\"/guides/sync\" horizontal>\n Two-phase model (initial pull → activities-checked delta loop), `date_from` semantics, deletion reconciliation, edge cases, and reference implementations in Node and Python.\n</Card>",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Activities"
                },
                "examples": {
                  "active_user": {
                    "summary": "Active user — every bucket has activity",
                    "description": "An established user who has watched, rated, paused, and curated content across all three domains. Every timestamp is non-null. This is the shape your sync loop will see most often once a user has been around for a while.",
                    "value": {
                      "all": "2026-05-14T06:50:38Z",
                      "settings": {
                        "all": "2026-02-15T22:53:03Z"
                      },
                      "tv_shows": {
                        "all": "2026-05-14T06:49:56Z",
                        "rated_at": "2026-04-10T05:34:55Z",
                        "playback": "2026-04-11T10:36:01Z",
                        "plantowatch": "2026-04-10T05:42:42Z",
                        "watching": "2026-05-04T19:40:58Z",
                        "completed": "2026-04-11T11:50:21Z",
                        "hold": "2026-05-14T06:49:56Z",
                        "dropped": "2026-05-14T06:49:56Z",
                        "removed_from_list": "2026-04-10T05:34:55Z"
                      },
                      "anime": {
                        "all": "2026-05-14T06:50:38Z",
                        "rated_at": "2026-04-10T05:34:55Z",
                        "playback": "2026-05-14T06:50:38Z",
                        "plantowatch": "2026-05-14T06:41:53Z",
                        "watching": "2026-05-14T06:43:00Z",
                        "completed": "2026-05-14T06:42:42Z",
                        "hold": "2026-05-14T06:42:05Z",
                        "dropped": "2026-05-14T06:49:56Z",
                        "removed_from_list": "2026-04-10T05:34:55Z"
                      },
                      "movies": {
                        "all": "2026-05-14T06:50:38Z",
                        "rated_at": "2026-05-14T06:43:20Z",
                        "playback": "2026-05-14T06:50:38Z",
                        "plantowatch": "2026-05-14T06:43:11Z",
                        "completed": "2026-05-14T06:43:15Z",
                        "dropped": "2026-05-14T06:49:56Z",
                        "removed_from_list": "2026-04-10T05:34:55Z"
                      }
                    }
                  },
                  "fresh_user": {
                    "summary": "Brand-new user — just authenticated, library empty",
                    "description": "A user who has just connected your app and hasn't touched their Simkl library yet. Every timestamp is `null` because no event has fired in any bucket. `settings.all` is also null unless the user changed a setting during signup. This is *Type 1* null — \"never happened yet\".",
                    "value": {
                      "all": null,
                      "settings": {
                        "all": null
                      },
                      "tv_shows": {
                        "all": null,
                        "rated_at": null,
                        "playback": null,
                        "plantowatch": null,
                        "watching": null,
                        "completed": null,
                        "hold": null,
                        "dropped": null,
                        "removed_from_list": null
                      },
                      "anime": {
                        "all": null,
                        "rated_at": null,
                        "playback": null,
                        "plantowatch": null,
                        "watching": null,
                        "completed": null,
                        "hold": null,
                        "dropped": null,
                        "removed_from_list": null
                      },
                      "movies": {
                        "all": null,
                        "rated_at": null,
                        "playback": null,
                        "plantowatch": null,
                        "completed": null,
                        "dropped": null,
                        "removed_from_list": null
                      }
                    }
                  },
                  "partial_user": {
                    "summary": "Mid-state user — TV-only, some buckets untouched",
                    "description": "A user who actively syncs TV shows but has never added an anime or rated a movie. Demonstrates the common mix of populated and null fields: the buckets they've used have timestamps, the ones they haven't are null.",
                    "value": {
                      "all": "2024-08-19T12:34:56Z",
                      "settings": {
                        "all": "2023-11-02T18:01:45Z"
                      },
                      "tv_shows": {
                        "all": "2024-08-19T12:34:56Z",
                        "rated_at": "2024-08-19T12:34:56Z",
                        "playback": null,
                        "plantowatch": "2024-07-30T09:12:00Z",
                        "watching": "2024-08-19T12:34:56Z",
                        "completed": "2024-08-15T22:18:00Z",
                        "hold": null,
                        "dropped": null,
                        "removed_from_list": "2024-08-10T19:45:13Z"
                      },
                      "anime": {
                        "all": null,
                        "rated_at": null,
                        "playback": null,
                        "plantowatch": null,
                        "watching": null,
                        "completed": null,
                        "hold": null,
                        "dropped": null,
                        "removed_from_list": null
                      },
                      "movies": {
                        "all": "2024-08-12T20:00:00Z",
                        "rated_at": null,
                        "playback": null,
                        "plantowatch": "2024-08-12T20:00:00Z",
                        "completed": null,
                        "dropped": null,
                        "removed_from_list": null
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-activities",
          "metadata": {
            "sidebarTitle": "Last Activities"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl \"https://api.simkl.com/sync/activities?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\" \\\n  -H \"User-Agent: my-app-name/1.0\" \\\n  -H \"Authorization: Bearer YOUR_ACCESS_TOKEN\""
          },
          {
            "lang": "JavaScript",
            "label": "Node",
            "source": "const params = new URLSearchParams({\n  client_id:     CLIENT_ID,\n  'app-name':    'my-app-name',\n  'app-version': '1.0',\n});\nconst activities = await fetch(`https://api.simkl.com/sync/activities?${params}`, {\n  headers: {\n    'User-Agent':    'my-app-name/1.0',\n    'Authorization': `Bearer ${ACCESS_TOKEN}`,\n  },\n}).then(r => r.json());"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "import requests\nactivities = requests.get(\n    'https://api.simkl.com/sync/activities',\n    params={\n        'client_id':   CLIENT_ID,\n        'app-name':    'my-app-name',\n        'app-version': '1.0',\n    },\n    headers={\n        'User-Agent':    'my-app-name/1.0',\n        'Authorization': f'Bearer {ACCESS_TOKEN}',\n    },\n).json()"
          }
        ]
      }
    },
    "/sync/add-to-list": {
      "post": {
        "operationId": "post-sync-add-to-list",
        "summary": "Add to Watchlist",
        "description": "Move an item into one of the user's **Watchlist** statuses. The body's per-item `to` field selects the destination:\n\n<Note>\n**Most apps prefer [`POST /sync/history`](/api-reference/simkl/add-to-history) for sync flows.** Use this endpoint (`/sync/add-to-list`) only when your app has explicit \"Add to Plan to Watch\" / \"Move to Hold\" UI buttons — i.e. setting watchlist status without recording a watch event. For backfill from another tracker, scrobbling, or marking-watched UI, send to `/sync/history` instead (which carries `status`, `rating`, `memo`, AND the watch event in one shape).\n\n**Don't chain `/sync/history` then `/sync/add-to-list` — the history call already moves the item.** `POST /sync/history` automatically places (and re-classifies) the item on the right Watchlist based on the watch event. Read `added.statuses[].response.status` in the history response to see the resolved status — e.g. a `\"completed\"` write on a still-airing show is silently downgraded to `\"watching\"` and reflected there. A follow-up `/sync/add-to-list` call is redundant and may overwrite the server's smarter decision.\n\nSee the [Sync guide](/guides/sync) for the two-phase pull/delta pattern.\n</Note>\n\n<Warning>\n**This endpoint does not save memos.** If you include a `memo` field per item, the request **succeeds** and the memo is **echoed back** in the response — but the value is not persisted; reading the item with `?memos=yes` afterwards returns `memo: {}`. To set or update a memo, send the item to [`POST /sync/history`](/api-reference/simkl/add-to-history) with `ids` + `status` + `memo`. `/sync/history` also auto-adds the item to the watchlist if it wasn't there yet, so a single call covers both \"add the item\" and \"set the memo\".\n</Warning>\n\n| `to` value | Destination |\n|---|---|\n| `watching` | Currently watching. (For movies, automatically becomes `completed` since movies are atomic.) |\n| `plantowatch` | Plan to watch. |\n| `hold` | On hold. |\n| `dropped` | Dropped. |\n| `completed` | Completed. |\n\n`to` is **per-item** (each entry in the array carries its own destination). The legacy top-level `to` shape is **not accepted** — the server returns `400 empty_field` (`Missed \"to\" parameter`) when `to` only appears at the top level.\n\n<Tip>\n**You don't need a Simkl ID.** The server resolves any combination of identifiers via its internal Search — pass whatever IDs your app already has and skip the `/redirect` lookup step. Identifier slots accepted on each item:\n\n| Slot | Notes |\n|---|---|\n| `ids.simkl` | Simkl internal ID. Always wins when present. |\n| `ids.imdb` | IMDb ID (e.g. `tt1375666`). Works for movies and shows. |\n| `ids.tmdb` | TMDB ID. Works for movies and shows. |\n| `ids.tvdb` | TVDB ID. Most-used canonical for TV in media-server stacks (Plex, Sonarr, Jellyfin, Kodi). |\n| `ids.mal` / `ids.anidb` / `ids.anilist` / `ids.kitsu` | Anime catalogs. Send any/all you have. |\n| `ids.slug` | URL slug — useful when you only have a Simkl-shaped link. |\n| `title` + `year` (no `ids` at all) | Text fallback. Fuzzy match; ambiguous titles may miss — inspect `not_found` in the response. |\n\n**Send everything you have.** The server picks the first identifier that resolves and accepts the extras. This is the canonical shape for migrations from another tracker (Trakt → Simkl, IMDb-list import, Letterboxd export, etc.) — just forward whatever the source carried.\n</Tip>\n\n```json\n{\n  \"movies\": [\n    {\n      \"to\": \"completed\",\n      \"title\": \"Inception\",\n      \"year\": 2010,\n      \"ids\": {\n        \"simkl\": 472214,\n        \"imdb\": \"tt1375666\",\n        \"tmdb\": \"27205\"\n      }\n    }\n  ],\n  \"shows\": [\n    {\n      \"to\": \"watching\",\n      \"title\": \"Game of Thrones\",\n      \"year\": 2011,\n      \"ids\": {\n        \"simkl\": 17465,\n        \"slug\": \"game-of-thrones\",\n        \"imdb\": \"tt0944947\",\n        \"tmdb\": \"1399\",\n        \"tvdb\": \"121361\"\n      }\n    }\n  ]\n}\n```\n\nOptional per-item fields: `watched_at`, `added_at`.\n\n<Warning>\n**To remove an item, use [`POST /sync/history/remove`](/api-reference/simkl/remove-from-history).** This endpoint operates on the Watchlist (the five statuses above); the canonical un-track / delete-from-list path is `/sync/history/remove`, which writes to the same backing store and returns the same kind of result envelope. A legacy `to: \"remove\"` value is accepted by this endpoint for backwards compatibility, but it is **undocumented** and should not be used in new integrations — Simkl reserves the right to change its behavior without notice.\n</Warning>\n\n#### Response: `added` and `not_found`\n\nThe response always returns 201 (even on partial failures) with two arrays per media-type:\n\n```json\n{\n \"added\": {\n \"movies\": [{ \"to\": \"completed\", \"ids\": {...}, \"type\": \"movie\" }],\n \"shows\": [{ \"to\": \"watching\", \"ids\": {...}, \"type\": \"show\" }]\n },\n \"not_found\": {\n \"movies\": [{ \"title\": \"Definitely Not A Real Movie\", \"year\": 9999 }],\n \"shows\": []\n }\n}\n```\n\nItems the server's resolver matched land in `added`. Items it couldn't match (typos, fuzzy title misses, IDs not in Simkl's catalog yet) land in `not_found` — verbatim copies of the input so you can show \"we couldn't add: …\" in your UI. **Always inspect both arrays after a bulk call.**\n\nErrors: `400 empty_field` if `to` is missing on an item; `400 wrong_parameter` if `to` is not one of the values above.\n\n#### Silent `to` rewrites\n\nThe server may downgrade your requested `to` value when an item isn't in a state where that status applies:\n\n- **Movies** with `to: \"watching\"` → silently rewritten to `completed` (movies are atomic; you can't \"be watching\" a movie).\n- **Shows** that aren't ready for `completed` (still airing, or pre-release) get rewritten to `watching` or `plantowatch` respectively, depending on whether any episode has aired.\n\nThe rewrites happen server-side; the consumer just sees the actual stored value in `added.<type>[i].to`. There is **no error code** surfaced for the rewrite — the only way to detect it is to compare the value you sent against the value that came back.\n\n> Note: this endpoint operates on the Simkl **Watchlist** (the five canonical statuses above). Custom user-created lists will get their own API in a future release.\n\n<Card title=\"Sync guide — full walkthrough\" icon=\"arrows-rotate\" href=\"/guides/sync\" horizontal>\n Two-phase model (initial pull → activities-checked delta loop), `date_from` semantics, deletion reconciliation, edge cases, and reference implementations in Node and Python.\n</Card>\n\n**Anime titles:** can go in either the `anime[]` array OR the `shows[]` array — both are accepted. The server normalizes anime into the response's `shows` array with `\"type\": \"show\"` per-item, since anime are TV-like in the cross-catalog data model. AniDB-specific IDs (`mal`, `anidb`, `anilist`, `kitsu`) belong inside each item's `ids` object regardless of which array it lives in. See [Anime under shows[]](/conventions/standard-media-objects#anime).\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "movies": [
                  {
                    "title": "Terminator 3: Rise of the Machines",
                    "to": "completed",
                    "year": "2003",
                    "added_at": "2014-09-01T09:10:11.000Z",
                    "watched_at": "2014-10-10T22:10:00.000Z",
                    "ids": {
                      "imdb": "tt0181852",
                      "tmdb": "296",
                      "simkl": 53536
                    }
                  },
                  {
                    "to": "plantowatch",
                    "ids": {
                      "simkl": 210728
                    }
                  }
                ],
                "shows": [
                  {
                    "to": "watching",
                    "title": "Attack on Titan",
                    "year": 2013,
                    "ids": {
                      "simkl": 39687,
                      "mal": "16498",
                      "tvdb": "267440",
                      "imdb": "tt2560140",
                      "anidb": "9541"
                    }
                  },
                  {
                    "title": "The Walking Dead",
                    "year": 2010,
                    "to": "completed",
                    "ids": {
                      "simkl": 2090,
                      "tvdb": "153021",
                      "imdb": "tt1520211"
                    }
                  }
                ]
              },
              "schema": {
                "$ref": "#/components/schemas/AddToListRequest"
              },
              "examples": {
                "add_anime_completed": {
                  "summary": "Add an anime to `completed`",
                  "description": "Anime use the `anime` array key in the REQUEST body. (In responses, anime entries are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                  "value": {
                    "anime": [
                      {
                        "to": "completed",
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        }
                      }
                    ]
                  }
                },
                "add_anime_dropped": {
                  "summary": "Add an anime to `dropped`",
                  "description": "Anime use the `anime` array key in the REQUEST body. (In responses, anime entries are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                  "value": {
                    "anime": [
                      {
                        "to": "dropped",
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        }
                      }
                    ]
                  }
                },
                "add_anime_hold": {
                  "summary": "Add an anime to `hold`",
                  "description": "Anime use the `anime` array key in the REQUEST body. (In responses, anime entries are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                  "value": {
                    "anime": [
                      {
                        "to": "hold",
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        }
                      }
                    ]
                  }
                },
                "add_anime_plantowatch": {
                  "summary": "Add an anime to `plantowatch`",
                  "description": "Anime use the `anime` array key in the REQUEST body. (In responses, anime entries are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                  "value": {
                    "anime": [
                      {
                        "to": "plantowatch",
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        }
                      }
                    ]
                  }
                },
                "add_anime_watching": {
                  "summary": "Add an anime to `watching`",
                  "description": "Anime use the `anime` array key in the REQUEST body. (In responses, anime entries are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                  "value": {
                    "anime": [
                      {
                        "to": "watching",
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        }
                      }
                    ]
                  }
                },
                "add_movie_completed_per_item": {
                  "summary": "Add a single movie to `completed` (per-item `to`)",
                  "description": "Canonical body shape: media-type array of items, each with its own `to` field.",
                  "value": {
                    "movies": [
                      {
                        "to": "completed",
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "add_movie_dropped_per_item": {
                  "summary": "Add a single movie to `dropped` (per-item `to`)",
                  "description": "Canonical body shape: media-type array of items, each with its own `to` field.",
                  "value": {
                    "movies": [
                      {
                        "to": "dropped",
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "add_movie_plantowatch_per_item": {
                  "summary": "Add a single movie to `plantowatch` (per-item `to`)",
                  "description": "Canonical body shape: media-type array of items, each with its own `to` field.",
                  "value": {
                    "movies": [
                      {
                        "to": "plantowatch",
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "add_show_completed": {
                  "summary": "Add a TV show to `completed`",
                  "description": "TV shows accept all 5 watchlist statuses (movies are restricted to plantowatch/completed/dropped).",
                  "value": {
                    "shows": [
                      {
                        "to": "completed",
                        "ids": {
                          "simkl": 2090
                        }
                      }
                    ]
                  }
                },
                "add_show_dropped": {
                  "summary": "Add a TV show to `dropped`",
                  "description": "TV shows accept all 5 watchlist statuses (movies are restricted to plantowatch/completed/dropped).",
                  "value": {
                    "shows": [
                      {
                        "to": "dropped",
                        "ids": {
                          "simkl": 2090
                        }
                      }
                    ]
                  }
                },
                "add_show_hold": {
                  "summary": "Add a TV show to `hold`",
                  "description": "TV shows accept all 5 watchlist statuses (movies are restricted to plantowatch/completed/dropped).",
                  "value": {
                    "shows": [
                      {
                        "to": "hold",
                        "ids": {
                          "simkl": 2090
                        }
                      }
                    ]
                  }
                },
                "add_show_plantowatch": {
                  "summary": "Add a TV show to `plantowatch`",
                  "description": "TV shows accept all 5 watchlist statuses (movies are restricted to plantowatch/completed/dropped).",
                  "value": {
                    "shows": [
                      {
                        "to": "plantowatch",
                        "ids": {
                          "simkl": 2090
                        }
                      }
                    ]
                  }
                },
                "add_show_watching": {
                  "summary": "Add a TV show to `watching`",
                  "description": "TV shows accept all 5 watchlist statuses (movies are restricted to plantowatch/completed/dropped).",
                  "value": {
                    "shows": [
                      {
                        "to": "watching",
                        "ids": {
                          "simkl": 2090
                        }
                      }
                    ]
                  }
                },
                "bulk_add_cross_media_types": {
                  "summary": "Bulk add across all three media types in one request",
                  "description": "The body can carry `movies`, `shows`, and `anime` arrays simultaneously. Each is processed independently; the response aggregates the per-bucket counts.",
                  "value": {
                    "movies": [
                      {
                        "to": "plantowatch",
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ],
                    "shows": [
                      {
                        "to": "watching",
                        "ids": {
                          "simkl": 1203662
                        }
                      }
                    ],
                    "anime": [
                      {
                        "to": "completed",
                        "ids": {
                          "simkl": 37089,
                          "mal": "1",
                          "anidb": "23",
                          "anilist": "1"
                        }
                      }
                    ]
                  }
                },
                "bulk_add_movies_mixed_statuses": {
                  "summary": "Bulk add movies with per-item statuses",
                  "description": "Most efficient way to seed a user's library after import: send all items in one request, each with its own `to`. The server processes each item independently and the response counts all successes. NB: per-item `to` is the canonical shape — top-level `to` is a legacy fallback default.",
                  "value": {
                    "movies": [
                      {
                        "to": "completed",
                        "ids": {
                          "simkl": 472214
                        }
                      },
                      {
                        "to": "plantowatch",
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "change_movie_status": {
                  "summary": "Move an existing item to a new status",
                  "description": "Same body shape as initial-add. The server updates the existing row instead of duplicating it. Use this to move plantowatch → completed when a user finishes a movie they had on their list.",
                  "value": {
                    "movies": [
                      {
                        "to": "completed",
                        "ids": {
                          "simkl": 472214
                        }
                      }
                    ]
                  }
                },
                "negative_top_level_to_rejected": {
                  "summary": "REJECTED: `to` at top level alone (without per-item `to`)",
                  "description": "**This shape is wrong** — the inherited apiary spec showed it as canonical, but the live server rejects it with `400 empty_field` (`Missed \"to\" parameter`). Per-item `to` is required.",
                  "value": {
                    "to": "plantowatch",
                    "movies": [
                      {
                        "ids": {
                          "simkl": 472214
                        }
                      }
                    ]
                  }
                },
                "quirk_movies_with_watching_status": {
                  "summary": "Quirk: server silently rewrites `watching` → `completed` for movies",
                  "description": "Movies are documented as not supporting `watching`/`hold` (see /conventions/list-statuses). The server silently rewrites the requested `watching` to `completed` After the request, the movie's status is `'completed'`.",
                  "value": {
                    "movies": [
                      {
                        "to": "watching",
                        "ids": {
                          "simkl": 472214
                        }
                      }
                    ]
                  }
                },
                "add_anime_full_id_set": {
                  "summary": "Add an anime with the full anime-catalog ID set",
                  "description": "Anime have a richer canonical ID set than movies/shows: `mal` (MyAnimeList) + `anidb` (AniDB) + `anilist` + `kitsu` — in addition to the cross-catalog IDs (`simkl`, `imdb`, `tmdb`, `tvdb`). Send everything you have.",
                  "value": {
                    "anime": [
                      {
                        "to": "watching",
                        "title": "Kimetsu no Yaiba",
                        "year": 2019,
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14107",
                          "anilist": "101922",
                          "kitsu": "41370"
                        }
                      }
                    ]
                  }
                },
                "add_anime_via_mal_only": {
                  "summary": "Add an anime using ONLY its MyAnimeList ID",
                  "description": "MAL is the most-used anime ID. AniDB / AniList / Kitsu work identically — pass them inside `ids` and the server resolves. No simkl_id required.",
                  "value": {
                    "anime": [
                      {
                        "to": "plantowatch",
                        "ids": {
                          "mal": "38000"
                        }
                      }
                    ]
                  }
                },
                "add_movie_via_imdb_only": {
                  "summary": "Add a movie using ONLY its IMDb ID (no simkl_id needed)",
                  "description": "**The simkl_id is not required.** The server resolves any ID combination internally. Pass whatever IDs your app already has — IMDb, TMDB, TVDB, MAL, AniDB, AniList, Kitsu — alone or in combination. No need to call `/redirect` first.",
                  "value": {
                    "movies": [
                      {
                        "to": "plantowatch",
                        "ids": {
                          "imdb": "tt1375666"
                        }
                      }
                    ]
                  }
                },
                "add_movie_via_title_year_only": {
                  "summary": "Add a movie using ONLY title + year (no IDs at all)",
                  "description": "When you don't have ANY external ID, the server can match by `title` + `year`. The match is fuzzy and may miss for ambiguous titles — items that don't resolve land in `not_found` rather than `added`, so always inspect the response. Useful for spreadsheet/OCR/voice-assistant backfill flows.",
                  "value": {
                    "movies": [
                      {
                        "to": "plantowatch",
                        "title": "Inception",
                        "year": 2010
                      }
                    ]
                  }
                },
                "add_movie_via_tmdb_only": {
                  "summary": "Add a movie using ONLY its TMDB ID",
                  "description": "Same as the imdb-only example: the server resolves the TMDB ID server-side; no need to know the simkl_id first. Common for apps integrating with Plex, Jellyfin, Stremio, etc., where TMDB is the primary metadata source.",
                  "value": {
                    "movies": [
                      {
                        "to": "plantowatch",
                        "ids": {
                          "tmdb": "27205"
                        }
                      }
                    ]
                  }
                },
                "add_show_full_id_set_plus_title_year": {
                  "summary": "Add with the full ID set + title + year (canonical maximal shape)",
                  "description": "Defensive: send EVERY identifier you have. The server picks the first that resolves and accepts the extras. Use this shape when importing from another tracker that already carried multiple IDs — no need to drop any. Useful for Trakt → Simkl migrations, IMDb-list imports, etc. `slug` is response-only — never send it; see [Standard media objects → Supported ID keys](/conventions/standard-media-objects#supported-id-keys).",
                  "value": {
                    "shows": [
                      {
                        "to": "completed",
                        "title": "Game of Thrones",
                        "year": 2011,
                        "ids": {
                          "simkl": 17465,
                          "imdb": "tt0944947",
                          "tmdb": "1399",
                          "tvdb": "121361"
                        }
                      }
                    ]
                  }
                },
                "add_show_via_tvdb_only": {
                  "summary": "Add a TV show using ONLY its TVDB ID",
                  "description": "TVDB is the most-used canonical ID for TV in media-server stacks (Plex, Sonarr, Jellyfin, Kodi). No simkl_id needed.",
                  "value": {
                    "shows": [
                      {
                        "to": "watching",
                        "ids": {
                          "tvdb": "153021"
                        }
                      }
                    ]
                  }
                },
                "add_unresolvable_lands_in_not_found": {
                  "summary": "PARTIAL SUCCESS: items that don't resolve land in `not_found`",
                  "description": "When the server can't resolve an item to any catalog record, the request still returns 201 — but the item lands in `response.not_found.<media_type>` instead of `response.added.<media_type>`. Always inspect both arrays after a bulk call.",
                  "value": {
                    "movies": [
                      {
                        "to": "plantowatch",
                        "title": "ZZZ-Definitely-Not-A-Real-Movie-Title-XYZ",
                        "year": 9999
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddToListResponse"
                },
                "example": {
                  "added": {
                    "movies": [
                      {
                        "title": "Terminator 3: Rise of the Machines",
                        "to": "completed",
                        "year": "2003",
                        "added_at": "2014-09-01T09:10:11.000Z",
                        "watched_at": "2014-10-10T22:10:00.000Z",
                        "ids": {
                          "imdb": "tt0181852",
                          "tmdb": "296",
                          "simkl": 53536
                        }
                      },
                      {
                        "to": "plantowatch",
                        "ids": {
                          "simkl": 210728
                        }
                      }
                    ],
                    "shows": [
                      {
                        "to": "watching",
                        "title": "Attack on Titan",
                        "year": 2013,
                        "ids": {
                          "simkl": 39687,
                          "mal": "16498",
                          "tvdb": "267440",
                          "imdb": "tt2560140",
                          "anidb": "9541"
                        }
                      },
                      {
                        "title": "The Walking Dead",
                        "year": 2010,
                        "to": "watching",
                        "ids": {
                          "simkl": 2090,
                          "tvdb": "153021",
                          "imdb": "tt1520211"
                        }
                      }
                    ]
                  },
                  "not_found": {
                    "movies": [
                      {
                        "ids": {
                          "imdb": "tt0000222"
                        }
                      }
                    ],
                    "shows": []
                  }
                },
                "examples": {
                  "add_anime_completed": {
                    "summary": "Add an anime to `completed`",
                    "description": "Anime use the `anime` array key in the REQUEST body. (In responses, anime entries are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "completed",
                            "ids": {
                              "simkl": 831411,
                              "mal": "38000",
                              "anidb": "14116",
                              "anilist": "101922"
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_anime_dropped": {
                    "summary": "Add an anime to `dropped`",
                    "description": "Anime use the `anime` array key in the REQUEST body. (In responses, anime entries are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "dropped",
                            "ids": {
                              "simkl": 831411,
                              "mal": "38000",
                              "anidb": "14116",
                              "anilist": "101922"
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_anime_hold": {
                    "summary": "Add an anime to `hold`",
                    "description": "Anime use the `anime` array key in the REQUEST body. (In responses, anime entries are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "hold",
                            "ids": {
                              "simkl": 831411,
                              "mal": "38000",
                              "anidb": "14116",
                              "anilist": "101922"
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_anime_plantowatch": {
                    "summary": "Add an anime to `plantowatch`",
                    "description": "Anime use the `anime` array key in the REQUEST body. (In responses, anime entries are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "plantowatch",
                            "ids": {
                              "simkl": 831411,
                              "mal": "38000",
                              "anidb": "14116",
                              "anilist": "101922"
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_anime_watching": {
                    "summary": "Add an anime to `watching`",
                    "description": "Anime use the `anime` array key in the REQUEST body. (In responses, anime entries are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "watching",
                            "ids": {
                              "simkl": 831411,
                              "mal": "38000",
                              "anidb": "14116",
                              "anilist": "101922"
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_movie_completed_per_item": {
                    "summary": "Add a single movie to `completed` (per-item `to`)",
                    "description": "Canonical body shape: media-type array of items, each with its own `to` field.",
                    "value": {
                      "added": {
                        "movies": [
                          {
                            "to": "completed",
                            "ids": {
                              "simkl": 752138
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_movie_dropped_per_item": {
                    "summary": "Add a single movie to `dropped` (per-item `to`)",
                    "description": "Canonical body shape: media-type array of items, each with its own `to` field.",
                    "value": {
                      "added": {
                        "movies": [
                          {
                            "to": "dropped",
                            "ids": {
                              "simkl": 752138
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_movie_plantowatch_per_item": {
                    "summary": "Add a single movie to `plantowatch` (per-item `to`)",
                    "description": "Canonical body shape: media-type array of items, each with its own `to` field.",
                    "value": {
                      "added": {
                        "movies": [
                          {
                            "to": "plantowatch",
                            "ids": {
                              "simkl": 752138
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_show_completed": {
                    "summary": "Add a TV show to `completed`",
                    "description": "TV shows accept all 5 watchlist statuses (movies are restricted to plantowatch/completed/dropped).",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "completed",
                            "ids": {
                              "simkl": 2090
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_show_dropped": {
                    "summary": "Add a TV show to `dropped`",
                    "description": "TV shows accept all 5 watchlist statuses (movies are restricted to plantowatch/completed/dropped).",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "dropped",
                            "ids": {
                              "simkl": 2090
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_show_hold": {
                    "summary": "Add a TV show to `hold`",
                    "description": "TV shows accept all 5 watchlist statuses (movies are restricted to plantowatch/completed/dropped).",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "hold",
                            "ids": {
                              "simkl": 2090
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_show_plantowatch": {
                    "summary": "Add a TV show to `plantowatch`",
                    "description": "TV shows accept all 5 watchlist statuses (movies are restricted to plantowatch/completed/dropped).",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "plantowatch",
                            "ids": {
                              "simkl": 2090
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_show_watching": {
                    "summary": "Add a TV show to `watching`",
                    "description": "TV shows accept all 5 watchlist statuses (movies are restricted to plantowatch/completed/dropped).",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "watching",
                            "ids": {
                              "simkl": 2090
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "bulk_add_cross_media_types": {
                    "summary": "Bulk add across all three media types in one request",
                    "description": "The body can carry `movies`, `shows`, and `anime` arrays simultaneously. Each is processed independently; the response aggregates the per-bucket counts.",
                    "value": {
                      "added": {
                        "movies": [
                          {
                            "to": "plantowatch",
                            "ids": {
                              "simkl": 752138
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": [
                          {
                            "to": "watching",
                            "ids": {
                              "simkl": 1203662
                            },
                            "type": "show"
                          },
                          {
                            "to": "completed",
                            "ids": {
                              "simkl": 37089,
                              "mal": "1",
                              "anidb": "23",
                              "anilist": "1"
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "bulk_add_movies_mixed_statuses": {
                    "summary": "Bulk add movies with per-item statuses",
                    "description": "Most efficient way to seed a user's library after import: send all items in one request, each with its own `to`. The server processes each item independently and the response counts all successes. NB: per-item `to` is the canonical shape — top-level `to` is a legacy fallback default.",
                    "value": {
                      "added": {
                        "movies": [
                          {
                            "to": "completed",
                            "ids": {
                              "simkl": 472214
                            },
                            "type": "movie"
                          },
                          {
                            "to": "plantowatch",
                            "ids": {
                              "simkl": 752138
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "change_movie_status": {
                    "summary": "Move an existing item to a new status",
                    "description": "Same body shape as initial-add. The server updates the existing row instead of duplicating it. Use this to move plantowatch → completed when a user finishes a movie they had on their list.",
                    "value": {
                      "added": {
                        "movies": [
                          {
                            "to": "completed",
                            "ids": {
                              "simkl": 472214
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "quirk_movies_with_watching_status": {
                    "summary": "Quirk: server silently rewrites `watching` → `completed` for movies",
                    "description": "Movies are documented as not supporting `watching`/`hold` (see /conventions/list-statuses). The server silently rewrites the requested `watching` to `completed` After the request, the movie's status is `'completed'`.",
                    "value": {
                      "added": {
                        "movies": [
                          {
                            "to": "watching",
                            "ids": {
                              "simkl": 472214
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_anime_full_id_set": {
                    "summary": "Add an anime with the full anime-catalog ID set",
                    "description": "Anime have a richer canonical ID set than movies/shows: `mal` (MyAnimeList) + `anidb` (AniDB) + `anilist` + `kitsu` — in addition to the cross-catalog IDs (`simkl`, `imdb`, `tmdb`, `tvdb`). Send everything you have.",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "watching",
                            "title": "Kimetsu no Yaiba",
                            "year": 2019,
                            "ids": {
                              "simkl": 831411,
                              "mal": "38000",
                              "anidb": "14107",
                              "anilist": "101922",
                              "kitsu": "41370"
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_anime_via_mal_only": {
                    "summary": "Add an anime using ONLY its MyAnimeList ID",
                    "description": "MAL is the most-used anime ID. AniDB / AniList / Kitsu work identically — pass them inside `ids` and the server resolves. No simkl_id required.",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "plantowatch",
                            "ids": {
                              "mal": "38000"
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_movie_via_imdb_only": {
                    "summary": "Add a movie using ONLY its IMDb ID (no simkl_id needed)",
                    "description": "**The simkl_id is not required.** The server resolves any ID combination internally. Pass whatever IDs your app already has — IMDb, TMDB, TVDB, MAL, AniDB, AniList, Kitsu — alone or in combination. No need to call `/redirect` first.",
                    "value": {
                      "added": {
                        "movies": [
                          {
                            "to": "plantowatch",
                            "ids": {
                              "imdb": "tt1375666"
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_movie_via_title_year_only": {
                    "summary": "Add a movie using ONLY title + year (no IDs at all)",
                    "description": "When you don't have ANY external ID, the server can match by `title` + `year`. The match is fuzzy and may miss for ambiguous titles — items that don't resolve land in `not_found` rather than `added`, so always inspect the response. Useful for spreadsheet/OCR/voice-assistant backfill flows.",
                    "value": {
                      "added": {
                        "movies": [
                          {
                            "to": "plantowatch",
                            "title": "Inception",
                            "year": 2010,
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_movie_via_tmdb_only": {
                    "summary": "Add a movie using ONLY its TMDB ID",
                    "description": "Same as the imdb-only example: the server resolves the TMDB ID server-side; no need to know the simkl_id first. Common for apps integrating with Plex, Jellyfin, Stremio, etc., where TMDB is the primary metadata source.",
                    "value": {
                      "added": {
                        "movies": [
                          {
                            "to": "plantowatch",
                            "ids": {
                              "tmdb": "27205"
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_show_full_id_set_plus_title_year": {
                    "summary": "Add with the full ID set + title + year (canonical maximal shape)",
                    "description": "Defensive: send EVERY identifier you have. The server picks the first that resolves and accepts the extras. Use this shape when importing from another tracker that already carried multiple IDs — no need to drop any. Useful for Trakt → Simkl migrations, IMDb-list imports, etc.",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "completed",
                            "title": "Game of Thrones",
                            "year": 2011,
                            "ids": {
                              "simkl": 17465,
                              "slug": "game-of-thrones",
                              "imdb": "tt0944947",
                              "tmdb": "1399",
                              "tvdb": "121361"
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_show_via_tvdb_only": {
                    "summary": "Add a TV show using ONLY its TVDB ID",
                    "description": "TVDB is the most-used canonical ID for TV in media-server stacks (Plex, Sonarr, Jellyfin, Kodi). No simkl_id needed.",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": [
                          {
                            "to": "watching",
                            "ids": {
                              "tvdb": "153021"
                            },
                            "type": "show"
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "add_unresolvable_lands_in_not_found": {
                    "summary": "PARTIAL SUCCESS: items that don't resolve land in `not_found`",
                    "description": "When the server can't resolve an item to any catalog record, the request still returns 201 — but the item lands in `response.not_found.<media_type>` instead of `response.added.<media_type>`. Always inspect both arrays after a bulk call.",
                    "value": {
                      "added": {
                        "movies": [],
                        "shows": []
                      },
                      "not_found": {
                        "movies": [
                          {
                            "to": "plantowatch",
                            "title": "ZZZ-Definitely-Not-A-Real-Movie-Title-XYZ",
                            "year": 9999,
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest",
            "content": {
              "application/json": {
                "examples": {
                  "negative_top_level_to_rejected": {
                    "summary": "REJECTED: `to` at top level alone (without per-item `to`)",
                    "description": "**This shape is wrong** — the inherited apiary spec showed it as canonical, but the live server rejects it with `400 empty_field` (`Missed \"to\" parameter`). Per-item `to` is required.",
                    "value": {
                      "error": "empty_field",
                      "code": 400,
                      "message": "Missed \"to\" parameter"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/add-to-list",
          "metadata": {
            "sidebarTitle": "Add to Watchlist"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/sync/all-items/{type}/{status}": {
      "get": {
        "operationId": "get-sync-all-items-type-status",
        "summary": "Get all items of one type in one status bucket",
        "description": "> ## ⚠️ For continuous sync, do NOT call `/sync/all-items` on a timer\n>\n> The correct loop, every time you want to check for changes:\n>\n> 1. **Call [`GET /sync/activities`](/api-reference/simkl/get-activities) first.** It returns a tiny JSON of `last-modified` timestamps per category — costs almost nothing.\n> 2. **Compare those timestamps to the ones you saved on your last sync.** If nothing changed, stop here. Do **not** call `/sync/all-items`.\n> 3. **Only if a timestamp changed**, call `/sync/all-items?date_from=<your-last-sync-timestamp>`. The `date_from` makes the server return only the small delta of items that actually changed, not the user's entire library.\n>\n> Polling `/sync/all-items` directly on a timer (without checking `/sync/activities` and without `date_from`) downloads the user's whole library every call. It overloads the API server and hurts every other client.\n>\n> **Apps that do this will have their `client_id` suspended.** No warning, no appeal — we see the traffic pattern and turn the key off.\n>\n> Read the [**Sync guide**](/guides/sync) end-to-end before shipping anything that calls this endpoint. The full two-phase model (initial full sync → activities-checked delta loop) is documented there with reference implementations in Node and Python.\n\n<CardGroup cols={2}>\n <Card title=\"Sync guide\" icon=\"arrows-rotate\" href=\"/guides/sync\">\n The two-phase model (initial pull → activities-checked delta loop), `date_from` semantics, deletion reconciliation, edge cases, and reference implementations in Node and Python. **Required reading** before shipping anything that polls this endpoint.\n </Card>\n <Card title=\"Rewatches guide\" icon=\"rotate\" href=\"/guides/rewatches\">\n Session lifecycle (`active` / `completed` / `closed`), per-item rewatch fields, episode-level tracking, flag combinations for reading sessions back, and ready-made code for the UI patterns simkl.com uses on every detail page. Required if you set `?allow_rewatch=yes`.\n </Card>\n</CardGroup>\n\nThe single endpoint that powers watchlist reads. Both `{type}` and `{status}` are optional path segments, and any combination is valid:\n\n| Path | Returns |\n| --- | --- |\n| `/sync/all-items` | Every type, every status. The full library. |\n| `/sync/all-items/{type}` | A single type (`shows`, `movies`, or `anime`), every status. |\n| `/sync/all-items/{type}/{status}` | One type, one status bucket. |\n\nThe response shape is the same across all three forms: a top-level object keyed by `shows`, `movies`, and `anime`. Filtered calls just include fewer top-level keys; an empty result returns `{}`. See [Per-endpoint shape matrix](/conventions/null-values#per-endpoint-shape-matrix).\n\nPair this endpoint with [`GET /sync/activities`](/api-reference/simkl/get-activities) and the `date_from` query parameter for incremental sync — see the [Sync guide](/guides/sync) for the two-phase model.\n\n**Watchlist statuses by type:**\n\n| Type | `watching` | `plantowatch` | `hold` | `dropped` | `completed` |\n|------|:-:|:-:|:-:|:-:|:-:|\n| `shows` | ✅ | ✅ | ✅ | ✅ | ✅ |\n| `anime` | ✅ | ✅ | ✅ | ✅ | ✅ |\n| `movies` | — | ✅ | — | ✅ | ✅ |\n\nMovies skip `watching` and `hold` — see [Watchlist statuses](/conventions/list-statuses).\n\n#### Useful query parameters\n\nA quick map of the params below — see each parameter's full schema later on this page.\n\n| Param | What it does |\n|---|---|\n| `date_from` | Required on every continuous-sync call. Returns only items modified since this ISO-8601 timestamp. |\n| `extended=simkl_ids_only` / `=ids_only` / `=full` / `=full_anime_seasons` | Controls response richness — from just `ids.simkl` (smallest) up to per-episode breakdowns. `=full` is **required** for `seasons[].episodes[]` and is the only value that adds `runtime`; it does **not** add `overview` / `fanart` / `genres` / `ratings` (use the detail endpoints for catalog metadata). Pair `=full` and `=full_anime_seasons` with `date_from` — they're significantly larger payloads. |\n| `include_all_episodes=yes` / `=original` | **Requires `extended=full`** (no effect on its own). Loads `seasons[].episodes[]` for items in `completed` and `dropped` too (which skip episode load by default). `yes` fills in virtual episode rows — stamped with the show's last-watched time — where per-episode data is missing; `original` returns only the episodes the user actually recorded, which can be fewer than `watched_episodes_count` for a show marked complete in one action. |\n| `episode_watched_at=yes` | Adds per-episode `watched_at` timestamps to every loaded episode. **Requires `extended=full`** — episodes must be loaded first, so on its own it does nothing. |\n| `episode_tvdb_id=yes` | Adds `ids.tvdb_id` per episode. |\n| `next_watch_info=yes` | On `watching` items with a next episode, attaches `next_to_watch_info` (`title`, `season`, `episode`, `date`). |\n| `memos=yes` | Includes the user's per-item `memo` object (`text` capped at 140 chars). |\n| `anime_type=movies` | Restrict the `anime` results to the anime-movie subtype. `movies` is the only accepted value — it's a subtype filter, not a full type selector. (The per-item `anime_type` **response** field still carries the full vocabulary: `tv`, `movie`, `ova`, `ona`, `special`, `music video`.) |\n| `language=en` | Force English titles instead of the user's profile language. |\n| `allow_rewatch=yes` | Synthesize one extra entry per rewatch session alongside the canonical row. **Simkl Pro / VIP only** — gate the flag on `account.type` from [`POST /users/settings`](/api-reference/simkl/get-user-settings) (cache it; refetch only when `activities.settings.all` bumps — see [Rewatches guide → Pro / VIP gate](/guides/rewatches)). Free-tier callers get a silent no-op that still consumes a rate-limit slot. See the [Rewatches guide](/guides/rewatches) for the full pattern. |\n\n**Rewatches** (Simkl Pro / VIP). Without the flag, each item — movie, show, or anime — appears once in the response, reflecting the user's current watch state. Set `?allow_rewatch=yes` and any item with saved rewatch sessions appears multiple times: the normal entry, plus one extra entry per rewatch session. The extra entries carry `is_rewatch: true`, `rewatch_id`, `rewatch_status` (`active` / `completed` / `closed`), `last_watched_at`, and `watched_episodes_count`, so you can tell them apart from the main entry and from each other.\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "name": "type",
            "in": "path",
            "description": "One of `shows`, `movies`, `anime`, or `all`. Pass `all` to skip filtering on type even when the runtime accepts the segment-less form, so for spec strictness this is `true`. To call without it in practice, just drop the segment from the URL.",
            "schema": {
              "type": "string",
              "enum": [
                "movies",
                "shows",
                "anime",
                "all"
              ],
              "example": "all"
            },
            "required": true,
            "examples": {
              "phase1_initial_full_pull": {
                "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                "value": "all"
              },
              "phase2_incremental_delta": {
                "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                "value": "all"
              },
              "movies_completed_filtered": {
                "summary": "Path filter — only completed movies",
                "value": "movies"
              },
              "watching_with_next_to_watch_info": {
                "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                "value": "shows"
              },
              "extended_full_with_seasons": {
                "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                "value": "shows"
              },
              "anime_with_mapped_tvdb_seasons": {
                "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                "value": "anime"
              },
              "simkl_ids_only_minimal": {
                "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                "value": "all"
              },
              "ids_only_with_externals": {
                "summary": "extended=ids_only — all external IDs, no per-show metadata",
                "value": "movies"
              },
              "rewatches_via_allow_rewatch": {
                "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                "value": "all"
              },
              "all_modifiers_inspection_only": {
                "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                "value": "all"
              }
            }
          },
          {
            "name": "status",
            "in": "path",
            "description": "One of `watching`, `plantowatch`, `hold`, `completed`, `dropped`, or `all`. Movies accept only `plantowatch`, `completed`, `dropped`, and `all`; TV and anime accept all six. Pass `all` to skip filtering on status — `/sync/all-items/{type}/all` returns every status for that type.",
            "schema": {
              "$ref": "#/components/schemas/WatchlistStatus",
              "enum": [
                "watching",
                "plantowatch",
                "hold",
                "completed",
                "dropped",
                "all"
              ],
              "example": "all"
            },
            "required": true,
            "examples": {
              "phase1_initial_full_pull": {
                "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                "value": "all"
              },
              "phase2_incremental_delta": {
                "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                "value": "all"
              },
              "movies_completed_filtered": {
                "summary": "Path filter — only completed movies",
                "value": "completed"
              },
              "watching_with_next_to_watch_info": {
                "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                "value": "watching"
              },
              "extended_full_with_seasons": {
                "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                "value": "watching"
              },
              "anime_with_mapped_tvdb_seasons": {
                "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                "value": "completed"
              },
              "simkl_ids_only_minimal": {
                "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                "value": "all"
              },
              "ids_only_with_externals": {
                "summary": "extended=ids_only — all external IDs, no per-show metadata",
                "value": "completed"
              },
              "rewatches_via_allow_rewatch": {
                "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                "value": "completed"
              },
              "all_modifiers_inspection_only": {
                "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                "value": "all"
              }
            }
          },
          {
            "name": "allow_rewatch",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "no"
              ],
              "default": "no"
            },
            "description": "Opt into rewatch tracking. When `yes`, `POST /sync/history` records an additional rewatch session instead of being a no-op for already-watched items, and `GET /sync/all-items` returns one extra entry per saved rewatch session alongside the item's normal entry. Available to Simkl **Pro** and **VIP** users — non-Pro callers see no effect even with the flag set.\n\n⚠️ **Do not enable this flag until you've read the [Rewatches guide](/guides/rewatches) end-to-end and implemented the precautions.** Used carelessly (on retries, on every scrobble event, on importer re-runs, without pinning `rewatch_id` after the first write), it will pollute the user's history stats and rewatches panel with phantom sessions. The flag should be gated behind explicit user intent — a dedicated \"Rewatch\" button — never on background or automated flows. Also expose a per-user *Track rewatches* toggle in your app's settings (default off) — not every user wants the rewatch-session complexity.\n\nLimits: up to **50 rewatches per item** (movie, show, or anime), and any two watch events on the **same item** (movie or episode) must be at least **2 days apart** — a new rewatch within 48 hours of the previous watch of that same item collapses into the same session (it's a rewatch, not a rewind 😄). Full walkthrough — session lifecycle (`active` / `completed` / `closed` with bidirectional transitions), episode-level tracking, reading sessions back from `GET /sync/all-items`, and ready-made code for simkl.com-style UI patterns — in the [Rewatches guide](/guides/rewatches).",
            "examples": {
              "phase1_initial_full_pull": {
                "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                "value": "no"
              },
              "phase2_incremental_delta": {
                "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                "value": "no"
              },
              "movies_completed_filtered": {
                "summary": "Path filter — only completed movies",
                "value": "no"
              },
              "watching_with_next_to_watch_info": {
                "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                "value": "no"
              },
              "extended_full_with_seasons": {
                "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                "value": "no"
              },
              "anime_with_mapped_tvdb_seasons": {
                "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                "value": "no"
              },
              "simkl_ids_only_minimal": {
                "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                "value": "no"
              },
              "ids_only_with_externals": {
                "summary": "extended=ids_only — all external IDs, no per-show metadata",
                "value": "no"
              },
              "rewatches_via_allow_rewatch": {
                "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                "value": "yes"
              },
              "all_modifiers_inspection_only": {
                "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                "value": "yes"
              }
            }
          },
          {
            "name": "date_from",
            "in": "query",
            "required": false,
            "description": "ISO-8601 timestamp. Returns only items updated since this time. Use the value saved from `/sync/activities`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "examples": {
              "phase1_initial_full_pull": {
                "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                "value": ""
              },
              "phase2_incremental_delta": {
                "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                "value": "2026-05-14T00:00:00Z"
              },
              "movies_completed_filtered": {
                "summary": "Path filter — only completed movies",
                "value": ""
              },
              "watching_with_next_to_watch_info": {
                "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                "value": ""
              },
              "extended_full_with_seasons": {
                "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                "value": ""
              },
              "anime_with_mapped_tvdb_seasons": {
                "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                "value": ""
              },
              "simkl_ids_only_minimal": {
                "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                "value": ""
              },
              "ids_only_with_externals": {
                "summary": "extended=ids_only — all external IDs, no per-show metadata",
                "value": ""
              },
              "rewatches_via_allow_rewatch": {
                "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                "value": ""
              },
              "all_modifiers_inspection_only": {
                "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                "value": ""
              }
            }
          },
          {
            "name": "extended",
            "in": "query",
            "description": "Controls response richness. Omit for the default (summary fields only — status, counters, `last_watched` / `next_to_watch` markers, no episode arrays).\n\n- `simkl_ids_only` — smallest payload: just `ids.simkl` per item. Ideal for the deletion-reconciliation diff in continuous sync.\n- `ids_only` — same, plus external IDs (`imdb`, `tmdb`, `tvdb`, `mal`, …).\n- `full` — **required to get the per-episode `seasons[].episodes[]` arrays**; without it, `episode_watched_at` and `include_all_episodes` do nothing. Necessary but not always sufficient: on its own it loads episodes for `watching` / `hold` / `plantowatch` items only — `completed` and `dropped` additionally need `include_all_episodes`. The only extra *metadata* field it adds is `runtime`.\n- `full_anime_seasons` — like `full`, plus TVDB season/episode mapping on anime (`mapped_tvdb_seasons` at the show level, a `tvdb` block per episode).\n\n**This endpoint does not return `overview`, `fanart`, `genres`, or `ratings` at any `extended` value** — it returns watch state plus a compact item stub (`title`, `poster`, `year`, `ids`, and `runtime` on `full`). For catalog metadata, call the detail endpoints ([`/movies/{id}`](/api-reference/simkl/get-movie), [`/tv/{id}`](/api-reference/simkl/get-tv-show), [`/anime/{id}`](/api-reference/simkl/get-anime)).\n\nLarge payload on `full` / `full_anime_seasons` — pair with `date_from` for continuous sync. The one expected full-library use is a one-time episode baseline on first sync (see the [Sync guide → Phase 1](/guides/sync#phase-1-initial-sync)).",
            "schema": {
              "type": "string",
              "enum": [
                "full",
                "full_anime_seasons",
                "simkl_ids_only",
                "ids_only"
              ]
            },
            "examples": {
              "phase1_initial_full_pull": {
                "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                "value": "no"
              },
              "phase2_incremental_delta": {
                "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                "value": "full"
              },
              "movies_completed_filtered": {
                "summary": "Path filter — only completed movies",
                "value": "no"
              },
              "watching_with_next_to_watch_info": {
                "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                "value": "no"
              },
              "extended_full_with_seasons": {
                "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                "value": "full"
              },
              "anime_with_mapped_tvdb_seasons": {
                "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                "value": "full_anime_seasons"
              },
              "simkl_ids_only_minimal": {
                "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                "value": "simkl_ids_only"
              },
              "ids_only_with_externals": {
                "summary": "extended=ids_only — all external IDs, no per-show metadata",
                "value": "ids_only"
              },
              "rewatches_via_allow_rewatch": {
                "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                "value": "full"
              },
              "all_modifiers_inspection_only": {
                "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                "value": "full_anime_seasons"
              }
            }
          },
          {
            "name": "next_watch_info",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes"
              ]
            },
            "description": "When `yes`, attaches a `next_to_watch_info` object to each watched item, indicating the next episode to watch.",
            "examples": {
              "phase1_initial_full_pull": {
                "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                "value": "no"
              },
              "phase2_incremental_delta": {
                "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                "value": "no"
              },
              "movies_completed_filtered": {
                "summary": "Path filter — only completed movies",
                "value": "no"
              },
              "watching_with_next_to_watch_info": {
                "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                "value": "yes"
              },
              "extended_full_with_seasons": {
                "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                "value": "no"
              },
              "anime_with_mapped_tvdb_seasons": {
                "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                "value": "no"
              },
              "simkl_ids_only_minimal": {
                "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                "value": "no"
              },
              "ids_only_with_externals": {
                "summary": "extended=ids_only — all external IDs, no per-show metadata",
                "value": "no"
              },
              "rewatches_via_allow_rewatch": {
                "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                "value": "no"
              },
              "all_modifiers_inspection_only": {
                "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                "value": "yes"
              }
            }
          },
          {
            "name": "episode_tvdb_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes"
              ]
            },
            "description": "When `yes`, includes TVDB IDs on each episode in episode-bearing responses.",
            "examples": {
              "phase1_initial_full_pull": {
                "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                "value": "no"
              },
              "phase2_incremental_delta": {
                "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                "value": "no"
              },
              "movies_completed_filtered": {
                "summary": "Path filter — only completed movies",
                "value": "no"
              },
              "watching_with_next_to_watch_info": {
                "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                "value": "no"
              },
              "extended_full_with_seasons": {
                "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                "value": "no"
              },
              "anime_with_mapped_tvdb_seasons": {
                "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                "value": "no"
              },
              "simkl_ids_only_minimal": {
                "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                "value": "no"
              },
              "ids_only_with_externals": {
                "summary": "extended=ids_only — all external IDs, no per-show metadata",
                "value": "no"
              },
              "rewatches_via_allow_rewatch": {
                "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                "value": "no"
              },
              "all_modifiers_inspection_only": {
                "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                "value": "yes"
              }
            }
          },
          {
            "$ref": "#/components/parameters/AllItemsLanguageQuery"
          },
          {
            "$ref": "#/components/parameters/AllItemsAnimeTypeQuery"
          },
          {
            "name": "episode_watched_at",
            "in": "query",
            "description": "`yes` adds per-episode `watched_at` timestamps to every loaded episode. **Requires `extended=full`** (or `extended=full_anime_seasons`) — it's a modifier on already-loaded episodes, so on its own it does nothing. To also cover `completed` / `dropped` items, combine with `include_all_episodes` (which itself also requires `extended=full`). Pair with `date_from` for continuous sync — significantly larger response.",
            "schema": {
              "type": "string",
              "const": "yes"
            },
            "examples": {
              "phase1_initial_full_pull": {
                "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                "value": "no"
              },
              "phase2_incremental_delta": {
                "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                "value": "yes"
              },
              "movies_completed_filtered": {
                "summary": "Path filter — only completed movies",
                "value": "no"
              },
              "watching_with_next_to_watch_info": {
                "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                "value": "no"
              },
              "extended_full_with_seasons": {
                "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                "value": "yes"
              },
              "anime_with_mapped_tvdb_seasons": {
                "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                "value": "no"
              },
              "simkl_ids_only_minimal": {
                "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                "value": "no"
              },
              "ids_only_with_externals": {
                "summary": "extended=ids_only — all external IDs, no per-show metadata",
                "value": "no"
              },
              "rewatches_via_allow_rewatch": {
                "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                "value": "yes"
              },
              "all_modifiers_inspection_only": {
                "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                "value": "yes"
              }
            }
          },
          {
            "name": "include_all_episodes",
            "in": "query",
            "description": "Three-value flag that controls per-episode loading on canonical entries. **Requires `extended=full`** — it has no effect on its own.\n\n- `no` *(default)* — Episode lists are loaded only for items in `watching`, `plantowatch`, and `hold` statuses. Items in `completed` and `dropped` skip episode loading entirely (you get only `watched_episodes_count`).\n- `yes` — Load episode lists for **every** status. For completed entries with no per-episode data recorded, synthesizes virtual episode rows stamped with the item's last-watched time (the same timestamp is shared across all synthesized rows). Complete coverage, approximate dates.\n- `original` — Load episode lists for every status, but **skip** virtual-episode synthesis. Completed entries get only their real recorded rows with real dates — which can be **fewer** than `watched_episodes_count` for an item the user marked complete in a single action. Treat the count as authoritative for how many episodes are watched, and the rows for which ones and when.\n\nIndependent of `allow_rewatch=yes` — combine the two when you need both canonical episode lists AND rewatch session episode lists in one response. Pair with `date_from` for continuous sync since the response can be much larger when episodes load for completed-bucket items.",
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "original",
                "no"
              ],
              "default": "no"
            },
            "examples": {
              "phase1_initial_full_pull": {
                "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                "value": "no"
              },
              "phase2_incremental_delta": {
                "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                "value": "no"
              },
              "movies_completed_filtered": {
                "summary": "Path filter — only completed movies",
                "value": "no"
              },
              "watching_with_next_to_watch_info": {
                "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                "value": "no"
              },
              "extended_full_with_seasons": {
                "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                "value": "no"
              },
              "anime_with_mapped_tvdb_seasons": {
                "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                "value": "no"
              },
              "simkl_ids_only_minimal": {
                "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                "value": "no"
              },
              "ids_only_with_externals": {
                "summary": "extended=ids_only — all external IDs, no per-show metadata",
                "value": "no"
              },
              "rewatches_via_allow_rewatch": {
                "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                "value": "no"
              },
              "all_modifiers_inspection_only": {
                "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                "value": "yes"
              }
            }
          },
          {
            "name": "memos",
            "in": "query",
            "description": "`yes` includes the user's per-item `memo` object (`text` capped at 140 chars, plus `is_private`) in addition to all other data. Field name is singular `memo`; empty memos render as `{}`.",
            "schema": {
              "type": "string",
              "const": "yes"
            },
            "examples": {
              "phase1_initial_full_pull": {
                "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                "value": "no"
              },
              "phase2_incremental_delta": {
                "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                "value": "no"
              },
              "movies_completed_filtered": {
                "summary": "Path filter — only completed movies",
                "value": "no"
              },
              "watching_with_next_to_watch_info": {
                "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                "value": "no"
              },
              "extended_full_with_seasons": {
                "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                "value": "no"
              },
              "anime_with_mapped_tvdb_seasons": {
                "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                "value": "no"
              },
              "simkl_ids_only_minimal": {
                "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                "value": "no"
              },
              "ids_only_with_externals": {
                "summary": "extended=ids_only — all external IDs, no per-show metadata",
                "value": "no"
              },
              "rewatches_via_allow_rewatch": {
                "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                "value": "no"
              },
              "all_modifiers_inspection_only": {
                "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                "value": "yes"
              }
            }
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Top-level dict keyed by `shows`, `movies`, and `anime`. **Keys are present only when there's at least one item in that bucket** — filtered calls (`/movies/completed`) return just that key; an empty library returns `{}`.\n\nThe per-item shape is `AllItemsEntry` — its fields are gated on the query parameters (`extended`, `memos`, `next_watch_info`, `episode_watched_at`, `episode_tvdb_id`, `allow_rewatch`, etc.). See the schema and the examples below for what each modifier adds.",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AllItemsResponse"
                },
                "examples": {
                  "phase1_initial_full_pull": {
                    "summary": "Phase 1 — Initial full pull (Sync guide recommendation, run ONCE per user)",
                    "description": "Call: `GET /sync/all-items`",
                    "value": {
                      "shows": [
                        {
                          "added_to_watchlist_at": "2018-02-24T23:55:13Z",
                          "last_watched_at": null,
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "plantowatch",
                          "last_watched": null,
                          "next_to_watch": "S01E01",
                          "watched_episodes_count": 0,
                          "total_episodes_count": 178,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Charmed",
                            "poster": "24/24273cee77f9d9f",
                            "year": 1998,
                            "ids": {
                              "simkl": 297,
                              "slug": "charmed",
                              "imdb": "tt0158552",
                              "tvdb": "70626",
                              "tmdb": "1981"
                            }
                          }
                        }
                      ],
                      "anime": [
                        {
                          "added_to_watchlist_at": "2026-05-15T00:13:09Z",
                          "last_watched_at": "2026-05-15T00:13:09Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "last_watched": null,
                          "next_to_watch": null,
                          "watched_episodes_count": 26,
                          "total_episodes_count": 26,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Cowboy Bebop",
                            "poster": "36/36842f1bceb6b39",
                            "year": 1998,
                            "ids": {
                              "simkl": 37089,
                              "slug": "cowboy-bebop",
                              "mal": "1",
                              "anidb": "23",
                              "anilist": "1"
                            }
                          },
                          "anime_type": "tv"
                        }
                      ]
                    }
                  },
                  "phase2_incremental_delta": {
                    "summary": "Phase 2 — Incremental delta with date_from + extended=full + episode_watched_at=yes (Sync guide recommendation, the recurring call)",
                    "description": "Call: `GET /sync/all-items?date_from=2026-05-14T00:00:00Z&extended=full&episode_watched_at=yes`",
                    "value": {
                      "shows": [
                        {
                          "added_to_watchlist_at": "2026-05-15T00:35:15Z",
                          "last_watched_at": "2026-05-15T00:35:15Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "watching",
                          "last_watched": "S01E01",
                          "next_to_watch": null,
                          "watched_episodes_count": 176,
                          "total_episodes_count": 177,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "The Walking Dead",
                            "poster": "16/16913426086fc13",
                            "year": 2010,
                            "ids": {
                              "simkl": 2090,
                              "slug": "the-walking-dead",
                              "imdb": "tt1520211",
                              "tvdb": "153021"
                            }
                          }
                        }
                      ],
                      "anime": [
                        {
                          "added_to_watchlist_at": "2026-05-15T00:13:09Z",
                          "last_watched_at": "2026-05-15T00:13:09Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "last_watched": null,
                          "next_to_watch": null,
                          "watched_episodes_count": 26,
                          "total_episodes_count": 26,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Cowboy Bebop",
                            "poster": "36/36842f1bceb6b39",
                            "year": 1998,
                            "ids": {
                              "simkl": 37089,
                              "slug": "cowboy-bebop",
                              "mal": "1",
                              "anidb": "23",
                              "anilist": "1"
                            }
                          },
                          "anime_type": "tv"
                        }
                      ],
                      "movies": [
                        {
                          "added_to_watchlist_at": "2026-05-14T06:49:56Z",
                          "last_watched_at": null,
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "dropped",
                          "watched_episodes_count": 0,
                          "total_episodes_count": 0,
                          "not_aired_episodes_count": 0,
                          "movie": {
                            "title": "Pulp Fiction",
                            "poster": "13/13311405613660dcc9",
                            "year": 1994,
                            "ids": {
                              "simkl": 54130,
                              "slug": "pulp-fiction",
                              "imdb": "tt0110912"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "movies_completed_filtered": {
                    "summary": "Path filter — only completed movies",
                    "description": "Call: `GET /sync/all-items/movies/completed`",
                    "value": {
                      "movies": [
                        {
                          "added_to_watchlist_at": "2026-04-10T20:13:02Z",
                          "last_watched_at": "1994-09-01T16:00:00Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "watched_episodes_count": 0,
                          "total_episodes_count": 0,
                          "not_aired_episodes_count": 0,
                          "movie": {
                            "title": "The Godfather",
                            "poster": "10/102447562f6b49ff3a",
                            "year": 1972,
                            "ids": {
                              "simkl": 53434,
                              "slug": "the-godfather",
                              "imdb": "tt0068646",
                              "tmdb": "238"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "watching_with_next_to_watch_info": {
                    "summary": "next_watch_info=yes — adds next_to_watch_info for watching items",
                    "description": "Call: `GET /sync/all-items/shows/watching?next_watch_info=yes`",
                    "value": {
                      "shows": [
                        {
                          "added_to_watchlist_at": "2014-11-12T18:42:53Z",
                          "last_watched_at": "2026-05-04T19:40:59Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "watching",
                          "last_watched": "S08E02",
                          "next_to_watch": "S08E03",
                          "watched_episodes_count": 126,
                          "total_episodes_count": 165,
                          "not_aired_episodes_count": 11,
                          "show": {
                            "title": "Futurama",
                            "poster": "18/18421459bbf0f06beb",
                            "year": 1999,
                            "ids": {
                              "simkl": 3407,
                              "slug": "futurama",
                              "imdb": "tt0149460",
                              "tvdb": "73871"
                            }
                          },
                          "next_to_watch_info": {
                            "title": "How the West Was 1010001",
                            "season": 8,
                            "episode": 3,
                            "date": "2023-08-07T00:00:00-05:00"
                          }
                        }
                      ]
                    }
                  },
                  "extended_full_with_seasons": {
                    "summary": "extended=full + episode_watched_at=yes — runtime + seasons[].episodes[].watched_at",
                    "description": "Call: `GET /sync/all-items/shows/watching?extended=full&episode_watched_at=yes`",
                    "value": {
                      "shows": [
                        {
                          "added_to_watchlist_at": "2026-05-15T00:35:15Z",
                          "last_watched_at": "2026-05-15T00:35:15Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "watching",
                          "last_watched": "S01E01",
                          "next_to_watch": null,
                          "watched_episodes_count": 176,
                          "total_episodes_count": 177,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "The Walking Dead",
                            "poster": "16/16913426086fc13",
                            "year": 2010,
                            "runtime": 43,
                            "ids": {
                              "simkl": 2090,
                              "slug": "the-walking-dead",
                              "imdb": "tt1520211",
                              "tvdb": "153021"
                            }
                          },
                          "seasons": [
                            {
                              "number": 1,
                              "episodes": [
                                {
                                  "number": 2,
                                  "watched_at": "2026-05-15T00:32:20Z"
                                },
                                {
                                  "number": 3,
                                  "watched_at": "2026-05-15T00:32:21Z"
                                }
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  },
                  "anime_with_mapped_tvdb_seasons": {
                    "summary": "extended=full_anime_seasons — anime gets mapped_tvdb_seasons",
                    "description": "Call: `GET /sync/all-items/anime/completed?extended=full_anime_seasons`",
                    "value": {
                      "anime": [
                        {
                          "added_to_watchlist_at": "2026-05-15T00:13:09Z",
                          "last_watched_at": "2026-05-15T00:13:09Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "last_watched": null,
                          "next_to_watch": null,
                          "watched_episodes_count": 26,
                          "total_episodes_count": 26,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Cowboy Bebop",
                            "poster": "36/36842f1bceb6b39",
                            "year": 1998,
                            "runtime": 25,
                            "ids": {
                              "simkl": 37089,
                              "slug": "cowboy-bebop",
                              "mal": "1",
                              "anidb": "23",
                              "anilist": "1"
                            }
                          },
                          "anime_type": "tv",
                          "mapped_tvdb_seasons": [
                            1
                          ]
                        }
                      ]
                    }
                  },
                  "simkl_ids_only_minimal": {
                    "summary": "extended=simkl_ids_only — smallest payload (incremental sync)",
                    "description": "Call: `GET /sync/all-items?extended=simkl_ids_only`",
                    "value": {
                      "shows": [
                        {
                          "show": {
                            "ids": {
                              "simkl": 297,
                              "slug": "charmed"
                            }
                          }
                        }
                      ],
                      "anime": [
                        {
                          "show": {
                            "ids": {
                              "simkl": 37089,
                              "slug": "cowboy-bebop",
                              "mal": "1",
                              "anidb": "23",
                              "anilist": "1"
                            }
                          }
                        }
                      ],
                      "movies": [
                        {
                          "movie": {
                            "ids": {
                              "simkl": 53434,
                              "slug": "the-godfather"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "ids_only_with_externals": {
                    "summary": "extended=ids_only — all external IDs, no per-show metadata",
                    "description": "Call: `GET /sync/all-items/movies/completed?extended=ids_only`",
                    "value": {
                      "movies": [
                        {
                          "movie": {
                            "ids": {
                              "simkl": 53434,
                              "slug": "the-godfather",
                              "imdb": "tt0068646",
                              "tmdb": "238",
                              "tvdb": "275"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "rewatches_via_allow_rewatch": {
                    "summary": "allow_rewatch=yes + extended=full + episode_watched_at=yes — rewatch rows WITH per-episode data (Simkl Pro / VIP). Without extended=full, rewatch rows return summary-only with watched_episodes_count:0 as sentinel.",
                    "description": "Call: `GET /sync/all-items/all/completed?allow_rewatch=yes&extended=full&episode_watched_at=yes`",
                    "value": {
                      "shows": [
                        {
                          "added_to_watchlist_at": "2026-05-15T00:13:18Z",
                          "last_watched_at": "2026-05-15T00:13:18Z",
                          "user_rated_at": "2026-05-16T14:20:16Z",
                          "user_rating": 10,
                          "status": "completed",
                          "last_watched": null,
                          "next_to_watch": null,
                          "watched_episodes_count": 73,
                          "total_episodes_count": 73,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Game of Thrones",
                            "poster": "57/5742576cd8f59fcb0",
                            "year": 2011,
                            "runtime": 52,
                            "ids": {
                              "simkl": 17465,
                              "slug": "game-of-thrones",
                              "imdb": "tt0944947",
                              "tvdb": "121361",
                              "tmdb": "1399"
                            }
                          },
                          "is_rewatch": false
                        },
                        {
                          "added_to_watchlist_at": "2026-05-16T14:02:10Z",
                          "last_watched_at": "2026-05-16T20:00:00Z",
                          "user_rated_at": "2026-05-16T14:20:16Z",
                          "user_rating": 10,
                          "status": "completed",
                          "last_watched": "S01E04",
                          "next_to_watch": null,
                          "watched_episodes_count": 4,
                          "total_episodes_count": 73,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Game of Thrones",
                            "poster": "57/5742576cd8f59fcb0",
                            "year": 2011,
                            "runtime": 52,
                            "ids": {
                              "simkl": 17465,
                              "slug": "game-of-thrones",
                              "imdb": "tt0944947",
                              "tvdb": "121361",
                              "tmdb": "1399"
                            }
                          },
                          "is_rewatch": true,
                          "rewatch_id": 7482,
                          "rewatch_status": "completed",
                          "seasons": [
                            {
                              "number": 1,
                              "episodes": [
                                {
                                  "number": 1,
                                  "watched_at": "2026-05-16T14:02:10Z"
                                },
                                {
                                  "number": 2,
                                  "watched_at": "2026-05-16T14:02:10Z"
                                },
                                {
                                  "number": 3,
                                  "watched_at": "2026-05-16T19:00:00Z"
                                },
                                {
                                  "number": 4,
                                  "watched_at": "2026-05-16T20:00:00Z"
                                }
                              ]
                            }
                          ]
                        }
                      ],
                      "anime": [
                        {
                          "added_to_watchlist_at": "2026-05-15T00:13:09Z",
                          "last_watched_at": "2026-05-15T00:13:09Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "last_watched": null,
                          "next_to_watch": null,
                          "watched_episodes_count": 26,
                          "total_episodes_count": 26,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Cowboy Bebop",
                            "poster": "36/36842f1bceb6b39",
                            "year": 1998,
                            "runtime": 25,
                            "ids": {
                              "simkl": 37089,
                              "slug": "cowboy-bebop",
                              "mal": "1",
                              "anidb": "23",
                              "anilist": "1",
                              "kitsu": "1"
                            }
                          },
                          "anime_type": "tv",
                          "is_rewatch": false
                        },
                        {
                          "added_to_watchlist_at": "2026-05-16T14:02:10Z",
                          "last_watched_at": "2026-05-16T14:02:10Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "last_watched": "E2",
                          "next_to_watch": null,
                          "watched_episodes_count": 2,
                          "total_episodes_count": 26,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Cowboy Bebop",
                            "poster": "36/36842f1bceb6b39",
                            "year": 1998,
                            "runtime": 25,
                            "ids": {
                              "simkl": 37089,
                              "slug": "cowboy-bebop",
                              "mal": "1",
                              "anidb": "23",
                              "anilist": "1",
                              "kitsu": "1"
                            }
                          },
                          "anime_type": "tv",
                          "is_rewatch": true,
                          "rewatch_id": 7484,
                          "rewatch_status": "active",
                          "seasons": [
                            {
                              "number": 1,
                              "episodes": [
                                {
                                  "number": 1,
                                  "watched_at": "2026-05-16T14:02:10Z"
                                },
                                {
                                  "number": 2,
                                  "watched_at": "2026-05-16T14:02:10Z"
                                }
                              ]
                            }
                          ]
                        }
                      ],
                      "movies": [
                        {
                          "added_to_watchlist_at": "2026-04-10T20:13:02Z",
                          "last_watched_at": "1994-09-01T16:00:00Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "watched_episodes_count": 0,
                          "total_episodes_count": 0,
                          "not_aired_episodes_count": 0,
                          "movie": {
                            "title": "The Godfather",
                            "poster": "10/102447562f6b49ff3a",
                            "year": 1972,
                            "runtime": 175,
                            "ids": {
                              "simkl": 53434,
                              "slug": "the-godfather",
                              "imdb": "tt0068646",
                              "tmdb": "238",
                              "tvdb": "275"
                            }
                          },
                          "is_rewatch": false
                        },
                        {
                          "added_to_watchlist_at": "2026-04-11T11:44:27Z",
                          "last_watched_at": "2026-04-11T11:30:00Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "watched_episodes_count": 0,
                          "total_episodes_count": 0,
                          "not_aired_episodes_count": 0,
                          "movie": {
                            "title": "The Godfather",
                            "poster": "10/102447562f6b49ff3a",
                            "year": 1972,
                            "runtime": 175,
                            "ids": {
                              "simkl": 53434,
                              "slug": "the-godfather",
                              "imdb": "tt0068646",
                              "tmdb": "238",
                              "tvdb": "275"
                            }
                          },
                          "is_rewatch": true,
                          "rewatch_id": 2368,
                          "rewatch_status": "completed"
                        }
                      ]
                    }
                  },
                  "all_modifiers_inspection_only": {
                    "summary": "INSPECTION ONLY — every modifier on at once. NOT a production default — payload size + Pro-only fields. Use it to see every possible response field in one place.",
                    "description": "Call: `GET /sync/all-items?extended=full_anime_seasons&memos=yes&next_watch_info=yes&episode_watched_at=yes&episode_tvdb_id=yes&include_all_episodes=yes&allow_rewatch=yes`",
                    "value": {
                      "shows": [
                        {
                          "added_to_watchlist_at": "2026-05-15T00:13:18Z",
                          "last_watched_at": "2026-05-15T00:13:18Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "last_watched": null,
                          "next_to_watch": null,
                          "watched_episodes_count": 73,
                          "total_episodes_count": 73,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Game of Thrones",
                            "poster": "57/5742576cd8f59fcb0",
                            "year": 2011,
                            "runtime": 52,
                            "ids": {
                              "simkl": 17465,
                              "slug": "game-of-thrones",
                              "imdb": "tt0944947",
                              "tvdb": "121361",
                              "tmdb": "1399"
                            }
                          },
                          "memo": {},
                          "is_rewatch": false,
                          "seasons": [
                            {
                              "number": 1,
                              "episodes": [
                                {
                                  "number": 1,
                                  "watched_at": "2026-05-15T00:13:18Z",
                                  "ids": {
                                    "tvdb_id": 3254641
                                  }
                                },
                                {
                                  "number": 2,
                                  "watched_at": "2026-05-15T00:13:18Z",
                                  "ids": {
                                    "tvdb_id": 3436411
                                  }
                                }
                              ]
                            }
                          ]
                        },
                        {
                          "added_to_watchlist_at": "2026-05-16T14:02:10Z",
                          "last_watched_at": "2026-05-16T14:02:10Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "last_watched": "S01E02",
                          "next_to_watch": null,
                          "watched_episodes_count": 2,
                          "total_episodes_count": 73,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Game of Thrones",
                            "poster": "57/5742576cd8f59fcb0",
                            "year": 2011,
                            "runtime": 52,
                            "ids": {
                              "simkl": 17465,
                              "slug": "game-of-thrones",
                              "imdb": "tt0944947",
                              "tvdb": "121361",
                              "tmdb": "1399"
                            }
                          },
                          "memo": {},
                          "is_rewatch": true,
                          "rewatch_id": 7482,
                          "rewatch_status": "active",
                          "seasons": [
                            {
                              "number": 1,
                              "episodes": [
                                {
                                  "number": 1,
                                  "watched_at": "2026-05-16T14:02:10Z",
                                  "ids": {
                                    "tvdb_id": 3254641
                                  }
                                },
                                {
                                  "number": 2,
                                  "watched_at": "2026-05-16T14:02:10Z",
                                  "ids": {
                                    "tvdb_id": 3436411
                                  }
                                }
                              ]
                            }
                          ]
                        }
                      ],
                      "anime": [
                        {
                          "added_to_watchlist_at": "2026-05-15T00:13:09Z",
                          "last_watched_at": "2026-05-15T00:13:09Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "last_watched": null,
                          "next_to_watch": null,
                          "watched_episodes_count": 26,
                          "total_episodes_count": 26,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Cowboy Bebop",
                            "poster": "36/36842f1bceb6b39",
                            "year": 1998,
                            "runtime": 25,
                            "ids": {
                              "simkl": 37089,
                              "slug": "cowboy-bebop",
                              "mal": "1",
                              "anidb": "23",
                              "anilist": "1",
                              "kitsu": "1"
                            }
                          },
                          "memo": {},
                          "anime_type": "tv",
                          "mapped_tvdb_seasons": [
                            1
                          ],
                          "is_rewatch": false,
                          "seasons": [
                            {
                              "number": 1,
                              "episodes": [
                                {
                                  "number": 1,
                                  "watched_at": "2026-05-15T00:13:09Z",
                                  "tvdb": {
                                    "season": 1,
                                    "episode": 1
                                  },
                                  "ids": {
                                    "tvdb_id": 219121
                                  }
                                },
                                {
                                  "number": 2,
                                  "watched_at": "2026-05-15T00:13:09Z",
                                  "tvdb": {
                                    "season": 1,
                                    "episode": 2
                                  },
                                  "ids": {
                                    "tvdb_id": 219122
                                  }
                                }
                              ]
                            }
                          ]
                        },
                        {
                          "added_to_watchlist_at": "2026-05-16T14:02:10Z",
                          "last_watched_at": "2026-05-16T14:02:10Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "last_watched": "E2",
                          "next_to_watch": null,
                          "watched_episodes_count": 2,
                          "total_episodes_count": 26,
                          "not_aired_episodes_count": 0,
                          "show": {
                            "title": "Cowboy Bebop",
                            "poster": "36/36842f1bceb6b39",
                            "year": 1998,
                            "runtime": 25,
                            "ids": {
                              "simkl": 37089,
                              "slug": "cowboy-bebop",
                              "mal": "1",
                              "anidb": "23",
                              "anilist": "1",
                              "kitsu": "1"
                            }
                          },
                          "memo": {},
                          "anime_type": "tv",
                          "mapped_tvdb_seasons": [
                            1
                          ],
                          "is_rewatch": true,
                          "rewatch_id": 7484,
                          "rewatch_status": "active",
                          "seasons": [
                            {
                              "number": 1,
                              "episodes": [
                                {
                                  "number": 1,
                                  "watched_at": "2026-05-16T14:02:10Z",
                                  "tvdb": {
                                    "season": 1,
                                    "episode": 1
                                  },
                                  "ids": {
                                    "tvdb_id": 219121
                                  }
                                },
                                {
                                  "number": 2,
                                  "watched_at": "2026-05-16T14:02:10Z",
                                  "tvdb": {
                                    "season": 1,
                                    "episode": 2
                                  },
                                  "ids": {
                                    "tvdb_id": 219122
                                  }
                                }
                              ]
                            }
                          ]
                        }
                      ],
                      "movies": [
                        {
                          "added_to_watchlist_at": "2026-04-10T20:13:02Z",
                          "last_watched_at": "1994-09-01T16:00:00Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "watched_episodes_count": 0,
                          "total_episodes_count": 0,
                          "not_aired_episodes_count": 0,
                          "movie": {
                            "title": "The Godfather",
                            "poster": "10/102447562f6b49ff3a",
                            "year": 1972,
                            "runtime": 175,
                            "ids": {
                              "simkl": 53434,
                              "slug": "the-godfather",
                              "imdb": "tt0068646",
                              "tmdb": "238",
                              "tvdb": "275"
                            }
                          },
                          "memo": {},
                          "is_rewatch": false
                        },
                        {
                          "added_to_watchlist_at": "2026-04-11T11:44:27Z",
                          "last_watched_at": "2026-04-11T11:30:00Z",
                          "user_rated_at": null,
                          "user_rating": null,
                          "status": "completed",
                          "watched_episodes_count": 0,
                          "total_episodes_count": 0,
                          "not_aired_episodes_count": 0,
                          "movie": {
                            "title": "The Godfather",
                            "poster": "10/102447562f6b49ff3a",
                            "year": 1972,
                            "runtime": 175,
                            "ids": {
                              "simkl": 53434,
                              "slug": "the-godfather",
                              "imdb": "tt0068646",
                              "tmdb": "238",
                              "tvdb": "275"
                            }
                          },
                          "memo": {},
                          "is_rewatch": true,
                          "rewatch_id": 2368,
                          "rewatch_status": "completed"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-all-items",
          "metadata": {
            "sidebarTitle": "All items"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "phase1_initial_full_pull",
            "source": "curl 'https://api.simkl.com/sync/all-items?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'"
          },
          {
            "lang": "curl",
            "label": "phase2_incremental_delta",
            "source": "curl 'https://api.simkl.com/sync/all-items?extended=full&episode_watched_at=yes&date_from=2026-05-14T00:00:00Z&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'"
          },
          {
            "lang": "curl",
            "label": "movies_completed_filtered",
            "source": "curl 'https://api.simkl.com/sync/all-items/movies/completed?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'"
          },
          {
            "lang": "curl",
            "label": "watching_with_next_to_watch_info",
            "source": "curl 'https://api.simkl.com/sync/all-items/shows/watching?next_watch_info=yes&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'"
          },
          {
            "lang": "curl",
            "label": "extended_full_with_seasons",
            "source": "curl 'https://api.simkl.com/sync/all-items/shows/watching?extended=full&episode_watched_at=yes&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'"
          },
          {
            "lang": "curl",
            "label": "anime_with_mapped_tvdb_seasons",
            "source": "curl 'https://api.simkl.com/sync/all-items/anime/completed?extended=full_anime_seasons&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'"
          },
          {
            "lang": "curl",
            "label": "simkl_ids_only_minimal",
            "source": "curl 'https://api.simkl.com/sync/all-items?extended=simkl_ids_only&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'"
          },
          {
            "lang": "curl",
            "label": "ids_only_with_externals",
            "source": "curl 'https://api.simkl.com/sync/all-items/movies/completed?extended=ids_only&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'"
          },
          {
            "lang": "curl",
            "label": "rewatches_via_allow_rewatch",
            "source": "curl 'https://api.simkl.com/sync/all-items/all/completed?extended=full&episode_watched_at=yes&allow_rewatch=yes&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'"
          },
          {
            "lang": "curl",
            "label": "all_modifiers_inspection_only",
            "source": "curl 'https://api.simkl.com/sync/all-items?extended=full_anime_seasons&memos=yes&next_watch_info=yes&episode_watched_at=yes&episode_tvdb_id=yes&include_all_episodes=yes&allow_rewatch=yes&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'"
          }
        ]
      }
    },
    "/sync/history": {
      "post": {
        "operationId": "post-sync-history",
        "summary": "Add to History",
        "description": "Record watch events. The unit is the **watch event** — adding \"I watched The Walking Dead S01E01 at 8pm\" — not list membership (use [`POST /sync/add-to-list`](/api-reference/simkl/add-to-list) for that, or set `status` per-item here to do both at once).\n\n<Tip>\n**You don't need a Simkl ID.** Same as `/sync/add-to-list` — the server resolves any combination of identifiers (`imdb`, `tmdb`, `tvdb`, `mal`, `anidb`, `anilist`, `kitsu`) plus `title` + `year`. See [Standard media objects → Supported ID keys](/conventions/standard-media-objects#supported-id-keys) for the full list, and the [/sync/add-to-list ID-resolution table](/api-reference/simkl/add-to-list) for per-slot semantics.\n</Tip>\n\n#### Granularity — when does the server expand \"implicit all\"?\n\nThe body shape determines whether you mark a single episode, a season, or a whole show.\n\n**One movie** — single movie completion.\n\n```json\n{ \"movies\": [{ \"ids\": {...} }] }\n```\n\n**Whole show** — every episode marked. *\"I finished this whole series.\"* Send `status: \"completed\"` with no `seasons` / `episodes`.\n\n```json\n{ \"shows\": [{ \"ids\": {...}, \"status\": \"completed\" }] }\n```\n\n**Whole season** — every episode of one season. *\"I finished season 2.\"* Send `seasons[]` without an inner `episodes`.\n\n```json\n{ \"shows\": [{ \"ids\": {...}, \"seasons\": [{ \"number\": 2 }] }] }\n```\n\n**Specific episodes only** — per-event scrobbling, manual tick-off.\n\n```json\n{\n  \"shows\": [{\n    \"ids\": {...},\n    \"seasons\": [{\n      \"number\": 1,\n      \"episodes\": [{ \"number\": 1 }, { \"number\": 2 }]\n    }]\n  }]\n}\n```\n\n**Top-level `episodes[]` shorthand** — auto-wraps to `seasons: [{ number: 1, ... }]`. Useful for anime sequential numbering and single-season shows.\n\n```json\n{ \"shows\": [{ \"ids\": {...}, \"episodes\": [{ \"number\": 1 }] }] }\n```\n\nThe response always reports the actual count of episodes affected in `added.episodes`, so apps can verify the server expanded correctly.\n\n#### Memo-only updates (and \"add to watchlist + memo\" in one call)\n\nThis endpoint is the **only way to set a memo on an item.** [`POST /sync/add-to-list`](/api-reference/simkl/add-to-list) accepts the `memo` field in the request body and echoes it back in the response, but **does not persist it** — silently discarded.\n\nTo set or update a memo without recording a watch event, send `ids` + `status` + `memo`:\n\n```json\n{\n  \"movies\": [{\n    \"ids\": { \"simkl\": 53536 },\n    \"status\": \"plantowatch\",\n    \"memo\": { \"text\": \"Remind me why I added this\", \"is_private\": true }\n  }]\n}\n```\n\nTwo behaviors worth knowing:\n\n- **Memos attach to watchlist items only.** The item has to be in one of the five statuses (`watching` / `plantowatch` / `hold` / `dropped` / `completed`) for the memo to stick. Sending `status` makes this explicit.\n- **The endpoint auto-adds items.** If the item isn't on the user's watchlist yet, this same call creates the watchlist row at the specified `status` AND saves the memo in one shot. `added.movies` / `added.shows` reports the count of newly-added items (`0` when the item was already there and you only changed memo/status).\n\nTo read memos back, call `GET /sync/all-items?memos=yes` — see the [Sync guide](/guides/sync).\n\n#### Per-item options\n\n| Field | Type | Notes |\n|---|---|---|\n| `watched_at` | ISO-8601 string | Pin the watch event to a specific time. Defaults to request time. |\n| `added_at` | ISO-8601 string | Override when the item was added to the watchlist (rarely used outside backups). |\n| `status` | string | Set the watchlist status (`watching`/`plantowatch`/`hold`/`completed`/`dropped`) in the same call. Combine with `rating` to do \"watched + rate + status\" in one request. |\n| `rating` | int 1-10 | Rate the item alongside the watch event. Same effect as a separate `POST /sync/ratings` call. |\n| `memo` | `{ \"text\": string, \"is_private\": bool }` | User memo, max 140 chars. `is_private: false` shows the memo on the user's public profile + activity feed; `true` keeps it self-only. Read-back requires `/sync/all-items?memos=yes`. |\n| `is_rewatch` | bool | Force the rewatch path on this item even if the server can't auto-detect (used by backup/restore tools). Requires `?allow_rewatch=yes` query param to take effect. |\n| `use_tvdb_anime_seasons` | bool *(anime-only, optional)* | Default `false` (AniDB sequential — flat single-season). Set `true` to interpret `season`/`number` as TVDB per-season numbering. **Only needed when your source uses TVDB-style numbering AND the title is multi-season in TVDB** (e.g. Demon Slayer S2 Entertainment District). Single-season anime and AniDB-sequential inputs work without this flag. Use when syncing from Plex/Sonarr/Kodi/Jellyfin. |\n\n#### Rewatches\n\nRe-posting an already-watched episode is a **no-op by default** — the server detects the duplicate and skips. To insert a rewatch session, send `?allow_rewatch=yes` as a query parameter. The server then creates a separate rewatch row that doesn't double-count the original watch.\n\n**Simkl Pro / VIP only.** Free-tier callers with `?allow_rewatch=yes` get a silent no-op (`added: { movies: 0, shows: 0, episodes: 0 }`) that still consumes a rate-limit slot. Check `account.type` from [`POST /users/settings`](/api-reference/simkl/get-user-settings) at sign-in and gate the flag on `\"pro\"` / `\"vip\"`. Cache the value; refetch only when `activities.settings.all` from [`GET /sync/activities`](/api-reference/simkl/get-activities) bumps. Full pattern in [Rewatches guide → Pro / VIP gate](/guides/rewatches).\n\nFor backup/restore tools that always want to insert (even when the auto-detect heuristic can't fire), set `is_rewatch: true` per-item AND pass the query param.\n\n#### Response: `added` and `not_found`\n\n```json\n{\n  \"added\": {\n    \"movies\": <int count>,\n    \"shows\": <int count>,\n    \"episodes\": <int count>,\n    \"statuses\": [\n      {\n        \"request\": { /* echo of input item, with type added */ },\n        \"response\": {\n          \"status\": \"completed\",\n          \"simkl_type\": \"tv\" | \"anime\" | \"movie\",\n          \"anime_type\": \"tv\" | \"movie\" | \"ova\" | null\n        }\n      }\n    ]\n  },\n  \"not_found\": {\n    \"movies\": [...],\n    \"shows\": [...],\n    \"episodes\": [...]\n  }\n}\n```\n\n**`added.statuses[*].response.status`** is the **resolved Watchlist status** the server placed the item on — e.g. a `\"completed\"` write on a still-airing show is silently downgraded to `\"watching\"` and reflected here. **You don't need a follow-up [`POST /sync/add-to-list`](/api-reference/simkl/add-to-list)** — this call already moves the item; chaining would just overwrite the server's smarter decision.\n\n**`added.statuses[*].response.simkl_type`** tells you which catalog the item resolved to (useful when you sent ambiguous IDs — TMDB IDs can be either movie or tv on Simkl). Always inspect to know what got created.\n\n**`not_found`** carries the verbatim input for items the resolver couldn't match (typo, fuzzy-title miss, ID not in Simkl's catalog yet). Apps should:\n\n- Show \"we couldn't track: …\" UI for these\n- Offer manual ID-entry fallback\n- Don't infer success from the 201 status alone — branch on `not_found.movies.length === 0 && not_found.shows.length === 0 && not_found.episodes.length === 0`\n\n#### Errors\n\n`400 empty_field` if a per-item required field is missing. `400 wrong_parameter` for invalid enum values. Empty body `{}` returns 201 with zero counts (NOT 400) — that's a known asymmetry vs `/scrobble/start` which 400s on empty body.\n\n<Card title=\"Sync guide — full walkthrough\" icon=\"arrows-rotate\" href=\"/guides/sync\" horizontal>\n Initial-pull-then-delta-loop pattern, `date_from` semantics, deletion reconciliation, Trakt/Letterboxd migration recipes.\n</Card>\n\n#### When to use `/sync/history` vs `/sync/add-to-list`\n\n| Goal | Endpoint |\n|---|---|\n| User finished watching → mark watched + rate + memo | **`/sync/history`** (carries all three in one shape) |\n| User clicked \"Add to Plan to Watch\" button | **`/sync/add-to-list`** (status-only, no watch event) |\n| Backfill from Trakt/Letterboxd/IMDb (events with timestamps) | **`/sync/history`** with `watched_at` per item |\n| Bulk import a watchlist (no watch events) | **`/sync/add-to-list`** |\n| Remove an item from the user's library | **[`/sync/history/remove`](/api-reference/simkl/remove-from-history)** |\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "$ref": "#/components/parameters/AllowRewatchQuery"
          },
          {
            "name": "skip_auto_watching",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes"
              ]
            },
            "description": "When `yes`, suppresses the implicit episode auto-fill that happens when you POST a show without explicit `seasons`/`episodes`. Use when the client manages episode-level state itself."
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "realistic_batch": {
                  "summary": "Realistic batch — multiple movies + shows with mixed IDs, titles, years",
                  "description": "What a tracker app typically sends after a catch-up sync — a mix of media types with whatever identifiers it has on hand. Some entries carry a Simkl ID directly; others use third-party IDs (IMDB / TMDB / TVDB) plus `title` + `year` as fallback. The server resolves every combination to a canonical Simkl record and records the watch events. Use this pattern for backfill from Trakt/Letterboxd/Plex/Jellyfin, where you'll have a varied bag of metadata per item.",
                  "value": {
                    "movies": [
                      {
                        "watched_at": "2026-05-15T22:30:00Z",
                        "title": "Dune: Part Two",
                        "year": 2024,
                        "ids": {
                          "simkl": 1015859
                        }
                      },
                      {
                        "watched_at": "2026-05-14T20:00:00Z",
                        "title": "Oppenheimer",
                        "year": 2023,
                        "ids": {
                          "imdb": "tt15398776",
                          "tmdb": "872585"
                        }
                      }
                    ],
                    "shows": [
                      {
                        "title": "The Last of Us",
                        "year": 2023,
                        "ids": {
                          "simkl": 1411674
                        },
                        "seasons": [
                          {
                            "number": 1,
                            "episodes": [
                              {
                                "number": 1,
                                "watched_at": "2026-05-13T19:00:00Z"
                              },
                              {
                                "number": 2,
                                "watched_at": "2026-05-13T20:00:00Z"
                              },
                              {
                                "number": 3,
                                "watched_at": "2026-05-14T18:30:00Z"
                              }
                            ]
                          }
                        ]
                      },
                      {
                        "title": "Breaking Bad",
                        "year": 2008,
                        "ids": {
                          "imdb": "tt0903747"
                        },
                        "status": "completed",
                        "rating": 10
                      }
                    ]
                  }
                },
                "add_movie_watched_no_timestamp": {
                  "summary": "Mark a movie watched right now (no `watched_at`)",
                  "description": "Minimal shape. Server records the watch event at request time. Use this for live UIs where the user just clicked Watched.",
                  "value": {
                    "movies": [
                      {
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "add_movie_watched_with_timestamp": {
                  "summary": "Mark a movie watched at a specific UTC time",
                  "description": "Pin the watch event to an exact moment. Use this for backfilling history from another tracker (Trakt, IMDb watchlist, etc.). `watched_at` is ISO-8601 with `Z` suffix. Omit it to default to the time of the request.",
                  "value": {
                    "movies": [
                      {
                        "watched_at": "2026-05-01T20:00:00Z",
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "mark_top_level_episodes_shorthand": {
                  "summary": "GRANULARITY: top-level episodes[] (auto-wrapped to season 1)",
                  "description": "Shorthand for the common case of single-season targeting (or anime AniDB sequential numbering). The server auto-wraps to `seasons: [{number: 1, episodes: [...]}]`.",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "episodes": [
                          {
                            "number": 1
                          },
                          {
                            "number": 2
                          }
                        ]
                      }
                    ]
                  }
                },
                "add_show_episodes_via_seasons": {
                  "summary": "Mark specific TV episodes watched (S01E01-E02)",
                  "description": "Targeted episode-level history. The `seasons` array carries one entry per season with an `episodes` array inside. Each episode can carry its own `watched_at`. Use this for fine-grained backfill or for marking re-watched episodes.",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "seasons": [
                          {
                            "number": 1,
                            "episodes": [
                              {
                                "number": 1,
                                "watched_at": "2026-05-01T20:00:00Z"
                              },
                              {
                                "number": 2,
                                "watched_at": "2026-05-01T21:00:00Z"
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "mark_specific_episodes_explicit": {
                  "summary": "GRANULARITY: mark specific episodes — seasons[].episodes[]",
                  "description": "Episode-level targeting. Each episode can carry its own `watched_at` for accurate per-event timestamps. Use this when syncing from a player that emits one event per episode.",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "seasons": [
                          {
                            "number": 1,
                            "episodes": [
                              {
                                "number": 1
                              },
                              {
                                "number": 2
                              },
                              {
                                "number": 3
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "mark_whole_season_no_episodes": {
                  "summary": "GRANULARITY: mark whole season — seasons[{number:N}] with no episodes[]",
                  "description": "Mark every episode of season N watched without enumerating them. Each season entry without an `episodes` array is expanded by the server. Useful when a user marks 'I finished season 3' in one click. Combine multiple seasons in the array to mark several at once.",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "seasons": [
                          {
                            "number": 1
                          }
                        ]
                      }
                    ]
                  }
                },
                "add_show_full_season": {
                  "summary": "Mark an entire TV season watched (season 1, all episodes)",
                  "description": "Shorthand for marking every episode of a season. Omit the `episodes` array; the server enumerates the season's episodes automatically. Watch-time defaults to request time for each episode unless you pass a `watched_at` on the season entry.",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "seasons": [
                          {
                            "number": 1
                          }
                        ]
                      }
                    ]
                  }
                },
                "mark_whole_show_completed": {
                  "summary": "GRANULARITY: mark whole show — no seasons/episodes + status=completed",
                  "description": "Most efficient way to mark an entire show watched: omit `seasons[]` AND `episodes[]`, set `status: \"completed\"`. The server iterates every episode of the series and marks them all watched. Response's `added.episodes` is the total count.",
                  "value": {
                    "shows": [
                      {
                        "title": "The Walking Dead",
                        "year": 2010,
                        "ids": {
                          "simkl": 2090
                        },
                        "status": "completed"
                      }
                    ]
                  }
                },
                "mixed_types_one_call": {
                  "summary": "Mixed types — a movie + a TV episode + an anime episode (anime under `shows[]`)",
                  "description": "Tracker apps batch catch-up syncs by sending every newly-watched item in one call. **Anime entries sit under `shows[]`, not `anime[]`** — Simkl resolves to the anime catalog automatically via the IDs (or via fuzzy title+year). The `anime[]` key still works for backwards compatibility but the cleanest pattern is one `shows[]` array for both TV and anime. The response's `added.statuses[]` array echoes each input with the resolved `simkl_type` (`movie` / `tv` / `anime`) and the watchlist status the item ended up in — `anime_type` (`tv` / `movie` / `ova` / `null`) further disambiguates anime catalog entries.",
                  "value": {
                    "movies": [
                      {
                        "ids": {
                          "simkl": 472214
                        }
                      }
                    ],
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "seasons": [
                          {
                            "number": 1,
                            "episodes": [
                              {
                                "number": 1
                              }
                            ]
                          }
                        ]
                      },
                      {
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        },
                        "seasons": [
                          {
                            "number": 1,
                            "episodes": [
                              {
                                "number": 1
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "history_rating_plus_status_combined": {
                  "summary": "Combined: mark watched + set status + rate in one request",
                  "description": "Per-item `rating` (1-10) is processed by the same handler as `/sync/ratings`. Combine with `status` to do all three actions in a single round-trip — common for 'I just finished this and want to rate it' UI flows.passes `rating` to.",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "status": "completed",
                        "rating": 9
                      }
                    ]
                  }
                },
                "history_with_private_memo": {
                  "summary": "Mark watched + attach a PRIVATE memo (self-only notes)",
                  "description": "Same shape as a public memo, but `is_private: true` keeps the text visible only to the owning user. Use for personal notes, rewatch reminders, spoilers, etc. Read-back requires `/sync/all-items?memos=yes` (read-side gating).",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "status": "completed",
                        "memo": {
                          "text": "Skip S7 next time, too slow",
                          "is_private": true
                        }
                      }
                    ]
                  }
                },
                "history_with_public_memo": {
                  "summary": "Mark watched + attach a PUBLIC memo (visible to other users)",
                  "description": "`memo` is a per-item field with two sub-fields: `text` (max 140 chars) and `is_private` (boolean). `is_private: false` makes the memo visible on the user's public Simkl profile and in the activity feed. Use for spoiler-free reactions and recommendations.",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "status": "completed",
                        "memo": {
                          "text": "Loved every season — best zombie show",
                          "is_private": false
                        }
                      }
                    ]
                  }
                },
                "add_anime_episode": {
                  "summary": "Mark an anime episode watched",
                  "description": "Anime use the same `shows` body shape as TV — AniDB numbering is single-season, so `seasons[0].number = 1` always. The catalog ID tells the server which catalog (anime vs TV) to dispatch to.",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        },
                        "seasons": [
                          {
                            "number": 1,
                            "episodes": [
                              {
                                "number": 1
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "anime_use_tvdb_seasons_flag": {
                  "summary": "ANIME (Plex/Sonarr): `use_tvdb_anime_seasons: true` with TVDB-only IDs",
                  "description": "Anime have two parallel numbering schemes: **AniDB sequential** (flat single-season — episode 27 of Demon Slayer S1 in AniDB terms is actually S2E1 in TVDB terms) and **TVDB per-season**. Players that source metadata from TheTVDB — Plex, Sonarr, Kodi, Jellyfin — only have the TVDB shape and typically lack `mal`/`anidb`/`anilist` IDs. Pass `use_tvdb_anime_seasons: true` and Simkl maps your TVDB-style `season`+`number` to the canonical AniDB record. **Note:** this example deliberately uses only TVDB+title+year (no anime-only IDs) to model the real Plex/Sonarr scenario.",
                  "value": {
                    "shows": [
                      {
                        "title": "Demon Slayer: Kimetsu no Yaiba",
                        "year": 2019,
                        "ids": {
                          "tvdb": "359476"
                        },
                        "use_tvdb_anime_seasons": true,
                        "seasons": [
                          {
                            "number": 2,
                            "episodes": [
                              {
                                "number": 5,
                                "watched_at": "2026-05-16T22:00:00Z"
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "rewatch_explicit_flag": {
                  "summary": "Rewatch — explicit `is_rewatch: true` per-item flag on a SHOW (Simkl Pro / VIP)",
                  "description": "Set `is_rewatch: true` on the item AND pass `?allow_rewatch=yes` to force the rewatch path. The VIP response includes `rewatch_id` and `rewatch_status` in `added.statuses[].response`. **Pin the `rewatch_id` on every subsequent write for the same session** to keep multi-call writes from forking into separate sessions — see the [Rewatches guide](/guides/rewatches).",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 17465
                        },
                        "is_rewatch": true,
                        "seasons": [
                          {
                            "number": 1,
                            "episodes": [
                              {
                                "number": 1
                              },
                              {
                                "number": 2
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "rewatch_with_allow_rewatch_query": {
                  "summary": "Rewatch — re-post episode with `?allow_rewatch=yes` on a previously-completed ANIME (Simkl Pro / VIP)",
                  "description": "Without `?allow_rewatch=yes`, re-posting a watched episode is a no-op. WITH the query param (and a VIP account), the server creates a rewatch session and the episode counts again. The response includes `rewatch_id` (cache it for subsequent writes in this session) and `rewatch_status` (`active`/`completed`/`closed`).",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 37089,
                          "mal": "1",
                          "anidb": "23",
                          "anilist": "1"
                        },
                        "is_rewatch": true,
                        "seasons": [
                          {
                            "number": 1,
                            "episodes": [
                              {
                                "number": 1
                              },
                              {
                                "number": 2
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "rewatch_max_info": {
                  "summary": "Rewatch — maximum info (every rewatch field populated, all wired to a real session) (Simkl Pro / VIP)",
                  "description": "Every per-item rewatch field set: `is_rewatch:true`, `rewatch_id` (to resume a specific session), `rewatch_status` (to explicitly close or reactivate it — for TV / anime, `\"completed\"` is clamped to `\"closed\"`; the server promotes back to `\"completed\"` once coverage of every aired regular episode lands), per-episode `watched_at`, plus the standard `rating` and `memo: {text, is_private}` fields. This is what a tracker app's *\"close out this rewatch\"* button would send.\n\nThe response echoes every field you set in `added.statuses[].request` AND surfaces the resulting `rewatch_id` + `rewatch_status` in `added.statuses[].response` (so you can confirm the session state Simkl ended up with — useful when you let the server pick the state via auto-transitions).",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 17465
                        },
                        "is_rewatch": true,
                        "rewatch_id": 7482,
                        "rewatch_status": "closed",
                        "rating": 10,
                        "memo": {
                          "text": "Rewatched the Stark family arcs ahead of the new book.",
                          "is_private": false
                        },
                        "seasons": [
                          {
                            "number": 1,
                            "episodes": [
                              {
                                "number": 3,
                                "watched_at": "2026-05-16T19:00:00Z"
                              },
                              {
                                "number": 4,
                                "watched_at": "2026-05-16T20:00:00Z"
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "history_partial_with_not_found": {
                  "summary": "PARTIAL SUCCESS: unresolvable item lands in not_found.movies",
                  "description": "When the server's resolver can't match an item (typo, fuzzy miss, ID not in catalog yet), the request still returns 201 — but the item lands in `response.not_found.<media_type>` instead of `response.added.statuses`. The not_found entries are verbatim copies of the input, so apps can show 'we couldn't add: …' UI and offer manual resolution.",
                  "value": {
                    "movies": [
                      {
                        "title": "ZZZ-Definitely-Not-A-Real-Movie-Title-XYZ",
                        "year": 9999
                      }
                    ]
                  }
                },
                "quirk_empty_body_201_zero": {
                  "summary": "EDGE CASE: empty body returns 201, not 400",
                  "description": "`POST /sync/history` with `{}` does not trigger validation — the server returns `201` with zero counts. Only malformed JSON (unparseable) triggers the 400 `json_error` envelope. Pin this behavior in your client: don't infer success from 200 alone, branch on `response.added > 0` if you care.",
                  "value": {}
                }
              },
              "schema": {
                "$ref": "#/components/schemas/HistoryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistoryAddResponse"
                },
                "examples": {
                  "realistic_batch": {
                    "summary": "Realistic batch — multiple movies + shows with mixed IDs, titles, years",
                    "description": "What a tracker app typically sends after a catch-up sync — a mix of media types with whatever identifiers it has on hand. Some entries carry a Simkl ID directly; others use third-party IDs (IMDB / TMDB / TVDB) plus `title` + `year` as fallback. The server resolves every combination to a canonical Simkl record and records the watch events. Use this pattern for backfill from Trakt/Letterboxd/Plex/Jellyfin, where you'll have a varied bag of metadata per item.",
                    "value": {
                      "added": {
                        "movies": 2,
                        "shows": 2,
                        "episodes": 65,
                        "statuses": [
                          {
                            "request": {
                              "watched_at": "2026-05-15T22:30:00Z",
                              "title": "Dune: Part Two",
                              "year": 2024,
                              "ids": {
                                "simkl": 1015859
                              },
                              "type": "movie",
                              "rating": null
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "movie",
                              "anime_type": null
                            }
                          },
                          {
                            "request": {
                              "watched_at": "2026-05-14T20:00:00Z",
                              "title": "Oppenheimer",
                              "year": 2023,
                              "ids": {
                                "imdb": "tt15398776",
                                "tmdb": "872585"
                              },
                              "type": "movie",
                              "rating": null
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "movie",
                              "anime_type": null
                            }
                          },
                          {
                            "request": {
                              "title": "The Last of Us",
                              "year": 2023,
                              "ids": {
                                "simkl": 1411674
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "watching",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          },
                          {
                            "request": {
                              "title": "Breaking Bad",
                              "year": 2008,
                              "ids": {
                                "imdb": "tt0903747"
                              },
                              "status": "completed",
                              "rating": 10,
                              "type": "show"
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "add_movie_watched_no_timestamp": {
                    "summary": "Mark a movie watched right now (no `watched_at`)",
                    "description": "Minimal shape. Server records the watch event at request time. Use this for live UIs where the user just clicked Watched.",
                    "value": {
                      "added": {
                        "movies": 1,
                        "shows": 0,
                        "episodes": 0,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 752138
                              },
                              "type": "movie",
                              "rating": null
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "movie",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "add_movie_watched_with_timestamp": {
                    "summary": "Mark a movie watched at a specific UTC time",
                    "description": "Pin the watch event to an exact moment. Use this for backfilling history from another tracker (Trakt, IMDb watchlist, etc.). `watched_at` is ISO-8601 with `Z` suffix. Omit it to default to the time of the request.",
                    "value": {
                      "added": {
                        "movies": 1,
                        "shows": 0,
                        "episodes": 0,
                        "statuses": [
                          {
                            "request": {
                              "watched_at": "2026-05-01T20:00:00Z",
                              "ids": {
                                "simkl": 752138
                              },
                              "type": "movie",
                              "rating": null
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "movie",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "mark_top_level_episodes_shorthand": {
                    "summary": "GRANULARITY: top-level episodes[] (auto-wrapped to season 1)",
                    "description": "Shorthand for the common case of single-season targeting (or anime AniDB sequential numbering). The server auto-wraps to `seasons: [{number: 1, episodes: [...]}]`.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 2,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 2090
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "watching",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "add_show_episodes_via_seasons": {
                    "summary": "Mark specific TV episodes watched (S01E01-E02)",
                    "description": "Targeted episode-level history. The `seasons` array carries one entry per season with an `episodes` array inside. Each episode can carry its own `watched_at`. Use this for fine-grained backfill or for marking re-watched episodes.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 2,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 2090
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "watching",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "mark_specific_episodes_explicit": {
                    "summary": "GRANULARITY: mark specific episodes — seasons[].episodes[]",
                    "description": "Episode-level targeting. Each episode can carry its own `watched_at` for accurate per-event timestamps. Use this when syncing from a player that emits one event per episode.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 3,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 2090
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "watching",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "mark_whole_season_no_episodes": {
                    "summary": "GRANULARITY: mark whole season — seasons[{number:N}] with no episodes[]",
                    "description": "Mark every episode of season N watched without enumerating them. Each season entry without an `episodes` array is expanded by the server. Useful when a user marks 'I finished season 3' in one click. Combine multiple seasons in the array to mark several at once.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 6,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 2090
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "watching",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "add_show_full_season": {
                    "summary": "Mark an entire TV season watched (season 1, all episodes)",
                    "description": "Shorthand for marking every episode of a season. Omit the `episodes` array; the server enumerates the season's episodes automatically. Watch-time defaults to request time for each episode unless you pass a `watched_at` on the season entry.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 0,
                        "episodes": 6,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 2090
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "watching",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "mark_whole_show_completed": {
                    "summary": "GRANULARITY: mark whole show — no seasons/episodes + status=completed",
                    "description": "Most efficient way to mark an entire show watched: omit `seasons[]` AND `episodes[]`, set `status: \"completed\"`. The server iterates every episode of the series and marks them all watched. Response's `added.episodes` is the total count.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 177,
                        "statuses": [
                          {
                            "request": {
                              "title": "The Walking Dead",
                              "year": 2010,
                              "ids": {
                                "simkl": 2090
                              },
                              "status": "completed",
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "mixed_types_one_call": {
                    "summary": "Mixed types — a movie + a TV episode + an anime episode (anime under `shows[]`)",
                    "description": "Tracker apps batch catch-up syncs by sending every newly-watched item in one call. **Anime entries sit under `shows[]`, not `anime[]`** — Simkl resolves to the anime catalog automatically via the IDs (or via fuzzy title+year). The `anime[]` key still works for backwards compatibility but the cleanest pattern is one `shows[]` array for both TV and anime. The response's `added.statuses[]` array echoes each input with the resolved `simkl_type` (`movie` / `tv` / `anime`) and the watchlist status the item ended up in — `anime_type` (`tv` / `movie` / `ova` / `null`) further disambiguates anime catalog entries.",
                    "value": {
                      "added": {
                        "movies": 1,
                        "shows": 2,
                        "episodes": 2,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 472214
                              },
                              "type": "movie",
                              "rating": null
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "movie",
                              "anime_type": null
                            }
                          },
                          {
                            "request": {
                              "ids": {
                                "simkl": 2090
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          },
                          {
                            "request": {
                              "ids": {
                                "simkl": 831411,
                                "mal": "38000",
                                "anidb": "14116",
                                "anilist": "101922"
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "watching",
                              "simkl_type": "anime",
                              "anime_type": "tv"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "history_rating_plus_status_combined": {
                    "summary": "Combined: mark watched + set status + rate in one request",
                    "description": "Per-item `rating` (1-10) is processed by the same handler as `/sync/ratings`. Combine with `status` to do all three actions in a single round-trip — common for 'I just finished this and want to rate it' UI flows.passes `rating` to.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 177,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 2090
                              },
                              "status": "completed",
                              "rating": 9,
                              "type": "show"
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "history_with_private_memo": {
                    "summary": "Mark watched + attach a PRIVATE memo (self-only notes)",
                    "description": "Same shape as a public memo, but `is_private: true` keeps the text visible only to the owning user. Use for personal notes, rewatch reminders, spoilers, etc. Read-back requires `/sync/all-items?memos=yes` (read-side gating).",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 177,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 2090
                              },
                              "status": "completed",
                              "memo": {
                                "text": "Skip S7 next time, too slow",
                                "is_private": true
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "history_with_public_memo": {
                    "summary": "Mark watched + attach a PUBLIC memo (visible to other users)",
                    "description": "`memo` is a per-item field with two sub-fields: `text` (max 140 chars) and `is_private` (boolean). `is_private: false` makes the memo visible on the user's public Simkl profile and in the activity feed. Use for spoiler-free reactions and recommendations.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 177,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 2090
                              },
                              "status": "completed",
                              "memo": {
                                "text": "Loved every season — best zombie show",
                                "is_private": false
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "completed",
                              "simkl_type": "tv",
                              "anime_type": null
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "add_anime_episode": {
                    "summary": "Mark an anime episode watched",
                    "description": "Anime use the same `shows` body shape as TV — AniDB numbering is single-season, so `seasons[0].number = 1` always. The catalog ID tells the server which catalog (anime vs TV) to dispatch to.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 1,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 831411,
                                "mal": "38000",
                                "anidb": "14116",
                                "anilist": "101922"
                              },
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "watching",
                              "simkl_type": "anime",
                              "anime_type": "tv"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "anime_use_tvdb_seasons_flag": {
                    "summary": "ANIME (Plex/Sonarr): `use_tvdb_anime_seasons: true` with TVDB-only IDs",
                    "description": "Anime have two parallel numbering schemes: **AniDB sequential** (flat single-season) and **TVDB per-season**. Players that source metadata from TheTVDB — Plex, Sonarr, Kodi, Jellyfin — only have the TVDB shape and typically lack `mal`/`anidb`/`anilist` IDs. Pass `use_tvdb_anime_seasons: true` and Simkl maps your TVDB-style `season`+`number` to the canonical AniDB record. This example deliberately uses only TVDB+title+year (no anime-only IDs) to model the real Plex/Sonarr scenario.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 1,
                        "statuses": [
                          {
                            "request": {
                              "title": "Demon Slayer: Kimetsu no Yaiba",
                              "year": 2019,
                              "ids": {
                                "tvdb": "359476",
                                "tvdbslug": "demon-slayer-kimetsu-no-yaiba"
                              },
                              "use_tvdb_anime_seasons": true,
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": "watching",
                              "simkl_type": "anime",
                              "anime_type": "tv"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "rewatch_explicit_flag": {
                    "summary": "Rewatch — explicit `is_rewatch: true` per-item flag on a SHOW (Simkl Pro / VIP)",
                    "description": "Set `is_rewatch: true` on the item AND pass `?allow_rewatch=yes` to force the rewatch path. The VIP response includes `rewatch_id` and `rewatch_status` in `added.statuses[].response`. **Pin the `rewatch_id` on every subsequent write for the same session** to keep multi-call writes from forking into separate sessions — see the [Rewatches guide](/guides/rewatches).",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 2,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 17465
                              },
                              "is_rewatch": true,
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": 3,
                              "simkl_type": "tv",
                              "anime_type": null,
                              "rewatch_id": 7482,
                              "rewatch_status": "active"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "rewatch_with_allow_rewatch_query": {
                    "summary": "Rewatch — re-post episode with `?allow_rewatch=yes` on a previously-completed ANIME (Simkl Pro / VIP)",
                    "description": "Without `?allow_rewatch=yes`, re-posting a watched episode is a no-op. WITH the query param (and a VIP account), the server creates a rewatch session and the episode counts again. The response includes `rewatch_id` (cache it for subsequent writes in this session) and `rewatch_status` (`active`/`completed`/`closed`).",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 2,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 37089,
                                "mal": "1",
                                "anidb": "23",
                                "anilist": "1"
                              },
                              "is_rewatch": true,
                              "type": "show",
                              "rating": null
                            },
                            "response": {
                              "status": 3,
                              "simkl_type": "anime",
                              "anime_type": "tv",
                              "rewatch_id": 7484,
                              "rewatch_status": "active"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "rewatch_max_info": {
                    "summary": "Rewatch — maximum info (every rewatch field populated, all wired to a real session) (Simkl Pro / VIP)",
                    "description": "Every per-item rewatch field set: `is_rewatch:true`, `rewatch_id` (to resume a specific session), `rewatch_status` (to explicitly close/complete/reactivate it), per-episode `watched_at`, plus the standard `rating` and `memo: {text, is_private}` fields. This is what a tracker app's *\"finished my rewatch\"* button would send.\n\nThe response echoes every field you set in `added.statuses[].request` AND surfaces the resulting `rewatch_id` + `rewatch_status` in `added.statuses[].response` (so you can confirm the session state Simkl ended up with — useful when you let the server pick the state via auto-transitions).",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 0,
                        "episodes": 2,
                        "statuses": [
                          {
                            "request": {
                              "ids": {
                                "simkl": 17465
                              },
                              "is_rewatch": true,
                              "rewatch_id": 7482,
                              "rewatch_status": "closed",
                              "rating": 10,
                              "memo": {
                                "text": "Rewatched the Stark family arcs ahead of the new book.",
                                "is_private": false
                              },
                              "type": "show"
                            },
                            "response": {
                              "status": 3,
                              "simkl_type": "tv",
                              "anime_type": null,
                              "rewatch_id": 7482,
                              "rewatch_status": "closed"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "history_partial_with_not_found": {
                    "summary": "PARTIAL SUCCESS: unresolvable item lands in not_found.movies",
                    "description": "When the server's resolver can't match an item (typo, fuzzy miss, ID not in catalog yet), the request still returns 201 — but the item lands in `response.not_found.<media_type>` instead of `response.added.statuses`. The not_found entries are verbatim copies of the input, so apps can show 'we couldn't add: …' UI and offer manual resolution.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 0,
                        "episodes": 0,
                        "statuses": []
                      },
                      "not_found": {
                        "movies": [
                          {
                            "title": "ZZZ-Definitely-Not-A-Real-Movie-Title-XYZ",
                            "year": 9999,
                            "rating": null
                          }
                        ],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  },
                  "quirk_empty_body_201_zero": {
                    "summary": "EDGE CASE: empty body returns 201, not 400",
                    "description": "`POST /sync/history` with `{}` does not trigger validation — the server returns `201` with zero counts. Only malformed JSON (unparseable) triggers the 400 `json_error` envelope. Pin this behavior in your client: don't infer success from 200 alone, branch on `response.added > 0` if you care.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 0,
                        "episodes": 0,
                        "statuses": []
                      },
                      "not_found": {
                        "movies": [],
                        "shows": [],
                        "episodes": []
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/add-to-history",
          "metadata": {
            "sidebarTitle": "Add to History"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "realistic_batch",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"movies\": [\n    {\n      \"watched_at\": \"2026-05-15T22:30:00Z\",\n      \"title\": \"Dune: Part Two\",\n      \"year\": 2024,\n      \"ids\": {\n        \"simkl\": 1015859\n      }\n    },\n    {\n      \"watched_at\": \"2026-05-14T20:00:00Z\",\n      \"title\": \"Oppenheimer\",\n      \"year\": 2023,\n      \"ids\": {\n        \"imdb\": \"tt15398776\",\n        \"tmdb\": \"872585\"\n      }\n    }\n  ],\n  \"shows\": [\n    {\n      \"title\": \"The Last of Us\",\n      \"year\": 2023,\n      \"ids\": {\n        \"simkl\": 1411674\n      },\n      \"seasons\": [\n        {\n          \"number\": 1,\n          \"episodes\": [\n            {\n              \"number\": 1,\n              \"watched_at\": \"2026-05-13T19:00:00Z\"\n            },\n            {\n              \"number\": 2,\n              \"watched_at\": \"2026-05-13T20:00:00Z\"\n            },\n            {\n              \"number\": 3,\n              \"watched_at\": \"2026-05-14T18:30:00Z\"\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"title\": \"Breaking Bad\",\n      \"year\": 2008,\n      \"ids\": {\n        \"imdb\": \"tt0903747\"\n      },\n      \"status\": \"completed\",\n      \"rating\": 10\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "add_movie_watched_no_timestamp",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"movies\": [\n    {\n      \"ids\": {\n        \"simkl\": 752138\n      }\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "add_movie_watched_with_timestamp",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"movies\": [\n    {\n      \"watched_at\": \"2026-05-01T20:00:00Z\",\n      \"ids\": {\n        \"simkl\": 752138\n      }\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "mark_top_level_episodes_shorthand",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 2090\n      },\n      \"episodes\": [\n        {\n          \"number\": 1\n        },\n        {\n          \"number\": 2\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "add_show_episodes_via_seasons",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 2090\n      },\n      \"seasons\": [\n        {\n          \"number\": 1,\n          \"episodes\": [\n            {\n              \"number\": 1,\n              \"watched_at\": \"2026-05-01T20:00:00Z\"\n            },\n            {\n              \"number\": 2,\n              \"watched_at\": \"2026-05-01T21:00:00Z\"\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "mark_specific_episodes_explicit",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 2090\n      },\n      \"seasons\": [\n        {\n          \"number\": 1,\n          \"episodes\": [\n            {\n              \"number\": 1\n            },\n            {\n              \"number\": 2\n            },\n            {\n              \"number\": 3\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "mark_whole_season_no_episodes",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 2090\n      },\n      \"seasons\": [\n        {\n          \"number\": 1\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "add_show_full_season",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 2090\n      },\n      \"seasons\": [\n        {\n          \"number\": 1\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "mark_whole_show_completed",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"title\": \"The Walking Dead\",\n      \"year\": 2010,\n      \"ids\": {\n        \"simkl\": 2090\n      },\n      \"status\": \"completed\"\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "mixed_types_one_call",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"movies\": [\n    {\n      \"ids\": {\n        \"simkl\": 472214\n      }\n    }\n  ],\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 2090\n      },\n      \"seasons\": [\n        {\n          \"number\": 1,\n          \"episodes\": [\n            {\n              \"number\": 1\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"ids\": {\n        \"simkl\": 831411,\n        \"mal\": 38000,\n        \"anidb\": 14116,\n        \"anilist\": 101922\n      },\n      \"seasons\": [\n        {\n          \"number\": 1,\n          \"episodes\": [\n            {\n              \"number\": 1\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "history_rating_plus_status_combined",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 2090\n      },\n      \"status\": \"completed\",\n      \"rating\": 9\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "history_with_private_memo",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 2090\n      },\n      \"status\": \"completed\",\n      \"memo\": {\n        \"text\": \"Skip S7 next time, too slow\",\n        \"is_private\": true\n      }\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "history_with_public_memo",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 2090\n      },\n      \"status\": \"completed\",\n      \"memo\": {\n        \"text\": \"Loved every season — best zombie show\",\n        \"is_private\": false\n      }\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "add_anime_episode",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 831411,\n        \"mal\": 38000,\n        \"anidb\": 14116,\n        \"anilist\": 101922\n      },\n      \"seasons\": [\n        {\n          \"number\": 1,\n          \"episodes\": [\n            {\n              \"number\": 1\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "anime_use_tvdb_seasons_flag",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"title\": \"Demon Slayer: Kimetsu no Yaiba\",\n      \"year\": 2019,\n      \"ids\": {\n        \"tvdb\": \"359476\",\n        \"tvdbslug\": \"demon-slayer-kimetsu-no-yaiba\"\n      },\n      \"use_tvdb_anime_seasons\": true,\n      \"seasons\": [\n        {\n          \"number\": 2,\n          \"episodes\": [\n            {\n              \"number\": 5,\n              \"watched_at\": \"2026-05-16T22:00:00Z\"\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "rewatch_explicit_flag",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?allow_rewatch=yes&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 17465\n      },\n      \"is_rewatch\": true,\n      \"seasons\": [\n        {\n          \"number\": 1,\n          \"episodes\": [\n            {\n              \"number\": 1\n            },\n            {\n              \"number\": 2\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "rewatch_with_allow_rewatch_query",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?allow_rewatch=yes&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 37089,\n        \"mal\": 1,\n        \"anidb\": 23,\n        \"anilist\": 1\n      },\n      \"is_rewatch\": true,\n      \"seasons\": [\n        {\n          \"number\": 1,\n          \"episodes\": [\n            {\n              \"number\": 1\n            },\n            {\n              \"number\": 2\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "rewatch_max_info",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?allow_rewatch=yes&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"shows\": [\n    {\n      \"ids\": {\n        \"simkl\": 17465\n      },\n      \"is_rewatch\": true,\n      \"rewatch_id\": 7482,\n      \"rewatch_status\": \"completed\",\n      \"rating\": 10,\n      \"memo\": {\n        \"text\": \"Rewatched the Stark family arcs ahead of the new book.\",\n        \"is_private\": false\n      },\n      \"seasons\": [\n        {\n          \"number\": 1,\n          \"episodes\": [\n            {\n              \"number\": 3,\n              \"watched_at\": \"2026-05-16T19:00:00Z\"\n            },\n            {\n              \"number\": 4,\n              \"watched_at\": \"2026-05-16T20:00:00Z\"\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "history_partial_with_not_found",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"movies\": [\n    {\n      \"title\": \"ZZZ-Definitely-Not-A-Real-Movie-Title-XYZ\",\n      \"year\": 9999\n    }\n  ]\n}'"
          },
          {
            "lang": "curl",
            "label": "quirk_empty_body_201_zero",
            "source": "curl -X POST 'https://api.simkl.com/sync/history?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0' \\\n  -H 'User-Agent: my-app-name/1.0' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{}'"
          }
        ]
      }
    },
    "/sync/history/remove": {
      "post": {
        "operationId": "post-sync-history-remove",
        "summary": "Remove from History",
        "description": "Removes items from the user's watched history. **Body shape is identical to [`POST /sync/history`](/api-reference/simkl/add-to-history)** — the same `movies[]`, `shows[]`, and granularity rules apply.\n\n#### Granularity\n\nWhat you send determines what gets removed.\n\n**Movie or show with no `seasons` and no `episodes`** — the item is **removed from the user's library entirely** (any watch history AND the watchlist entry). Equivalent to the user clicking \"Remove from list\" on the title page.\n\n```json\n{ \"shows\": [{ \"ids\": {...} }] }\n```\n\n**Show with `seasons[]` entries that omit `episodes`** — every episode in those seasons is unmarked as watched. The show stays in the user's library.\n\n```json\n{ \"shows\": [{ \"ids\": {...}, \"seasons\": [{ \"number\": 2 }] }] }\n```\n\n**Show with `seasons[].episodes[]`** — only the listed episodes are unmarked. The show stays in the user's library.\n\n```json\n{\n  \"shows\": [{\n    \"ids\": {...},\n    \"seasons\": [{\n      \"number\": 1,\n      \"episodes\": [{ \"number\": 1 }, { \"number\": 2 }]\n    }]\n  }]\n}\n```\n\n**Show with top-level `episodes[]` shorthand** — treated as `seasons: [{ number: 1, episodes: [...] }]`. Convenient for single-season shows; otherwise prefer the explicit form.\n\n```json\n{ \"shows\": [{ \"ids\": {...}, \"episodes\": [{ \"number\": 1 }] }] }\n```\n\n#### Response shape\n\nStatus: **201 Created**.\n\n```json\n{\n  \"deleted\": {\n    \"movies\":   <number of movies removed>,\n    \"shows\":    <number of shows removed from library>,\n    \"episodes\": <number of episodes unmarked>\n  },\n  \"not_found\": {\n    \"movies\": [<items Simkl could not match>],\n    \"shows\":  [<items Simkl could not match>]\n  }\n}\n```\n\n**`not_found` only has `movies` and `shows`** — there's no `not_found.episodes` array even when you tried to remove specific episodes. If the parent show isn't matchable, the show object lands in `not_found.shows` and no episodes are touched. If the show is matchable but a specific episode number doesn't exist, the call still counts as success and `episodes` in `deleted` reflects only the episodes that were actually unmarked.\n\n**Anime titles** go in `shows[]` (with anime-only IDs like `anidb` / `mal` / `anilist` inside each item's `ids` object). There is no top-level `anime[]` array on this endpoint — items sent under one are silently ignored. See [Anime under shows[]](/conventions/standard-media-objects#anime).\n\n<CardGroup cols={2}>\n  <Card title=\"POST /sync/history\" icon=\"clock\" href=\"/api-reference/simkl/add-to-history\" horizontal>\n    The mirror endpoint that adds history. Same body shape; this page is the removal side.\n  </Card>\n  <Card title=\"Sync guide — full walkthrough\" icon=\"arrows-rotate\" href=\"/guides/sync\" horizontal>\n    Two-phase model (initial pull → activities-checked delta loop), deletion reconciliation, and reference implementations.\n  </Card>\n</CardGroup>\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HistoryRequest"
              },
              "examples": {
                "remove_movie_entirely": {
                  "summary": "Remove a movie from history AND watchlist",
                  "value": {
                    "movies": [
                      {
                        "ids": {
                          "simkl": 53536
                        }
                      }
                    ]
                  }
                },
                "remove_specific_episodes": {
                  "summary": "Unmark specific episodes — show stays in library",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "seasons": [
                          {
                            "number": 1,
                            "episodes": [
                              {
                                "number": 1
                              },
                              {
                                "number": 2
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "remove_whole_season": {
                  "summary": "Unmark every episode in a season — pass season with no episodes",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "seasons": [
                          {
                            "number": 2
                          }
                        ]
                      }
                    ]
                  }
                },
                "remove_entire_show": {
                  "summary": "Remove the entire show from the user's library",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        }
                      }
                    ]
                  }
                },
                "bulk_mixed": {
                  "summary": "Bulk: one movie + episodes from one show in a single call",
                  "value": {
                    "movies": [
                      {
                        "ids": {
                          "simkl": 53536
                        }
                      }
                    ],
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "seasons": [
                          {
                            "number": 3,
                            "episodes": [
                              {
                                "number": 1
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "not_found_unknown_id": {
                  "summary": "Unknown ID lands in `not_found` — partial success is normal",
                  "value": {
                    "movies": [
                      {
                        "ids": {
                          "simkl": 99999991
                        }
                      }
                    ]
                  }
                },
                "anime_under_shows": {
                  "summary": "Anime title goes in `shows[]` with anime-only IDs",
                  "value": {
                    "shows": [
                      {
                        "title": "Demon Slayer",
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Counts of items affected, plus any IDs Simkl could not match.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistoryRemoveResponse"
                },
                "examples": {
                  "remove_movie_entirely": {
                    "summary": "Remove a movie from history AND watchlist",
                    "value": {
                      "deleted": {
                        "movies": 1,
                        "shows": 0,
                        "episodes": 0
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "remove_specific_episodes": {
                    "summary": "Unmark specific episodes — show stays in library",
                    "value": {
                      "deleted": {
                        "movies": 0,
                        "shows": 0,
                        "episodes": 2
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "remove_whole_season": {
                    "summary": "Unmark every episode in a season — pass season with no episodes",
                    "value": {
                      "deleted": {
                        "movies": 0,
                        "shows": 0,
                        "episodes": 13
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "remove_entire_show": {
                    "summary": "Remove the entire show from the user's library",
                    "value": {
                      "deleted": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 0
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "bulk_mixed": {
                    "summary": "Bulk: one movie + episodes from one show in a single call",
                    "value": {
                      "deleted": {
                        "movies": 1,
                        "shows": 0,
                        "episodes": 1
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "not_found_unknown_id": {
                    "summary": "Unknown ID lands in `not_found` — partial success is normal",
                    "value": {
                      "deleted": {
                        "movies": 0,
                        "shows": 0,
                        "episodes": 0
                      },
                      "not_found": {
                        "movies": [
                          {
                            "ids": {
                              "simkl": 99999991
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      }
                    }
                  },
                  "anime_under_shows": {
                    "summary": "Anime title goes in `shows[]` with anime-only IDs",
                    "value": {
                      "deleted": {
                        "movies": 0,
                        "shows": 1,
                        "episodes": 0
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/remove-from-history",
          "metadata": {
            "sidebarTitle": "Remove from History"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/sync/playback/{id}": {
      "delete": {
        "operationId": "delete-sync-playback-id",
        "summary": "Delete Playback",
        "description": "Removes a saved playback session by its `id`. **HTTP method is `DELETE`** — using `POST` or `GET` against this URL will not delete and will instead hit the list handler. Get the IDs from [`GET /sync/playback/{type}`](/api-reference/simkl/get-playback-sessions).\n\n#### Possible responses\n\n| Status | `error` | When |\n|---|---|---|\n| `204` | — | Session deleted. |\n| `404` | `empty` | The `id` is numeric but does not match any playback session for this user. |\n| `404` | `url_failed` | The `id` segment is missing, `0`, or non-numeric (e.g. `notanumber`, `abc123`). |\n\n<Warning>\n**Use `DELETE` and pass a real positive integer id.** Calling `POST` or `GET /sync/playback/<id>` does **not** delete anything — non-`DELETE` requests to this URL return the user's paused-playback list instead, the same shape as [`GET /sync/playback`](/api-reference/simkl/get-playback-sessions). Always explicitly send `DELETE`, and pass an `id` you got from [`GET /sync/playback/{type}`](/api-reference/simkl/get-playback-sessions). `DELETE /sync/playback/0`, `DELETE /sync/playback` (no id), and `DELETE /sync/playback/<non-numeric>` all return `404 url_failed`.\n</Warning>\n\n<Card title=\"Scrobble guide — full walkthrough\" icon=\"play\" href=\"/guides/scrobble\" horizontal>\n 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).\n</Card>",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL — DELETE with -X",
            "source": "curl -X DELETE \\\n  -H \"Authorization: Bearer YOUR_ACCESS_TOKEN\" \\\n  -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/sync/playback/10916890?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "JavaScript",
            "label": "fetch() — method: 'DELETE'",
            "source": "// Get a real id from GET /sync/playback/{type} first. Never pass 0.\nconst playbackId = 10916890;\nconst qs = new URLSearchParams({\n  client_id: \"YOUR_CLIENT_ID\",\n  \"app-name\": \"my-app-name\",\n  \"app-version\": \"1.0\",\n});\n\nconst res = await fetch(\n  `https://api.simkl.com/sync/playback/${playbackId}?${qs}`,\n  {\n    method: \"DELETE\", // <-- must be DELETE, not POST or GET\n    headers: {\n      Authorization: `Bearer ${ACCESS_TOKEN}`,\n      \"User-Agent\": \"my-app-name/1.0\",\n    },\n  }\n);\n\nif (res.status === 204) {\n  console.log(\"deleted\");\n} else if (res.status === 404) {\n  const { error } = await res.json();\n  console.warn(error === \"empty\" ? \"already gone\" : \"bad id shape\");\n}"
          },
          {
            "lang": "Python",
            "label": "httpx — client.delete()",
            "source": "# Get a real id from GET /sync/playback/{type} first. Never pass 0.\nimport httpx\n\nplayback_id = 10916890\nparams = {\n    \"client_id\": \"YOUR_CLIENT_ID\",\n    \"app-name\": \"my-app-name\",\n    \"app-version\": \"1.0\",\n}\nheaders = {\n    \"Authorization\": f\"Bearer {ACCESS_TOKEN}\",\n    \"User-Agent\": \"my-app-name/1.0\",\n}\n\nr = httpx.delete(  # <-- must be .delete(), not .post() or .get()\n    f\"https://api.simkl.com/sync/playback/{playback_id}\",\n    params=params,\n    headers=headers,\n)\nif r.status_code == 204:\n    print(\"deleted\")\nelif r.status_code == 404:\n    print(\"already gone\" if r.json()[\"error\"] == \"empty\" else \"bad id shape\")"
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The numeric playback-session id to delete. Must be a positive integer — pass values returned in the `id` field of [`GET /sync/playback/{type}`](/api-reference/simkl/get-playback-sessions). Non-numeric ids return `404 url_failed`; the literal value `0` is interpreted as \"no id\" and falls through to the list handler (see Warning above).",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 10916890
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "204": {
            "description": "Session deleted.",
            "headers": {},
            "content": {}
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "The id does not match a playback session for this user, OR the id segment is non-numeric. The `error` field disambiguates: `empty` = no such session; `url_failed` = bad URL shape.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "no_such_session": {
                    "summary": "Numeric id has no matching session for this user",
                    "value": {
                      "error": "empty",
                      "code": 404
                    }
                  },
                  "non_numeric_id": {
                    "summary": "Id segment is not a positive integer (e.g. `notanumber`)",
                    "value": {
                      "error": "url_failed",
                      "code": 404
                    }
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/delete-playback",
          "metadata": {
            "sidebarTitle": "Delete Playback"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/sync/playback": {
      "get": {
        "operationId": "get-sync-playback-all",
        "summary": "Get paused playback sessions for every type",
        "description": "Returns the user's paused playback sessions across all types (movies, shows, anime). For a single type see [`GET /sync/playback/{type}`](/api-reference/simkl/get-playback-sessions).\n\nUseful for \"Continue Watching\" rails that mix types.\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlaybackLimitQuery"
          },
          {
            "$ref": "#/components/parameters/PlaybackHideWatchedQuery"
          },
          {
            "$ref": "#/components/parameters/PlaybackDateFromQuery"
          },
          {
            "$ref": "#/components/parameters/PlaybackDateToQuery"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PlaybackListResponse"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-playback-sessions-all",
          "metadata": {
            "sidebarTitle": "Playback (all types)"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/sync/playback/{type}": {
      "get": {
        "operationId": "get-sync-playback-type",
        "summary": "Get paused playback sessions for one type",
        "description": "Returns the user's saved paused playbacks — created by `/scrobble/pause` or `/scrobble/stop` with progress < 80%. The `{type}` segment is optional:\n\n| Path | Returns |\n|---|---|\n| `GET /sync/playback` | All paused playbacks (episodes + movies). |\n| `GET /sync/playback/episodes` | TV/anime episode playbacks only. |\n| `GET /sync/playback/movies` | Movie playbacks only. |\n\nThe response shape is identical across the three forms; only the included items differ. Resume a session by calling [`/scrobble/start`](/api-reference/simkl/scrobble-start) with the same item.\n\n#### Query parameters\n\n| Param | Effect | Default |\n|---|---|---|\n| `date_from` | Only sessions with `paused_at >= date_from`. | — |\n| `date_to` | Only sessions with `paused_at < date_to`. | — |\n| `hide_watched` | Exclude items already watched after the pause was created. | `true` |\n| `limit` | Max items returned (1–10000). | `10000` |\n\n#### Item shape\n\n```json\n{\n  \"id\": 12345,\n  \"progress\": 42.2,\n  \"paused_at\": \"2024-04-30T22:13:00Z\",\n  \"type\": \"episode\",\n  \"episode\": {\n    \"season\": 1,\n    \"number\": 3,\n    \"title\": \"Chapter Three: Holly Jolly\",\n    \"tvdb_season\": 1,\n    \"tvdb_number\": 3\n  },\n  \"show\": {\n    \"title\": \"Stranger Things\",\n    \"year\": 2016,\n    \"ids\": {\n      \"simkl\": 39687,\n      \"imdb\": \"tt4574334\",\n      \"tvdb\": 305288\n    }\n  }\n}\n```\n\n> Note: `progress` is a **percentage (0-100)** — same scale as the scrobble endpoints. The example values shown above (`75`, `45.5`, `42.2`) are real outputs from the API.\n\nMembers can browse and clean these up at [simkl.com/my/history/playback-progress-manager](https://simkl.com/my/history/playback-progress-manager/).\n\n#### Retention by plan\n\n- **Free** — 7 days · **PRO** — 30 days · **VIP** — 90 days\n\nSessions persist until they're manually removed via [`DELETE /sync/playback/{id}`](/api-reference/simkl/delete-playback), replaced by the next scrobble update on the same title, or aged out per the plan retention window above. They are not auto-deleted on `paused_at` expiry — you'll see the same session in the response indefinitely until one of those three things happens.\n\n<Card title=\"Scrobble guide — full walkthrough\" icon=\"play\" href=\"/guides/scrobble\" horizontal>\n 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).\n</Card>\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlaybackTypeQuery"
          },
          {
            "$ref": "#/components/parameters/PlaybackLimitQuery"
          },
          {
            "$ref": "#/components/parameters/PlaybackHideWatchedQuery"
          },
          {
            "$ref": "#/components/parameters/PlaybackDateFromQuery"
          },
          {
            "$ref": "#/components/parameters/PlaybackDateToQuery"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PlaybackListResponse"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-playback-sessions",
          "metadata": {
            "sidebarTitle": "Playback (by type)"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/sync/ratings": {
      "post": {
        "operationId": "post-sync-ratings",
        "summary": "Add Ratings",
        "description": "Apply user ratings (1-10) to movies, shows, or anime. Same auth model and batching rules as the rest of the [Sync API](/guides/sync). To **read** ratings back, use [`GET /sync/ratings/:type/:rating`](/api-reference/simkl/get-user-ratings) — see **Read side** below.\n\n#### Body shape\n\nTop-level keys per media type, each carrying an array of items:\n\n```json\n{\n  \"movies\": [\n    {\n      \"rating\": 8,\n      \"ids\": {\n        \"simkl\": 53536\n      }\n    }\n  ],\n  \"shows\": [\n    {\n      \"rating\": 9,\n      \"ids\": {\n        \"tmdb\": \"1399\"\n      }\n    }\n  ],\n  \"anime\": [\n    {\n      \"rating\": 10,\n      \"ids\": {\n        \"mal\": \"11757\"\n      },\n      \"rated_at\": \"2026-05-15T20:00:00Z\"\n    }\n  ]\n}\n```\n\nPer-item fields:\n\n| Field      | Type    | Required | Notes |\n|---|---|---|---|\n| `rating`   | int 1-10 | yes | Out-of-range values (`0`, `11`, negatives) are **silently ignored** — see **Out-of-range** below. |\n| `ids`      | object  | yes | Any [supported ID](/conventions/standard-media-objects#supported-id-keys): `simkl`, `imdb`, `tmdb`, `tvdb`, `mal`, `anidb`, `anilist`, `kitsu`, `livechart`, `anisearch`, `animeplanet`. Plus optional `title`+`year` fallback. |\n| `rated_at` | ISO-8601 | no | Defaults to \"now\". Use to back-date imports from another tracker. |\n\nRe-rating an item **overwrites** the prior value — no need to call `/sync/ratings/remove` first.\n\n#### Auto-move side effect\n\nRating an item that's not yet on the user's list **auto-files it** based on airing status:\n\n| Item kind                                                    | New status     |\n|---|---|\n| Released movie                                                | `completed`    |\n| Unreleased / upcoming movie                                   | `plantowatch`  |\n| Single-episode show                                           | `completed`    |\n| Multi-episode show or anime (any other case)                  | `watching`     |\n\nThe corresponding list timestamp on [`/sync/activities`](/api-reference/simkl/get-activities) bumps, so a rated item shows up in the next `date_from` delta even though the user only rated it. Treat the delta as authoritative.\n\n#### Response (201 Created)\n\n```json\n{\n  \"added\": {\n    \"movies\": 1,\n    \"shows\": 1,\n    \"statuses\": [\n      {\n        \"request\": {\n          \"rating\": 8,\n          \"ids\": {\n            \"simkl\": 53536\n          }\n        },\n        \"response\": {\n          \"status\": \"completed\"\n        }\n      }\n    ]\n  },\n  \"not_found\": {\n    \"movies\": [],\n    \"shows\": []\n  }\n}\n```\n\n**`added.anime` does NOT exist.** Anime items are folded into the `shows` counter — apps must not look for a separate `anime` slot in `added` or `not_found`. If you need to know which items landed, walk `added.statuses[]` (the `request.ids` echo back what you sent).\n\n`response.status` per item is the watchlist status the auto-move applied (`completed`, `watching`, `plantowatch`, etc.) — useful for updating local UI without a follow-up `/sync/activities` poll.\n\n#### Out-of-range ratings\n\nAny `rating` outside 1-10 (including `0`, `11`, `-1`, `100`) is **silently rejected** — the item lands in `not_found.<type>` and the HTTP status is still `201`. No `400` is returned; the rejection is reported in the response body, not the status code. **Clients must validate client-side**; never trust that a 2xx response means the rating was applied. Always inspect `added.statuses[]` (or `not_found`) to confirm.\n\n#### Read side\n\n`GET /sync/ratings` returns every rated item across all types in one response, keyed by media type:\n\n```json\n{\n  \"movies\": [ { ..., \"user_rating\": 8, \"user_rated_at\": \"2026-05-13T...\" } ],\n  \"shows\":  [ { ..., \"user_rating\": 9, ... } ],\n  \"anime\":  [ { ..., \"user_rating\": 10, ... } ]\n}\n```\n\nEach item carries the standard watchlist record (status, episode counts, dates) plus `user_rating` (int 1-10 or `null`) and `user_rated_at` (ISO-8601 UTC or `null`).\n\nRead ratings back with [`GET /sync/ratings/:type/:rating`](/api-reference/simkl/get-user-ratings). For **public catalog** ratings (the community average + IMDb/MAL score for any title, no token required), the rating data is in the per-title detail endpoints — [`GET /movies/:id`](/api-reference/simkl/get-movie), [`GET /tv/:id`](/api-reference/simkl/get-tv-show), [`GET /anime/:id`](/api-reference/simkl/get-anime) — under the `ratings` field. Resolve external IDs first via [`GET /redirect`](/api-reference/simkl/redirect).\n\n#### Removing a rating\n\nUse [`POST /sync/ratings/remove`](/api-reference/simkl/remove-ratings) with the same body shape minus the `rating` field (the value is ignored on remove). Removing the rating does **not** remove the item from the user's watchlist — only the score is cleared.\n\n#### Rate alongside a watch event\n\nIf you're recording a watch event and want to attach a rating in the same call, use [`POST /sync/history`](/api-reference/simkl/add-to-history) — it accepts a `rating` field per item. One round-trip instead of two.\n\n<Card title=\"Sync guide — full walkthrough\" icon=\"arrows-rotate\" href=\"/guides/sync\" horizontal>\n  Two-phase model (initial pull -> activities-checked delta loop), `date_from` semantics, deletion reconciliation, edge cases, and reference implementations in Node and Python.\n</Card>\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "movies": [
                  {
                    "title": "Terminator 3: Rise of the Machines",
                    "rating": 8,
                    "rated_at": "2014-09-01T09:10:11.000Z",
                    "year": "2003",
                    "ids": {
                      "imdb": "tt0181852",
                      "tmdb": "296",
                      "simkl": 53536
                    }
                  },
                  {
                    "rating": 6,
                    "ids": {
                      "simkl": 210728
                    }
                  }
                ],
                "shows": [
                  {
                    "title": "Attack on Titan",
                    "year": 2013,
                    "rating": 10,
                    "ids": {
                      "simkl": 39687,
                      "mal": "16498",
                      "tvdb": "267440",
                      "imdb": "tt2560140",
                      "anidb": "9541"
                    }
                  }
                ]
              },
              "schema": {
                "$ref": "#/components/schemas/RatingsAddRequest"
              },
              "examples": {
                "bulk_rate_cross_media_types": {
                  "summary": "Bulk rate across all three media types in one request",
                  "description": "The body can carry `movies`, `shows`, and `anime` arrays simultaneously — useful when importing ratings from another tracker.",
                  "value": {
                    "movies": [
                      {
                        "rating": 7,
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ],
                    "shows": [
                      {
                        "rating": 9,
                        "ids": {
                          "simkl": 2090
                        }
                      }
                    ],
                    "anime": [
                      {
                        "rating": 8,
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        }
                      }
                    ]
                  }
                },
                "overwrite_movie_rating": {
                  "summary": "Overwrite an existing rating (5 → 9)",
                  "description": "Re-POSTing the same item with a different `rating` replaces the stored value. No need to call /sync/ratings/remove first.",
                  "value": {
                    "movies": [
                      {
                        "rating": 9,
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "quirk_out_of_range_rating_-1": {
                  "summary": "Quirk: server accepts rating -1 (out of 1-10 range)",
                  "description": "The server returned status 201 for `rating: -1`. Stored value lookup: None. Validate ratings client-side; the server does not enforce the documented 1-10 range.",
                  "value": {
                    "movies": [
                      {
                        "rating": -1,
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "quirk_out_of_range_rating_0": {
                  "summary": "Quirk: server accepts rating 0 (out of 1-10 range)",
                  "description": "The server returned status 201 for `rating: 0`. Stored value lookup: None. Validate ratings client-side; the server does not enforce the documented 1-10 range.",
                  "value": {
                    "movies": [
                      {
                        "rating": 0,
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "quirk_out_of_range_rating_100": {
                  "summary": "Quirk: server accepts rating 100 (out of 1-10 range)",
                  "description": "The server returned status 201 for `rating: 100`. Stored value lookup: None. Validate ratings client-side; the server does not enforce the documented 1-10 range.",
                  "value": {
                    "movies": [
                      {
                        "rating": 100,
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "quirk_out_of_range_rating_11": {
                  "summary": "Quirk: server accepts rating 11 (out of 1-10 range)",
                  "description": "The server returned status 201 for `rating: 11`. Stored value lookup: None. Validate ratings client-side; the server does not enforce the documented 1-10 range.",
                  "value": {
                    "movies": [
                      {
                        "rating": 11,
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "rate_anime_8": {
                  "summary": "Rate an anime 8/10",
                  "description": "Anime use the `anime` array key in the REQUEST. (Note: in the /sync/ratings/{type}/{rating} READ response, anime are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                  "value": {
                    "anime": [
                      {
                        "rating": 8,
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        }
                      }
                    ]
                  }
                },
                "rate_movie_1": {
                  "summary": "Rate a movie 1/10",
                  "description": "Standard rating shape. The server stores the value verbatim (no rounding). Re-POSTing with a different rating overwrites; there's no need to call /sync/ratings/remove first.",
                  "value": {
                    "movies": [
                      {
                        "rating": 1,
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "rate_movie_10": {
                  "summary": "Rate a movie 10/10",
                  "description": "Standard rating shape. The server stores the value verbatim (no rounding). Re-POSTing with a different rating overwrites; there's no need to call /sync/ratings/remove first.",
                  "value": {
                    "movies": [
                      {
                        "rating": 10,
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "rate_movie_5": {
                  "summary": "Rate a movie 5/10",
                  "description": "Standard rating shape. The server stores the value verbatim (no rounding). Re-POSTing with a different rating overwrites; there's no need to call /sync/ratings/remove first.",
                  "value": {
                    "movies": [
                      {
                        "rating": 5,
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "rate_movie_8": {
                  "summary": "Rate a movie 8/10",
                  "description": "Standard rating shape. The server stores the value verbatim (no rounding). Re-POSTing with a different rating overwrites; there's no need to call /sync/ratings/remove first.",
                  "value": {
                    "movies": [
                      {
                        "rating": 8,
                        "ids": {
                          "simkl": 752138
                        }
                      }
                    ]
                  }
                },
                "rate_show_9": {
                  "summary": "Rate a TV show 9/10",
                  "description": "Same shape as movies; just swap the array key to `shows`.",
                  "value": {
                    "shows": [
                      {
                        "rating": 9,
                        "ids": {
                          "simkl": 2090
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "example": {
                  "added": {
                    "movies": 2,
                    "shows": 1,
                    "statuses": [
                      {
                        "request": {
                          "title": "Terminator 3: Rise of the Machines",
                          "year": "2003",
                          "rated_at": "2014-09-01T09:10:11.000Z",
                          "rating": 8,
                          "ids": {
                            "imdb": "tt0181852",
                            "tmdb": "296",
                            "simkl": 53536
                          }
                        },
                        "response": {
                          "status": "completed"
                        }
                      },
                      {
                        "request": {
                          "rating": 6,
                          "ids": {
                            "simkl": 210728
                          }
                        },
                        "response": {
                          "status": "completed"
                        }
                      },
                      {
                        "request": {
                          "title": "Attack on Titan",
                          "year": 2013,
                          "rating": 10,
                          "ids": {
                            "simkl": 39687,
                            "mal": "16498",
                            "tvdb": "267440",
                            "imdb": "tt2560140",
                            "anidb": "9541"
                          }
                        },
                        "response": {
                          "status": "watching"
                        }
                      }
                    ]
                  },
                  "not_found": {
                    "movies": [],
                    "shows": []
                  }
                },
                "schema": {
                  "$ref": "#/components/schemas/RatingsAddResponse"
                }
              }
            }
          },
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RatingsAddResponse"
                },
                "examples": {
                  "bulk_rate_cross_media_types": {
                    "summary": "Bulk rate across all three media types in one request",
                    "description": "The body can carry `movies`, `shows`, and `anime` arrays simultaneously — useful when importing ratings from another tracker.",
                    "value": {
                      "added": {
                        "movies": 1,
                        "shows": 2,
                        "statuses": [
                          {
                            "request": {
                              "rating": 7,
                              "ids": {
                                "simkl": 752138
                              },
                              "type": "movie"
                            },
                            "response": {
                              "status": "completed"
                            }
                          },
                          {
                            "request": {
                              "rating": 9,
                              "ids": {
                                "simkl": 2090
                              },
                              "type": "show"
                            },
                            "response": {
                              "status": "watching"
                            }
                          },
                          {
                            "request": {
                              "rating": 8,
                              "ids": {
                                "simkl": 831411,
                                "mal": "38000",
                                "anidb": "14116",
                                "anilist": "101922"
                              },
                              "type": "show"
                            },
                            "response": {
                              "status": "watching"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "overwrite_movie_rating": {
                    "summary": "Overwrite an existing rating (5 → 9)",
                    "description": "Re-POSTing the same item with a different `rating` replaces the stored value. No need to call /sync/ratings/remove first.",
                    "value": {
                      "added": {
                        "movies": 1,
                        "shows": 0,
                        "statuses": [
                          {
                            "request": {
                              "rating": 9,
                              "ids": {
                                "simkl": 752138
                              },
                              "type": "movie"
                            },
                            "response": {
                              "status": "completed"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "quirk_out_of_range_rating_-1": {
                    "summary": "Quirk: server accepts rating -1 (out of 1-10 range)",
                    "description": "The server returned status 201 for `rating: -1`. Stored value lookup: None. Validate ratings client-side; the server does not enforce the documented 1-10 range.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 0,
                        "statuses": []
                      },
                      "not_found": {
                        "movies": [
                          {
                            "rating": -1,
                            "ids": {
                              "simkl": 752138
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      }
                    }
                  },
                  "quirk_out_of_range_rating_0": {
                    "summary": "Quirk: server accepts rating 0 (out of 1-10 range)",
                    "description": "The server returned status 201 for `rating: 0`. Stored value lookup: None. Validate ratings client-side; the server does not enforce the documented 1-10 range.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 0,
                        "statuses": []
                      },
                      "not_found": {
                        "movies": [
                          {
                            "rating": 0,
                            "ids": {
                              "simkl": 752138
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      }
                    }
                  },
                  "quirk_out_of_range_rating_100": {
                    "summary": "Quirk: server accepts rating 100 (out of 1-10 range)",
                    "description": "The server returned status 201 for `rating: 100`. Stored value lookup: None. Validate ratings client-side; the server does not enforce the documented 1-10 range.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 0,
                        "statuses": []
                      },
                      "not_found": {
                        "movies": [
                          {
                            "rating": 100,
                            "ids": {
                              "simkl": 752138
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      }
                    }
                  },
                  "quirk_out_of_range_rating_11": {
                    "summary": "Quirk: server accepts rating 11 (out of 1-10 range)",
                    "description": "The server returned status 201 for `rating: 11`. Stored value lookup: None. Validate ratings client-side; the server does not enforce the documented 1-10 range.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 0,
                        "statuses": []
                      },
                      "not_found": {
                        "movies": [
                          {
                            "rating": 11,
                            "ids": {
                              "simkl": 752138
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      }
                    }
                  },
                  "rate_anime_8": {
                    "summary": "Rate an anime 8/10",
                    "description": "Anime use the `anime` array key in the REQUEST. (Note: in the /sync/ratings/{type}/{rating} READ response, anime are wrapped in `show:` for cross-catalog compatibility — see /conventions/null-values.)",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "statuses": [
                          {
                            "request": {
                              "rating": 8,
                              "ids": {
                                "simkl": 831411,
                                "mal": "38000",
                                "anidb": "14116",
                                "anilist": "101922"
                              },
                              "type": "show"
                            },
                            "response": {
                              "status": "watching"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "rate_movie_1": {
                    "summary": "Rate a movie 1/10",
                    "description": "Standard rating shape. The server stores the value verbatim (no rounding). Re-POSTing with a different rating overwrites; there's no need to call /sync/ratings/remove first.",
                    "value": {
                      "added": {
                        "movies": 1,
                        "shows": 0,
                        "statuses": [
                          {
                            "request": {
                              "rating": 1,
                              "ids": {
                                "simkl": 752138
                              },
                              "type": "movie"
                            },
                            "response": {
                              "status": "completed"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "rate_movie_10": {
                    "summary": "Rate a movie 10/10",
                    "description": "Standard rating shape. The server stores the value verbatim (no rounding). Re-POSTing with a different rating overwrites; there's no need to call /sync/ratings/remove first.",
                    "value": {
                      "added": {
                        "movies": 1,
                        "shows": 0,
                        "statuses": [
                          {
                            "request": {
                              "rating": 10,
                              "ids": {
                                "simkl": 752138
                              },
                              "type": "movie"
                            },
                            "response": {
                              "status": "completed"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "rate_movie_5": {
                    "summary": "Rate a movie 5/10",
                    "description": "Standard rating shape. The server stores the value verbatim (no rounding). Re-POSTing with a different rating overwrites; there's no need to call /sync/ratings/remove first.",
                    "value": {
                      "added": {
                        "movies": 1,
                        "shows": 0,
                        "statuses": [
                          {
                            "request": {
                              "rating": 5,
                              "ids": {
                                "simkl": 752138
                              },
                              "type": "movie"
                            },
                            "response": {
                              "status": "completed"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "rate_movie_8": {
                    "summary": "Rate a movie 8/10",
                    "description": "Standard rating shape. The server stores the value verbatim (no rounding). Re-POSTing with a different rating overwrites; there's no need to call /sync/ratings/remove first.",
                    "value": {
                      "added": {
                        "movies": 1,
                        "shows": 0,
                        "statuses": [
                          {
                            "request": {
                              "rating": 8,
                              "ids": {
                                "simkl": 752138
                              },
                              "type": "movie"
                            },
                            "response": {
                              "status": "completed"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "rate_show_9": {
                    "summary": "Rate a TV show 9/10",
                    "description": "Same shape as movies; just swap the array key to `shows`.",
                    "value": {
                      "added": {
                        "movies": 0,
                        "shows": 1,
                        "statuses": [
                          {
                            "request": {
                              "rating": 9,
                              "ids": {
                                "simkl": 2090
                              },
                              "type": "show"
                            },
                            "response": {
                              "status": "watching"
                            }
                          }
                        ]
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/add-ratings",
          "metadata": {
            "sidebarTitle": "Add Ratings"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/sync/ratings/remove": {
      "post": {
        "operationId": "post-sync-ratings-remove",
        "summary": "Remove Ratings",
        "description": "Clears the user's ratings on the listed items. **Body shape is identical to [`POST /sync/ratings`](/api-reference/simkl/add-ratings) minus the `rating` field** — the IDs alone are enough to identify which entries to un-rate.\n\n<Note>\n**Removing a rating does NOT remove the item from the user's watchlist** — it only clears the rating value. The item keeps its watchlist status (`watching` / `completed` / etc.) and stays in the library. To remove an item from the user's library entirely, use [`POST /sync/history/remove`](/api-reference/simkl/remove-from-history).\n</Note>\n\n#### Response shape\n\nStatus: **201 Created**.\n\n```json\n{\n  \"deleted\": {\n    \"movies\": <number of movies un-rated>,\n    \"shows\":  <number of shows un-rated (anime included)>\n  },\n  \"not_found\": {\n    \"movies\": [<items Simkl could not match>],\n    \"shows\":  [<items Simkl could not match>]\n  }\n}\n```\n\n**No `anime` key** — anime is folded under `shows` on both the request and response side, same as on [`POST /sync/ratings`](/api-reference/simkl/add-ratings). Send anime titles in `shows[]` with anime-only IDs (`mal`, `anidb`, `anilist`, `kitsu`) inside each item's `ids` object.\n\n**`deleted` counts matched items**, not items that actually had a rating. If you send a movie that Simkl resolves to a canonical record but the user never rated it, that movie still counts in `deleted.movies`. The call is idempotent — sending the same body twice has the same end state on the second call as on the first.\n\n<CardGroup cols={2}>\n  <Card title=\"POST /sync/ratings\" icon=\"star\" href=\"/api-reference/simkl/add-ratings\" horizontal>\n    The mirror endpoint that sets ratings. Same body shape minus the `rating` field on each item.\n  </Card>\n  <Card title=\"Sync guide — full walkthrough\" icon=\"arrows-rotate\" href=\"/guides/sync\" horizontal>\n    The two-phase sync model and how rating activity surfaces in `/sync/activities`.\n  </Card>\n</CardGroup>\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RatingsRemoveRequest"
              },
              "examples": {
                "remove_movie_rating": {
                  "summary": "Clear a user's rating on a movie",
                  "value": {
                    "movies": [
                      {
                        "ids": {
                          "simkl": 53536
                        }
                      }
                    ]
                  }
                },
                "remove_show_rating": {
                  "summary": "Clear a user's rating on a TV show",
                  "value": {
                    "shows": [
                      {
                        "ids": {
                          "simkl": 17465
                        }
                      }
                    ]
                  }
                },
                "remove_anime_rating": {
                  "summary": "Anime rating — send under `shows[]`",
                  "value": {
                    "shows": [
                      {
                        "title": "Demon Slayer",
                        "ids": {
                          "simkl": 831411,
                          "mal": "38000",
                          "anidb": "14116",
                          "anilist": "101922"
                        }
                      }
                    ]
                  }
                },
                "bulk_cross_type": {
                  "summary": "Bulk: clear ratings on a movie and a show in a single call",
                  "value": {
                    "movies": [
                      {
                        "ids": {
                          "simkl": 53536
                        }
                      }
                    ],
                    "shows": [
                      {
                        "ids": {
                          "simkl": 2090
                        }
                      }
                    ]
                  }
                },
                "not_found_unknown_id": {
                  "summary": "Unknown ID lands in `not_found` — partial success is normal",
                  "value": {
                    "movies": [
                      {
                        "ids": {
                          "simkl": 99999991
                        }
                      }
                    ]
                  }
                },
                "empty_body": {
                  "summary": "Empty body returns the zero-counter shape",
                  "value": {}
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Counts of items affected, plus any IDs Simkl could not match.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RatingsRemoveResponse"
                },
                "examples": {
                  "remove_movie_rating": {
                    "summary": "Clear a user's rating on a movie",
                    "value": {
                      "deleted": {
                        "movies": 1,
                        "shows": 0
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "remove_show_rating": {
                    "summary": "Clear a user's rating on a TV show",
                    "value": {
                      "deleted": {
                        "movies": 0,
                        "shows": 1
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "remove_anime_rating": {
                    "summary": "Anime rating — send under `shows[]`",
                    "value": {
                      "deleted": {
                        "movies": 0,
                        "shows": 1
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "bulk_cross_type": {
                    "summary": "Bulk: clear ratings on a movie and a show in a single call",
                    "value": {
                      "deleted": {
                        "movies": 1,
                        "shows": 1
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  },
                  "not_found_unknown_id": {
                    "summary": "Unknown ID lands in `not_found` — partial success is normal",
                    "value": {
                      "deleted": {
                        "movies": 0,
                        "shows": 0
                      },
                      "not_found": {
                        "movies": [
                          {
                            "ids": {
                              "simkl": 99999991
                            },
                            "type": "movie"
                          }
                        ],
                        "shows": []
                      }
                    }
                  },
                  "empty_body": {
                    "summary": "Empty body returns the zero-counter shape",
                    "value": {
                      "deleted": {
                        "movies": 0,
                        "shows": 0
                      },
                      "not_found": {
                        "movies": [],
                        "shows": []
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/remove-ratings",
          "metadata": {
            "sidebarTitle": "Remove Ratings"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/sync/ratings/{type}/{rating}": {
      "get": {
        "operationId": "get-user-ratings",
        "summary": "Get the user's rated items, filtered by type and rating",
        "description": "Returns the items **the user has rated themselves** — filtered to one type (movies, shows, or anime) and one or more rating values.\n\n#### Path parameters\n\n| Segment | What to send |\n|---|---|\n| `type` | `movies`, `shows`, or `anime`. |\n| `rating` | A single value `1`–`10`, or a comma-separated list like `8,9,10`. |\n\nExample: `GET /sync/ratings/movies/9,10` returns every movie the user rated 9 or 10.\n\n#### Want every rated item in one type?\n\nPass the full list as a CSV: `GET /sync/ratings/movies/1,2,3,4,5,6,7,8,9,10`. The response then includes only items the user actually rated (any value from 1 to 10) and skips unrated library items.\n\n#### Common query parameters\n\nSame as [`GET /sync/all-items`](/api-reference/simkl/get-all-items): `extended`, `date_from`, `episode_watched_at`, `memos`, `language`. Use `date_from` after [`GET /sync/activities`](/api-reference/simkl/get-activities) tells you `rated_at` has bumped to pull only the newly-changed ratings.\n\n<Note>\n**This is the user's own 1–10 scores — not the Simkl community average.** If you want Simkl's public ratings for items in the user's watchlist, use [`GET /ratings/{type}`](/api-reference/simkl/get-watchlist-ratings) instead.\n</Note>\n\n<Note>\n**Already pulling the full library via [`GET /sync/all-items`](/api-reference/simkl/get-all-items)?** Each item there already carries `user_rating` (1–10 or `null`) and `user_rated_at`. Filter client-side with `item.user_rating === 9` instead of calling this endpoint. Use `/sync/ratings/{type}/{rating}` only when you want the server to do the filtering — typically the first load of a bulk-rating UI that just needs \"all my 9s and 10s\" without downloading the whole library.\n</Note>\n\n#### Silent fallbacks (no errors)\n\nThe API is forgiving here and won't return a `400` when you pass something odd — it just returns an empty or unexpected result. Worth knowing so you don't think the user has no ratings when the URL was actually wrong:\n\n| URL | What you get back |\n|---|---|\n| `/sync/ratings/tv_shows/9` (any unrecognized type word) | `200` with **cross-type** results at rating 9 — the type segment is silently ignored, not validated. The correct word is `shows`, not `tv_shows`. |\n| `/sync/ratings/movies/99` (out of range) | `200 {}` — the value is accepted but never matches any 1–10 rating. |\n| `/sync/ratings/movies` (rating segment omitted) | `200` with the user's **entire movie library**, including unrated items (each carries `user_rating: null`). Effectively the same as [`GET /sync/all-items/movies`](/api-reference/simkl/get-all-items) — prefer that route since it's the documented one. |\n\n<Card title=\"Sync guide — full walkthrough\" icon=\"arrows-rotate\" href=\"/guides/sync\" horizontal>\n Two-phase model (initial pull → activities-checked delta loop), `date_from` semantics, deletion reconciliation, edge cases, and reference implementations in Node and Python.\n</Card>\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "$ref": "#/components/parameters/UserRatingsTypeQuery"
          },
          {
            "$ref": "#/components/parameters/UserRatingsRatingQuery"
          },
          {
            "$ref": "#/components/parameters/DateFromParam"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/UserRatingsListResponse"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-user-ratings",
          "metadata": {
            "sidebarTitle": "User ratings"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/sync/watched": {
      "post": {
        "operationId": "post-sync-watched",
        "summary": "Look up watched status for items",
        "description": "POST an array of items you already know about; Simkl returns a parallel array telling you, **per item**, whether it's in the user's library, its current status, last-watched timestamp, and (optionally) per-episode breakdown.\n\nUse this **only** when you don't already cache the user's full library locally — typical case is a media-server plugin or a deep-link landing page that needs to check \"is this title in the user's tracker yet?\" for a handful of specific titles, without syncing the whole library first.\n\n> ⚠️ **Don't use this endpoint if your app already pulls [`GET /sync/all-items/{type}/{status}`](/api-reference/simkl/get-all-items).** The full-library response already contains the same per-item watch state, statuses, and last-watched timestamps that `/sync/watched` returns — your local cache has the answer. Calling both is wasted requests, counts twice against your rate-limit quota, and is one of the patterns that gets an app's `client_id` suspended. The correct loop for tracker apps that sync the full library is the two-phase model: full pull once, then `/sync/activities`-gated incremental refresh — see the [Sync guide](/guides/sync).\n\n#### Item identification\n\nEach input item carries one or more IDs. Simkl resolves to the canonical record before looking up watch state, so any of these work:\n\n| ID style | Example |\n|---|---|\n| Simkl ID | `{ \"ids\": { \"simkl\": 2090 } }` |\n| IMDb / TMDB / TVDB / MAL / AniDB / AniList / Kitsu | `{ \"ids\": { \"imdb\": \"tt1520211\" } }` |\n| Title + year fallback | `{ \"title\": \"Inception\", \"year\": 2010 }` |\n\nPair `season` + `episode` on an item to ask 'has the user watched this specific episode?' instead of 'is this title in the library?'.\n\n#### Query params\n\n| Param | Effect |\n|---|---|\n| `extended=episodes` | Include per-episode breakdown (`seasons[].episodes[]` arrays) for shows/anime. **Limit: 100 items per call** when this is set — sending more triggers `400 max_items`. |\n| `extended=specials` | Include specials (season `0`). Only effective when combined with `episodes`. |\n| `extended=counters` | When sent **alone** (without `episodes`), the `seasons[]` array is included but its `episodes[]` arrays are omitted — useful when you only want totals without the per-episode payload. When sent **together with `episodes`**, the per-episode arrays are still included. |\n\nMultiple values are comma-separated: `extended=episodes,specials`.\n\n#### Response shape (per item)\n\nThe response is an array of the same length as the request, in the same order. Each entry echoes the input identifiers and adds:\n\n| Field | When present | Notes |\n|---|---|---|\n| `result` | always | `true` if the user has watched (or is watching) this item. `false` if Simkl matched the IDs but the item isn't in the user's library. `\"not_found\"` if Simkl couldn't match the IDs at all — in this case only `result` is returned, no `simkl`/`list`/etc. |\n| `simkl` | when `result` ≠ `\"not_found\"` | Canonical Simkl ID. |\n| `list` | when matched | Current watchlist status (`watching`, `completed`, `plantowatch`, `hold`, `dropped`) or `null` if not in any list. |\n| `last_watched_at` | when matched | ISO-8601 timestamp of the most recent watch event, or `null` if never watched. |\n| `episodes_total` / `episodes_aired` / `episodes_to_be_aired` / `episodes_watched` | with `extended=episodes` or `extended=counters` (shows/anime only) | Aggregate counts across all seasons. |\n| `seasons[]` | with `extended=episodes` or `extended=counters` (shows/anime only) | Per-season `{number, episodes_total, episodes_aired, episodes_to_be_aired, episodes_watched}`. With `extended=episodes` alone, each season also includes an `episodes[]` array (per-episode `{number, watched, aired, last_watched_at}`). With `extended=counters` alone, `episodes[]` is omitted. |\n\n**Empty body quirk.** Sending an empty array `[]` returns the literal `null` (not `[]`). Treat both as 'no items to check'.\n\n#### Errors\n\n| Status | `error` | When |\n|---|---|---|\n| 400 | `max_items` | More than 100 items in a single call when `extended=episodes` (or any other `extended` value that triggers per-episode loading) is set. |\n\n<Card title=\"Sync guide — full walkthrough\" icon=\"arrows-rotate\" href=\"/guides/sync\" horizontal>\n Two-phase model (initial pull → activities-checked delta loop), `date_from` semantics, when to use `/sync/watched` vs `/sync/all-items`, and reference implementations.\n</Card>\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "name": "extended",
            "in": "query",
            "description": "Comma-separated combination of `counters`, `episodes`, `specials`. Order does not matter; empty or unknown values are ignored. Examples: `counters`, `episodes,specials`, `counters,episodes,specials`.",
            "schema": {
              "type": "string",
              "pattern": "^(counters|episodes|specials)(,(counters|episodes|specials))*$"
            },
            "example": "episodes,specials"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "one_movie_in_library": {
                  "summary": "Single movie — known to Simkl but not in user's library",
                  "value": [
                    {
                      "ids": {
                        "simkl": 53536
                      }
                    }
                  ]
                },
                "one_show_in_library": {
                  "summary": "Single show — in user's library, completed",
                  "value": [
                    {
                      "ids": {
                        "simkl": 2090
                      }
                    }
                  ]
                },
                "unknown_id_not_found": {
                  "summary": "ID couldn't be resolved — minimal `result: not_found` shape",
                  "value": [
                    {
                      "ids": {
                        "simkl": 99999991
                      }
                    }
                  ]
                },
                "bulk_mixed_results": {
                  "summary": "Three items: known-but-not-watched, not_found, in-library",
                  "value": [
                    {
                      "ids": {
                        "simkl": 53536
                      }
                    },
                    {
                      "ids": {
                        "simkl": 99999992
                      }
                    },
                    {
                      "ids": {
                        "simkl": 17465
                      }
                    }
                  ]
                },
                "show_with_full_episodes": {
                  "summary": "Show with `extended=episodes` — full per-episode breakdown",
                  "value": [
                    {
                      "ids": {
                        "simkl": 2090
                      }
                    }
                  ]
                },
                "show_with_counters_only": {
                  "summary": "Show with `extended=counters` — totals but no per-episode arrays",
                  "value": [
                    {
                      "ids": {
                        "simkl": 2090
                      }
                    }
                  ]
                },
                "specific_episode_lookup": {
                  "summary": "Per-episode lookup via `season` + `episode` on the input item",
                  "value": [
                    {
                      "ids": {
                        "simkl": 2090
                      },
                      "season": 1,
                      "episode": 1
                    }
                  ]
                },
                "title_year_fallback": {
                  "summary": "Title + year fallback (no IDs) — Simkl resolves to canonical record",
                  "value": [
                    {
                      "title": "Inception",
                      "year": 2010
                    }
                  ]
                }
              },
              "schema": {
                "$ref": "#/components/schemas/WatchedLookupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Array of per-item watch results in input order.",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WatchedLookupResponse"
                },
                "examples": {
                  "one_movie_in_library": {
                    "summary": "Single movie — known to Simkl but not in user's library",
                    "value": [
                      {
                        "ids": {
                          "simkl": 53536
                        },
                        "result": false,
                        "simkl": 53536,
                        "list": null,
                        "last_watched_at": null
                      }
                    ]
                  },
                  "one_show_in_library": {
                    "summary": "Single show — in user's library, completed",
                    "value": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "result": true,
                        "simkl": 2090,
                        "list": "completed",
                        "last_watched_at": "2026-05-15T00:35:15Z"
                      }
                    ]
                  },
                  "unknown_id_not_found": {
                    "summary": "ID couldn't be resolved — minimal `result: not_found` shape",
                    "value": [
                      {
                        "ids": {
                          "simkl": 99999991
                        },
                        "result": "not_found"
                      }
                    ]
                  },
                  "bulk_mixed_results": {
                    "summary": "Three items: known-but-not-watched, not_found, in-library",
                    "value": [
                      {
                        "ids": {
                          "simkl": 53536
                        },
                        "result": false,
                        "simkl": 53536,
                        "list": null,
                        "last_watched_at": null
                      },
                      {
                        "ids": {
                          "simkl": 99999992
                        },
                        "result": "not_found"
                      },
                      {
                        "ids": {
                          "simkl": 17465
                        },
                        "result": true,
                        "simkl": 17465,
                        "list": "completed",
                        "last_watched_at": "2026-05-15T00:13:18Z"
                      }
                    ]
                  },
                  "show_with_full_episodes": {
                    "summary": "Show with `extended=episodes` — full per-episode breakdown",
                    "value": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "result": true,
                        "simkl": 2090,
                        "list": "completed",
                        "last_watched_at": "2026-05-15T00:35:15Z",
                        "episodes_total": 177,
                        "episodes_aired": 177,
                        "episodes_to_be_aired": 0,
                        "episodes_watched": 177,
                        "seasons": [
                          {
                            "number": 1,
                            "episodes_total": 6,
                            "episodes_aired": 6,
                            "episodes_to_be_aired": 0,
                            "episodes_watched": 6,
                            "episodes": [
                              {
                                "number": 1,
                                "watched": true,
                                "aired": true,
                                "last_watched_at": null
                              },
                              {
                                "number": 2,
                                "watched": true,
                                "aired": true,
                                "last_watched_at": null
                              },
                              {
                                "number": 3,
                                "watched": true,
                                "aired": true,
                                "last_watched_at": null
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  },
                  "show_with_counters_only": {
                    "summary": "Show with `extended=counters` — totals but no per-episode arrays",
                    "value": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "result": true,
                        "simkl": 2090,
                        "list": "completed",
                        "last_watched_at": "2026-05-15T00:35:15Z",
                        "episodes_total": 177,
                        "episodes_aired": 177,
                        "episodes_to_be_aired": 0,
                        "episodes_watched": 177,
                        "seasons": [
                          {
                            "number": 1,
                            "episodes_total": 6,
                            "episodes_aired": 6,
                            "episodes_to_be_aired": 0,
                            "episodes_watched": 6
                          }
                        ]
                      }
                    ]
                  },
                  "specific_episode_lookup": {
                    "summary": "Per-episode lookup via `season` + `episode` on the input item",
                    "value": [
                      {
                        "ids": {
                          "simkl": 2090
                        },
                        "season": 1,
                        "episode": 1,
                        "result": true,
                        "simkl": 2090,
                        "list": "completed",
                        "last_watched_at": "2026-05-15T00:35:15Z"
                      }
                    ]
                  },
                  "title_year_fallback": {
                    "summary": "Title + year fallback (no IDs) — Simkl resolves to canonical record",
                    "value": [
                      {
                        "title": "Inception",
                        "year": 2010,
                        "result": false,
                        "simkl": 472214,
                        "list": null,
                        "last_watched_at": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — most commonly fired when `extended=episodes` (or any extended value that triggers per-episode loading) is combined with more than 100 items in a single call.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "max_items",
                  "code": 400
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Sync"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-watched",
          "metadata": {
            "sidebarTitle": "Lookup watched"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ]
      }
    },
    "/tv/airing": {
      "get": {
        "operationId": "get-tv-airing-date",
        "summary": "TV shows airing today, tomorrow, or on a specific date",
        "description": "Currently airing TV shows — same data that powers the [Simkl TV calendar](https://simkl.com/tv/airing/). No `access_token` required.\n\nSame shape and parameters as [`/anime/airing`](/api-reference/simkl/get-anime-airing) but for the TV catalog: no `anime_type` field, and the per-item `episode` block includes a `season` integer.\n\n<Warning>\n**Prefer the cached calendar endpoints for high-traffic use cases.** `/tv/airing` is **uncached** — every request hits the origin. For widgets, mobile-app home screens, or anything that fetches this on app launch / wake / timer, use the CDN-cached [Calendar data files](/api-reference/calendar) on `data.simkl.in` instead — both the rolling-window `/calendar/{type}.json` (yesterday + next 33 days) and the monthly archive `/calendar/{year}/{month}/{type}.json` serve the same per-day airing data, edge-cached so most requests don't even reach origin. Reserve `/tv/airing` for ad-hoc queries by a specific date that the calendar files don't pre-bake.\n\nBoth forms still need the standard URL params on every request — `client_id`, `app-name`, `app-version` (and the `User-Agent` header) — same as every other Simkl endpoint. See [Headers and required parameters](/conventions/headers).\n</Warning>\n\n#### Query parameters\n\n| Param | Default | Notes |\n|---|---|---|\n| `date` | `today` | `today`, `tomorrow`, or `DD-MM-YYYY`. Bogus values silently fall back to `today`. |\n| `sort` | `time` | `time`, `rank`, `popularity`. Bogus values silently fall back to `time`. |\n\n#### Item shape\n\n```json\n{\n  \"title\": \"string\",\n  \"year\": \"integer | null  (extracted from the episode air time)\",\n  \"date\": \"ISO-8601 string with -05:00 offset | null\",\n  \"poster\": \"string  (relative path; prepend https://simkl.in/posters/ + size)\",\n  \"rank\": \"integer | null  (Simkl popularity rank; null when not yet ranked)\",\n  \"url\": \"string  (relative simkl.com URL)\",\n  \"ids\": {\n    \"simkl_id\": \"integer\",\n    \"slug\": \"string\"\n  },\n  \"episode\": {\n    \"season\": \"integer\",\n    \"episode\": \"integer\",\n    \"url\": \"string\"\n  }\n}\n```\n\n#### Nulls — what they mean\n\n| Field | When null | Type |\n|---|---|---|\n| `date` | Catalog has no `Airs_Time` on file for this episode (rare — usually older or low-data titles) | [Type 4](/conventions/null-values#type-4) |\n| `rank` | Item not yet ranked, or rank value >= 999999 sentinel | [Type 4](/conventions/null-values#type-4) |\n\n#### Error responses\n\n| Status | When |\n|---|---|\n| `412 client_id_failed` | Missing or invalid `client_id` |\n| `500` | Server error |\n\nNo `400` — invalid `date`/`sort` values silently fall back to defaults. No `404` — empty result is `[]` with status `200`.\n",
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "description": "only data within this date",
            "schema": {
              "type": "string",
              "pattern": "^(today|tomorrow|\\d{2}-\\d{2}-\\d{4})$"
            },
            "example": "22-08-2026",
            "required": false
          },
          {
            "name": "sort",
            "in": "query",
            "description": "sort the results by the specified option",
            "schema": {
              "type": "string",
              "enum": [
                "time",
                "rank",
                "popularity"
              ]
            },
            "example": "time"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "year": {
                        "type": [
                          "integer",
                          "null"
                        ],
                        "description": "Year extracted from the episode's `Airs_Time`. Type 4 null when no air time on file. See [Null and missing values](/conventions/null-values)."
                      },
                      "date": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "format": "date-time",
                        "description": "Episode air time as ISO-8601 with `-05:00` offset (Simkl's server timezone). Type 4 null — catalog has no `Airs_Time` for this episode (rare; older or low-data titles). See [Null and missing values](/conventions/null-values)."
                      },
                      "poster": {
                        "type": "string",
                        "description": "Image path fragment. Combine with the prefixes in [Image conventions](/conventions/images) — for example `https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`."
                      },
                      "rank": {
                        "type": [
                          "integer",
                          "null"
                        ],
                        "description": "Simkl popularity rank. Type 4 null when not yet ranked or when the catalog sentinel value (>= 999999) is present. See [Null and missing values](/conventions/null-values)."
                      },
                      "url": {
                        "type": "string",
                        "description": "Relative simkl.com URL."
                      },
                      "ids": {
                        "type": "object",
                        "properties": {
                          "simkl_id": {
                            "type": "integer"
                          },
                          "slug": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "simkl_id",
                          "slug"
                        ]
                      },
                      "episode": {
                        "type": "object",
                        "properties": {
                          "season": {
                            "type": "integer",
                            "description": "Season number."
                          },
                          "episode": {
                            "type": "integer",
                            "description": "Episode number within the season."
                          },
                          "url": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "episode",
                          "url"
                        ]
                      }
                    },
                    "required": [
                      "title",
                      "year",
                      "date",
                      "poster",
                      "rank",
                      "url",
                      "ids",
                      "episode"
                    ]
                  }
                },
                "example": [
                  {
                    "title": "Men on a Mission",
                    "year": 2026,
                    "date": "2026-05-16T09:00:00-04:00",
                    "poster": "83/8303720832bdd35c5",
                    "rank": 3728,
                    "url": "/tv/584618/men-on-a-mission",
                    "ids": {
                      "simkl_id": 584618,
                      "slug": "men-on-a-mission"
                    },
                    "episode": {
                      "season": 12,
                      "episode": 18,
                      "url": "/tv/584618/men-on-a-mission/season-12/episode-18/"
                    }
                  },
                  {
                    "title": "Silence, ça pousse !",
                    "year": 2026,
                    "date": null,
                    "poster": "10/1004590825e591792b",
                    "rank": null,
                    "url": "/tv/2587369/silence-%C3%A7a-pousse",
                    "ids": {
                      "simkl_id": 2587369,
                      "slug": "silence-%C3%A7a-pousse"
                    },
                    "episode": {
                      "season": 2025,
                      "episode": 36,
                      "url": "/tv/2587369/silence-%C3%A7a-pousse/season-2025/episode-36/"
                    }
                  }
                ]
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "TV"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-tv-airing",
          "metadata": {
            "sidebarTitle": "Airing TV"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/tv/best/{filter}": {
      "get": {
        "summary": "Top-rated TV shows",
        "operationId": "get-best-tv",
        "description": "Top-rated TV shows. Mirrors the [Simkl Best TV](https://simkl.com/tv/best-shows/) pages. No `access_token` required.\n\nPick a bucket via the `{filter}` path segment:\n\n| Filter | What you get |\n|---|---|\n| `all` | All-time top-rated. |\n| `year` | Top-rated for the current year. |\n| `month` | Top-rated for the current month. |\n| `voted` | Most-voted titles (sorted by total IMDB votes). Items also include a `votes` count. |\n| `watched` | Most-watched this month. Items also include a `watched` count. |\n\nUnknown filter values fall back to `all`.\n\nOptionally narrow by `type=series`, `documentary`, `entertainment`, or `animation`. Unknown values are ignored.\n\n<Note>\n**60 items, no pagination.** The endpoint always returns up to 60 items in one call. The `page` and `limit` query parameters are accepted but ignored. For paginated browsing use [`GET /tv/genres/...`](/api-reference/simkl/get-tv-genres).\n</Note>\n\n<Tip>\n**`type=documentary` can return `null`.** When the type filter doesn't match anything in the top set, the response body is bare `null` rather than an empty array. Handle both shapes in your parser.\n</Tip>\n\n#### Errors\n\n| Status | When |\n|---|---|\n| `412` | Missing or invalid `client_id` |\n| `500` | Server error |\n\nUnknown `filter` or `type` values silently fall back — no `400`. The endpoint never returns `404`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BestFilterParam"
          },
          {
            "$ref": "#/components/parameters/BestTVTypeParam"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK — array of items, or bare `null` when a `?type=` filter zeroes the result set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BestResponse"
                },
                "examples": {
                  "All-time top": {
                    "summary": "All-time top",
                    "value": [
                      {
                        "title": "Red Dead Redemption II",
                        "year": 2018,
                        "poster": "14/146907490ae959e0ac",
                        "url": "/tv/2276947/red-dead-redemption-ii",
                        "ids": {
                          "simkl_id": 2276947,
                          "slug": "red-dead-redemption-ii"
                        },
                        "ratings": {
                          "simkl": {
                            "rating": 8.8,
                            "votes": 95
                          },
                          "imdb": {
                            "rating": 9.8,
                            "votes": 80062
                          }
                        }
                      }
                    ]
                  },
                  "Most voted": {
                    "summary": "Most voted",
                    "value": [
                      {
                        "title": "Breaking Bad",
                        "year": 2008,
                        "poster": "97/978343d5161a724",
                        "url": "/tv/11121/breaking-bad",
                        "votes": 2615298,
                        "ids": {
                          "simkl_id": 11121,
                          "slug": "breaking-bad"
                        },
                        "ratings": {
                          "simkl": {
                            "rating": 9.2,
                            "votes": 11657
                          },
                          "imdb": {
                            "rating": 9.5,
                            "votes": 2615298
                          }
                        }
                      }
                    ]
                  },
                  "Most watched this month": {
                    "summary": "Most watched this month",
                    "value": [
                      {
                        "title": "The Boys",
                        "year": 2019,
                        "poster": "19/196289114d7f60aa05",
                        "url": "/tv/967226/the-boys",
                        "watched": 6412,
                        "ids": {
                          "simkl_id": 967226,
                          "slug": "the-boys"
                        },
                        "ratings": {
                          "simkl": {
                            "rating": 8.3,
                            "votes": 6051
                          },
                          "imdb": {
                            "rating": 8.6,
                            "votes": 870349
                          }
                        }
                      }
                    ]
                  },
                  "Documentary filter — empty result returns null": {
                    "summary": "Documentary filter — empty result returns null",
                    "value": null
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "TV"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-best-tv",
          "metadata": {
            "sidebarTitle": "Best of"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "All-time top",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/tv/best/all?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "curl",
            "label": "Most voted",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/tv/best/voted?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "curl",
            "label": "Most watched this month",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/tv/best/watched?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "curl",
            "label": "Documentary filter — empty result returns null",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/tv/best/all?type=documentary&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/tv/episodes/{id}": {
      "get": {
        "operationId": "get-tv-episodes-id",
        "summary": "List episodes for a TV show",
        "description": "Returns the full episode list for a Simkl TV show ID. Items include `season`, `episode`, `title`, `description`, `aired` (boolean), `img`, `date` (timezone-shifted), and `ids.simkl_id`. Specials appear with `type: \"special\"` after the regular episodes.\n\nResponses are **Cloudflare-cached by Simkl ID**, so repeat lookups of popular shows are near-free. Parallel requests against this endpoint are explicitly allowed (see [Rate limits → Parallel requests](/resources/rate-limits#parallel-requests-when-allowed)).\n\n**Cache invalidation is automatic.** When Simkl updates the underlying episode list (new episode airs, airdate change, title edit, image swap, etc.), the corresponding Cloudflare cache entry is purged server-side. The next call returns the fresh data — there's no TTL to wait out. Your own app-level cache, if any, still has to be invalidated by your client.\n\nUse the parent show's Simkl ID. If you only have an external ID, resolve it via [`GET /redirect`](/api-reference/redirect) first.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "**Simkl ID of the TV show** — the parent show's Simkl ID (not an individual episode ID). The endpoint returns the full episode list for that show. Use a Simkl ID directly when you have one — the response is Cloudflare-cached.\n\n**If you only have an external ID** (IMDb, TMDB, TVDB), resolve it to a Simkl ID first via [`GET /redirect`](/api-reference/redirect).",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Array of episode entries ordered by season then episode. Specials follow the regular episodes and carry `type: \"special\"` with no `season`/`episode` numbers. An empty array `[]` is returned for an unknown parent show ID (Type 3 null).",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EpisodeDetail"
                  }
                },
                "examples": {
                  "first_two_episodes": {
                    "summary": "Regular numbered episodes (Walking Dead S01E01–02)",
                    "description": "First two episodes of a premium-cable drama. Standard shape: `season`/`episode` integers, `type: \"episode\"`, `aired: true`, `date` in timezone-shifted ISO format, full description and still image.",
                    "value": [
                      {
                        "title": "Days Gone Bye",
                        "description": "Rick searches for his family after emerging from a coma into a world terrorized by the walking dead. Morgan and Duane, whom he meets along the way, help teach Rick the new rules for survival.",
                        "season": 1,
                        "episode": 1,
                        "type": "episode",
                        "aired": true,
                        "img": "33/33039065126ec2470",
                        "date": "2010-10-31T05:00:00.000Z",
                        "ids": {
                          "simkl_id": 310766
                        }
                      },
                      {
                        "title": "Guts",
                        "description": "Rick unknowingly causes a group of survivors to be trapped by walkers. The group dynamic devolves from accusations to violence, as Rick must confront an enemy far more dangerous than the undead.",
                        "season": 1,
                        "episode": 2,
                        "type": "episode",
                        "aired": true,
                        "img": "33/3303806cc83f0ab83",
                        "date": "2010-11-07T05:00:00.000Z",
                        "ids": {
                          "simkl_id": 310768
                        }
                      }
                    ]
                  },
                  "special_episode": {
                    "summary": "Special / one-off entry",
                    "description": "Specials, clip shows, behind-the-scenes episodes. `type: \"special\"` and the regular `season`/`episode` numbers are omitted entirely (Type 2 null — not applicable to non-numbered content).",
                    "value": [
                      {
                        "title": "Behind The Dead (100 Episodes Special)",
                        "description": "Andrew Lincoln, Norman Reedus, and the rest of the cast and crew reflect on the history and celebrate reaching the 100th episode of The Walking Dead.",
                        "type": "special",
                        "aired": false,
                        "img": "62/6243336c0ad8db221",
                        "date": "2017-10-19T05:00:00.000Z",
                        "ids": {
                          "simkl_id": 2527432
                        }
                      }
                    ]
                  },
                  "unknown_id_empty": {
                    "summary": "Unknown Simkl show ID — empty array (Type 3 null)",
                    "description": "When the parent show's Simkl ID doesn't match any record, the response is `200 []`. Treat as 'show not found'.",
                    "value": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "Empty path segment — the path was hit as `/tv/episodes/` or `/anime/episodes/` (no `id`). Provide a Simkl ID for the parent show or anime in the path. See [Standard media objects -> Supported ID keys](/conventions/standard-media-objects#supported-id-keys).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "empty_id": {
                    "summary": "Empty `id` path segment",
                    "value": {
                      "error": "empty_id",
                      "code": 400
                    }
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "TV"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-tv-episodes",
          "metadata": {
            "sidebarTitle": "TV episodes"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/tv/genres/{genre}/{type}/{country}/{network}/{year}/{sort}": {
      "get": {
        "operationId": "get-tv-genres",
        "summary": "TV by genre",
        "description": "<Warning>\n**Not for TV / console / 10-foot apps.** The V1 genre-browse endpoints return a thin per-item shape (`title`, `year`, `poster`, `ids`, `ratings`, `rank`). Building a TV-app grid that shows overview text, full ratings, networks, runtimes, recommendations, or trailers would force one per-item refetch against the detail endpoint per visible card. **Wait for the V2 Beta API**, which returns the richer per-item shape TV-app surfaces need in a single call. If you're targeting TV / console / streaming-box clients, please hold off integrating these endpoints.\n</Warning>\n\nBrowse TV shows filtered by genre, type, country, network, year, and sort order. Path is `/tv/genres/{genre}/{type}/{country}/{network}/{year}/{sort}` — all segments **required** (use `all` as the wildcard).\n\nThis is the **6-segment** variant (one more than movies + anime — TV has both `country` AND `network` filters).\n\n| Path param | Values |\n|---|---|\n| `genre` | `all`, `action`, `adventure`, `animation`, `awards-show`, `children`, `comedy`, `crime`, `documentary`, `drama`, `erotica`, `family`, `fantasy`, `food`, `game-show`, `history`, `home-and-garden`, `horror`, `indie`, `korean-drama`, `martial-arts`, `mini-series`, `musical`, `mystery`, `news`, `podcast`, `reality`, `romance`, `science-fiction`, `soap`, `special-interest`, `sport`, `suspense`, `talk-show`, `thriller`, `travel`, `video-game-play`, `war`, `western` |\n| `type` | `all`, `series`, `mini-series`, `specials` |\n| `country` | `all` or ISO 3166-1 alpha-2 |\n| `network` | `all` or a network slug (`hbo`, `netflix`, `apple-tv`, `prime-video`, …) |\n| `year` | `all`, single year, or decade |\n| `sort` | `popular-this-week`, `popular-this-month`, `popular-all-time`, `rank`, `release-date`, `voted`, `watched` |\n\n#### Pagination\n\n| Param | Default | Notes |\n|---|---|---|\n| `page` | `1` | Hard-capped server-side at `20`. Higher values clamp silently. |\n| `limit` | `60` | Hard-capped server-side at `60`. Higher values clamp silently. Returned `X-Pagination-Limit` reflects the clamped value. |\n\n`X-Pagination-*` headers on every response — see [Pagination](/conventions/pagination).\n\n#### Silent fallbacks\n\nBad path segments DO NOT return errors:\n\n| Bad input | What happens |\n|---|---|\n| Unknown `genre` slug (`zzz`) | Top-level response is `null` (NOT `[]`). |\n| Unknown `year` (e.g. `zzz`) | Silently treated as `all` — full result set. |\n| Unknown `sort` (`zzzsortzzz`) | Silently treated as default sort order. |\n| Unknown `country` / `network` | Silently treated as `all`. |\n\n#### Errors\n\n| Status | When |\n|---|---|\n| `412 client_id_failed` | Missing or invalid `client_id` |\n| `500` | Server error |\n\nNo `400` or `404` — bad segments fall back silently or return `null`.\n",
        "parameters": [
          {
            "name": "genre",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "drama",
            "description": "TV genre slug, or `all`. See description for the full set."
          },
          {
            "name": "type",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "series",
                "mini-series",
                "specials"
              ]
            },
            "example": "all"
          },
          {
            "name": "country",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "us",
            "description": "ISO 3166-1 alpha-2 country code or `all`."
          },
          {
            "name": "network",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "hbo",
            "description": "Network slug (`hbo`, `netflix`, `apple-tv`, `prime-video`, …) or `all`."
          },
          {
            "name": "year",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "2010s",
            "description": "`all`, single year, or decade. Bogus values silently fall back to `all`."
          },
          {
            "name": "sort",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "popular-this-week",
                "popular-this-month",
                "popular-all-time",
                "rank",
                "release-date",
                "voted",
                "watched"
              ]
            },
            "example": "popular-this-month"
          },
          {
            "$ref": "#/components/parameters/PageParam"
          },
          {
            "$ref": "#/components/parameters/LimitGenresParam"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Pagination-Page": {
                "schema": {
                  "type": "string"
                },
                "description": "Current page (after clamp)."
              },
              "X-Pagination-Limit": {
                "schema": {
                  "type": "string"
                },
                "description": "Items per page (after clamp; max 60)."
              },
              "X-Pagination-Page-Count": {
                "schema": {
                  "type": "string"
                },
                "description": "Total number of pages."
              },
              "X-Pagination-Item-Count": {
                "schema": {
                  "type": "string"
                },
                "description": "Total number of items across all pages."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenresResponse"
                },
                "examples": {
                  "tv_all_us_popular_month": {
                    "summary": "All-genre US TV, popular this month (top 1)",
                    "value": [
                      {
                        "title": "Breaking Bad",
                        "year": 2008,
                        "date": "2008-01-20T00:00:00-05:00",
                        "url": "/tv/11121/breaking-bad",
                        "poster": "97/978343d5161a724",
                        "fanart": "97/97857fa360b6cc6",
                        "ids": {
                          "simkl_id": 11121,
                          "slug": "breaking-bad"
                        },
                        "rank": 2,
                        "ratings": {
                          "simkl": {
                            "rating": 9.2,
                            "votes": 11657
                          },
                          "imdb": {
                            "rating": 9.5,
                            "votes": 2615298
                          }
                        }
                      }
                    ]
                  },
                  "tv_drama_hbo": {
                    "summary": "HBO dramas (network filter narrows to 33 items)",
                    "value": [
                      {
                        "title": "Game of Thrones",
                        "year": 2011,
                        "date": "2011-04-17T00:00:00-05:00",
                        "url": "/tv/17465/game-of-thrones",
                        "poster": "57/5742576cd8f59fcb0",
                        "fanart": "65/651722dcefb6fc87",
                        "ids": {
                          "simkl_id": 17465,
                          "slug": "game-of-thrones"
                        },
                        "rank": 18,
                        "ratings": {
                          "simkl": {
                            "rating": 8.7,
                            "votes": 11832
                          },
                          "imdb": {
                            "rating": 9.2,
                            "votes": 2614875
                          }
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "TV"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-tv-genres",
          "metadata": {
            "sidebarTitle": "Genres"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "tv_all_us_popular_month",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/tv/genres/all/all/us/all/all/popular-this-month?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0&limit=10\""
          },
          {
            "lang": "Shell",
            "label": "tv_drama_hbo",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/tv/genres/drama/all/all/hbo/all/popular-this-month?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0&limit=10\""
          }
        ]
      }
    },
    "/tv/premieres/{param}": {
      "get": {
        "summary": "TV premieres (new + upcoming)",
        "operationId": "get-tv-premieres",
        "description": "TV premieres — recently aired or upcoming new shows. Mirrors the [Simkl TV Premieres](https://simkl.com/tv/premieres/) page. No `access_token` required.\n\nPass `new` for shows that already premiered (newest first), or `soon` for shows premiering in the next few weeks (soonest first). Any path value other than `new` is treated as `soon`.\n\nThe two shapes differ slightly: items in the `new` response include `rank` and `ratings`; items in the `soon` response don't carry those fields at all (the show hasn't aired enough to be ranked or rated yet).\n\n<Note>\n**US and Canada only.** The list is restricted to shows produced in the US or Canada — there's no opt-out. If you want premieres from other regions, use [`GET /tv/genres/{genre}/{type}/{country}/{network}/{year}/{sort}`](/api-reference/simkl/get-tv-genres) with the country segment set to your target (`kr`, `jp`, `gb`, etc.).\n</Note>\n\n#### Query parameters\n\n| Param | Default | Notes |\n|---|---|---|\n| `type` | (any) | Optional. `series` or `documentary`. Anything else is ignored and you get the full list. |\n| `page` | `1` | 1 to 20. Higher values are reduced to 20. |\n| `limit` | `60` | 1 to 60. Higher values are reduced to 60. |\n\n`X-Pagination-*` headers on every response — see [Pagination](/conventions/pagination).\n\nThe full per-item shape is in the **Response** panel on the right.\n\n#### Errors\n\n| Status | When |\n|---|---|\n| `412` | Missing or invalid `client_id` |\n| `500` | Server error |\n\nBogus `param` or `type` values silently fall back — no `400`. The endpoint never returns `404`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PremieresParam"
          },
          {
            "$ref": "#/components/parameters/PremieresTVTypeParam"
          },
          {
            "$ref": "#/components/parameters/PremieresPageParam"
          },
          {
            "$ref": "#/components/parameters/PremieresLimitParam"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK — array of items. Shape depends on `{param}` (see `oneOf` branches).",
            "headers": {
              "X-Pagination-Page": {
                "schema": {
                  "type": "string"
                },
                "description": "Current page (after clamp)."
              },
              "X-Pagination-Limit": {
                "schema": {
                  "type": "string"
                },
                "description": "Items per page (after clamp; max 60)."
              },
              "X-Pagination-Page-Count": {
                "schema": {
                  "type": "string"
                },
                "description": "Total number of pages."
              },
              "X-Pagination-Item-Count": {
                "schema": {
                  "type": "string"
                },
                "description": "Total number of items across all pages."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PremieresResponse"
                },
                "examples": {
                  "Recent releases": {
                    "summary": "Recent releases",
                    "value": [
                      {
                        "title": "Off Campus",
                        "year": 2026,
                        "date": "2026-05-13T00:00:00-05:00",
                        "url": "/tv/2597547/off-campus",
                        "poster": "19/197017756d31040c93",
                        "ids": {
                          "simkl_id": 2597547,
                          "slug": "off-campus"
                        },
                        "rank": 1196,
                        "ratings": {
                          "simkl": {
                            "rating": 7.9,
                            "votes": 24
                          },
                          "imdb": {
                            "rating": 8.2,
                            "votes": 3886
                          }
                        }
                      }
                    ]
                  },
                  "Upcoming": {
                    "summary": "Upcoming",
                    "value": [
                      {
                        "title": "Maximum Pleasure Guaranteed",
                        "year": 2026,
                        "date": "2026-05-20T00:00:00-05:00",
                        "url": "/tv/2727563/maximum-pleasure-guaranteed",
                        "poster": "19/19791825d3c328c88d",
                        "ids": {
                          "simkl_id": 2727563,
                          "slug": "maximum-pleasure-guaranteed"
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "TV"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-tv-premieres",
          "metadata": {
            "sidebarTitle": "Premieres"
          }
        },
        "security": [
          {
            "clientId": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "Recent releases",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/tv/premieres/new?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "curl",
            "label": "Upcoming",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/tv/premieres/soon?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/tv/{id}": {
      "get": {
        "operationId": "get-tv-id",
        "summary": "TV show details",
        "description": "Full detail record for one TV show — title, overview, year, runtime, country, certification, network, genres, status, first/last-aired dates, total episodes, airs schedule, ratings, posters, fanart, external IDs, trailers, user recommendations. The default response is already complete; no flags needed.\n\nResponses are **Cloudflare-cached by Simkl ID**, so repeat lookups of popular titles are near-free. Parallel requests against this endpoint are explicitly allowed (see [Rate limits → Parallel requests](/resources/rate-limits#parallel-requests-when-allowed)).\n\n**Cache invalidation is automatic.** When Simkl updates the underlying record (admin edits, automated metadata refresh, image swap, related-titles change, etc.), the corresponding Cloudflare cache entry is purged server-side. The next call to this endpoint returns the fresh data — there's no TTL to wait out and no client-side cache-busting needed. Your own app-level cache, if any, still has to be invalidated by your client.\n\nUse a Simkl ID for the lookup. If you only have an external ID, resolve it via [`GET /redirect`](/api-reference/redirect) first.\n\n<Tip>\n**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).\n</Tip>",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "**Simkl ID** for the item. Simkl IDs are stable, unambiguous, and the response is Cloudflare-cached by Simkl ID, so repeat lookups are very fast.\n\n**If you only have an external ID** (IMDb, TMDB, TVDB, MAL, AniDB, etc.), resolve it to a Simkl ID first via [`GET /redirect`](/api-reference/redirect) — it returns the Simkl ID in the `Location` header without a JSON payload, and the follow-up detail call is Cloudflare-cached.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "17465"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ShowDetail"
                    },
                    {
                      "type": "array",
                      "items": {},
                      "maxItems": 0,
                      "title": "Empty (unknown Simkl ID)",
                      "description": "Empty array `[]` — see `unknown_id_empty` example below."
                    }
                  ]
                },
                "examples": {
                  "game_of_thrones": {
                    "summary": "Ended HBO drama (Game of Thrones, simkl 17465)",
                    "description": "Premium-network series that finished its run. Demonstrates `status: \"ended\"` (lowercase, like every status value live), the airing-schedule object, `total_episodes` count, and the standard ratings pair (`simkl` + `imdb`). Note `type: \"show\"` — the canonical media-type label for TV records (the URL segment is `/tv/`, but the response `type` field always says `show`). Arrays truncated to keep the doc compact.",
                    "value": {
                      "title": "Game of Thrones",
                      "year": 2011,
                      "type": "show",
                      "ids": {
                        "simkl": 17465,
                        "slug": "game-of-thrones",
                        "tvdb": "121361",
                        "tvdbslug": "game-of-thrones",
                        "imdb": "tt0944947",
                        "tmdb": "1399",
                        "traktslug": "game-of-thrones"
                      },
                      "rank": 6,
                      "droprate": "1.2%",
                      "poster": "57/5742576cd8f59fcb0",
                      "fanart": "65/651708e80d87bb93",
                      "runtime": 52,
                      "certification": "TV-MA",
                      "country": "US",
                      "overview": "Seven noble families fight for control of the mythical land of Westeros. Friction between the houses leads to full-scale war. All while a very ancient evil awakens in the farthest north.",
                      "genres": [
                        "Drama",
                        "Fantasy",
                        "Adventure"
                      ],
                      "network": "HBO",
                      "status": "ended",
                      "first_aired": "2011-04-17",
                      "last_aired": "2019-05-19",
                      "airs": {
                        "day": "Sunday",
                        "time": "21:00",
                        "timezone": "America/New_York"
                      },
                      "total_episodes": 73,
                      "year_start_end": "2011-2019",
                      "ratings": {
                        "simkl": {
                          "rating": 9.1,
                          "votes": 1270
                        },
                        "imdb": {
                          "rating": 9.2,
                          "votes": 2287000
                        }
                      },
                      "trailers": [
                        {
                          "name": "Season 1 Trailer",
                          "youtube": "BpJYNVhGf1s",
                          "size": 1080
                        }
                      ],
                      "users_recommendations": [
                        {
                          "title": "Breaking Bad",
                          "year": 2008,
                          "poster": "97/978343d5161a724",
                          "type": "tv",
                          "ids": {
                            "simkl": 11121,
                            "slug": "breaking-bad"
                          }
                        },
                        {
                          "title": "The Walking Dead",
                          "year": 2010,
                          "poster": "16/16913426086fc13",
                          "type": "tv",
                          "ids": {
                            "simkl": 2090,
                            "slug": "the-walking-dead"
                          }
                        }
                      ]
                    }
                  },
                  "ongoing_long_running": {
                    "summary": "Long-running show (The Walking Dead, simkl 2090)",
                    "description": "Exercises the high `total_episodes` count (the show has 177+ across many seasons) and the `status: \"ended\"` (lowercase) branch. `last_aired` reflects the final aired episode.",
                    "value": {
                      "title": "The Walking Dead",
                      "year": 2010,
                      "type": "show",
                      "ids": {
                        "simkl": 2090,
                        "slug": "the-walking-dead",
                        "tvdb": "153021",
                        "tvdbslug": "the-walking-dead",
                        "imdb": "tt1520211",
                        "tmdb": "1402",
                        "traktslug": "the-walking-dead"
                      },
                      "rank": 41,
                      "droprate": "3.4%",
                      "poster": "16/16913426086fc13",
                      "runtime": 43,
                      "country": "US",
                      "genres": [
                        "Drama",
                        "Horror",
                        "Sci-Fi & Fantasy"
                      ],
                      "network": "AMC",
                      "status": "ended",
                      "first_aired": "2010-10-31",
                      "last_aired": "2022-11-20",
                      "total_episodes": 177,
                      "year_start_end": "2010-2022",
                      "ratings": {
                        "simkl": {
                          "rating": 7.9,
                          "votes": 2300
                        },
                        "imdb": {
                          "rating": 8.1,
                          "votes": 1067000
                        }
                      }
                    }
                  },
                  "unknown_id_empty": {
                    "summary": "Unknown Simkl ID — empty array (Type 3 null)",
                    "description": "When the path Simkl ID is well-formed (numeric) but no catalog record exists at that ID, the response is `200 []`, not `404`. Treat as 'not found' — see [Null and missing values · Type 3](/conventions/null-values#type-3).",
                    "value": []
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "TV"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-tv-show",
          "metadata": {
            "sidebarTitle": "TV details"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/users/recently-watched-background/{user_id}": {
      "get": {
        "operationId": "get-users-recently-watched-background-user-id",
        "summary": "Redirect to a user's last-watched cover image",
        "description": "Pulls metadata about the user's most recently watched item — useful for \"Now Watching\" widgets, dashboard backgrounds, and embedded user-cards.\n\nPUBLIC endpoint — no `access_token` required, just your `client_id`. The target user's profile must be public; private profiles return `404`.\n\n#### Two response modes (selected by the `image` query param)\n\n| `image` | Status | Body | Use case |\n|---|---|---|---|\n| _omitted_ | `200` | JSON with `id`, `url`, `title`, `poster`, `fanart` | Server-side render or custom card layout |\n| `poster` | `302` | Empty; `Location: https://simkl.net/posters/<key>_0.jpg` | Drop the request URL straight into `<img src=…>` |\n| `fanart` | `302` | Empty; `Location: https://simkl.net/fanart/<key>_0.jpg` | Same — full-bleed background image |\n\n#### Drop-in `<img>` example\n\nThe `?image=` redirect modes are designed for `<img src=\"…\">` tags. The browser follows the 302 automatically and renders the JPG — no JSON parsing, no string concatenation, no extra requests:\n\n```html\n<!-- Background image (1920×1080-ish) -->\n<img src=\"https://api.simkl.com/users/recently-watched-background/12345?image=fanart&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\">\n\n<!-- Cover poster (vertical) -->\n<img src=\"https://api.simkl.com/users/recently-watched-background/12345?image=poster&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\">\n```\n\n#### JSON mode shape\n\nThe no-param mode returns the same image keys as the redirect modes — concatenate manually if you want to skip the second round-trip:\n\n```json\n{\n  \"id\": 17465,\n  \"url\": \"https://simkl.com/tv/17465/game-of-thrones\",\n  \"title\": \"Game of Thrones\",\n  \"poster\": \"17/17465posterkey\",\n  \"fanart\": \"17/17465fanartkey\"\n}\n```\n\nRender as `https://simkl.net/posters/<poster>_0.jpg` / `https://simkl.net/fanart/<fanart>_0.jpg`.",
        "x-codeSamples": [
          {
            "lang": "HTML",
            "label": "Fanart <img> drop-in",
            "source": "<img src=\"https://api.simkl.com/users/recently-watched-background/12345?image=fanart&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\" alt=\"Now watching\" />"
          },
          {
            "lang": "Shell",
            "label": "JSON metadata (no ?image=)",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/users/recently-watched-background/12345?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "Follow the 302 to the JPG (-L)",
            "source": "curl -L -o cover.jpg -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://api.simkl.com/users/recently-watched-background/12345?image=poster&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ],
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "description": "Simkl user id which has public privacy settings.",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": "51"
          },
          {
            "name": "image",
            "in": "query",
            "description": "Switches the response mode:\n\n- **Omitted** (no `image` param) → `200` with JSON metadata (`id`, `url`, `title`, `poster`, `fanart`).\n- `image=poster` → `302` redirect to the poster JPG on `simkl.net/posters/`.\n- `image=fanart` → `302` redirect to the fanart JPG on `simkl.net/fanart/`.\n\nThe two redirect modes are designed to drop straight into an `<img src=\"…\">` tag — no JSON parsing or string concatenation needed.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "poster",
                "fanart"
              ]
            },
            "example": "fanart"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Returned when `?image=` is omitted. JSON metadata about the user's most recently watched item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecentlyWatchedBackground"
                },
                "examples": {
                  "metadata_tv": {
                    "summary": "TV show — most recently watched (no `?image=` param)",
                    "value": {
                      "id": 17465,
                      "url": "https://simkl.com/tv/17465/game-of-thrones",
                      "title": "Game of Thrones",
                      "poster": "17/17465posterkey",
                      "fanart": "17/17465fanartkey"
                    }
                  },
                  "metadata_movie": {
                    "summary": "Movie — most recently watched",
                    "value": {
                      "id": 472214,
                      "url": "https://simkl.com/movies/472214/inception",
                      "title": "Inception",
                      "poster": "47/472214posterkey",
                      "fanart": "47/472214fanartkey"
                    }
                  },
                  "metadata_anime": {
                    "summary": "Anime — most recently watched",
                    "value": {
                      "id": 831411,
                      "url": "https://simkl.com/anime/831411/kimetsu-no-yaiba",
                      "title": "Demon Slayer: Kimetsu no Yaiba",
                      "poster": "83/831411posterkey",
                      "fanart": "83/831411fanartkey"
                    }
                  }
                }
              }
            }
          },
          "302": {
            "description": "Returned for `?image=poster` or `?image=fanart`. Body is empty; the JPG URL is in the `Location` header. Drop the request URL straight into `<img src=\"…\">`; the browser follows the redirect automatically and renders the image.",
            "headers": {
              "Location": {
                "description": "Fully-qualified URL of the JPG on `simkl.net`. Format: `https://simkl.net/posters/<poster_key>_0.jpg` for `?image=poster`, `https://simkl.net/fanart/<fanart_key>_0.jpg` for `?image=fanart`.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                },
                "examples": {
                  "fanart": {
                    "summary": "Returned when `?image=fanart`",
                    "value": "https://simkl.net/fanart/17/17465fanartkey_0.jpg"
                  },
                  "poster": {
                    "summary": "Returned when `?image=poster`",
                    "value": "https://simkl.net/posters/17/17465posterkey_0.jpg"
                  }
                }
              }
            },
            "content": {}
          },
          "404": {
            "description": "`user_id` is non-numeric, `0`, or otherwise invalid (the path matcher requires a positive integer).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "user_id_failed",
                  "code": 404
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Users"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-recently-watched-image",
          "metadata": {
            "sidebarTitle": "Cover image"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/users/settings": {
      "post": {
        "operationId": "post-users-settings",
        "summary": "Get the authenticated user's settings",
        "description": "Returns the authenticated user's profile (name, avatar, bio, location, age) and account settings (timezone, plan type). `POST` for historical reasons — no body.\n\n#### Response shape\n\n```json\n{\n  \"user\": {\n    \"name\": \"username\",\n    \"joined_at\": \"2018-01-15T00:00:00Z\",\n    \"gender\": \"Male\",\n    \"avatar\": \"https://simkl.in/avatars/.../user_100.jpg\",\n    \"bio\": \"I like anime.\",\n    \"loc\": \"Spain\",\n    \"age\": 28\n  },\n  \"account\": {\n    \"id\": 12345,\n    \"timezone\": \"Europe/Madrid\",\n    \"type\": \"vip\"\n  }\n}\n```\n\n`account.type` is one of `free`, `pro`, `vip`. Fields like `gender` are blank if the user disabled them in their privacy settings.\n\n#### When to refetch\n\nUser settings are **set-and-forget** in practice — most users configure their timezone / date format / privacy preferences once and never touch them again. **Don't refetch on a timer or on every app launch / wake from background.** Instead, gate the refetch on [`/sync/activities`](/api-reference/simkl/get-activities), which returns a `settings.all` timestamp that bumps when the user changes any account-level preference. Refetch only when that timestamp moves since the value you saved last time. Most launches will do **zero** extra calls. Full pattern + code example at [Dates and timezones → User timezone preference](/conventions/dates#user-timezone-preference).",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserSettings"
                },
                "example": {
                  "user": {
                    "name": "jane_doe",
                    "joined_at": "2018-06-12T14:23:08.000Z",
                    "gender": "female",
                    "avatar": "https://simkl.in/avatars/12/12345678abcdef9/user_100.jpg",
                    "bio": "Big into sci-fi shows and slice-of-life anime.",
                    "loc": "Lisbon, Portugal",
                    "age": "27 years"
                  },
                  "account": {
                    "id": 12345,
                    "timezone": "Europe/Lisbon",
                    "type": "free"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Users"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-user-settings",
          "metadata": {
            "sidebarTitle": "User settings"
          }
        },
        "security": [
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": false,
          "description": "This endpoint takes no body — it's `POST` for historical reasons.",
          "content": {
            "application/json": {
              "example": {}
            }
          }
        }
      }
    },
    "/users/{user_id}/stats": {
      "post": {
        "operationId": "post-users-user-id-stats",
        "summary": "Get a user's watch statistics",
        "description": "<Warning>\n**The most expensive call in the Simkl API. Only fire it on an explicit user action.**\n\nStats are computed **live on every request** — there is no edge cache and no precomputed result cache. The server walks the user's entire watch history across all three catalogs (movies, TV, anime), looks up the runtime of every completed episode and movie, and aggregates everything from scratch. Response time scales with the size of the user's library.\n\n**OK to call:** when the user opens a \"My stats\" / \"Year in review\" / profile screen, or taps a refresh button on a stats widget.\n\n**Do not call:** on app launch, on resume from background, in any polling loop, speculatively to \"warm\" data, or for every user in a list (e.g. a friends leaderboard — batch via lazy loading). Apps that hammer this endpoint risk rate-limit throttling on the `client_id`.\n</Warning>\n\nReturns aggregate stats for the given user — total movies / shows / anime watched, total time spent, episode counts, last-week activity, and basic profile info.\n\nThe `user_id` must be a **positive integer** — the numeric Simkl id of the target account. To fetch stats for the **authenticated user**, call [`POST /users/settings`](/api-reference/simkl/get-user-settings) once at app start and cache `account.id`, then pass that value here.\n\nPublic profiles can be fetched without a bearer token (clientId-only). Private profiles require either a bearer token belonging to the target user, or a connection the target user has granted the requester (otherwise `403 private_profile`).\n\nThis is `POST` for historical reasons — there is no request body.\n\n#### Response shape\n\n```json\n{\n \"user\": {\n \"id\": 51,\n \"name\": \"username\",\n \"joined_at\": \"2018-01-15T00:00:00Z\",\n \"avatar\": \"https://simkl.in/avatars/.../user_100.jpg\",\n \"gender\": \"Male\",\n \"loc\": \"Spain\",\n \"age\": 28,\n \"type\": \"vip\"\n },\n \"total_mins\": 78230,\n \"movies\": {\n \"total_mins\": 18000,\n \"plantowatch\": { \"mins\": 0, \"count\": 12 },\n \"completed\": { \"mins\": 18000, \"count\": 200 },\n \"dropped\": { \"mins\": 0, \"count\": 1 }\n },\n \"tv\": {\n \"total_mins\": 35000,\n \"watching\": { \"watched_episodes_count\": 23, \"count\": 4, \"left_to_watch_episodes\": 12, \"left_to_watch_mins\": 600, \"total_episodes_count\": 35 }\n },\n \"anime\": {... },\n \"watched_last_week\": { \"total_mins\": 320, \"movies_mins\": 60, \"tv_mins\": 200, \"anime_mins\": 60 }\n}\n```\n\nThe `user` block is omitted when the target user has not loaded any data (e.g. brand-new accounts); only `total_mins` and the per-domain blocks are guaranteed.\n\n#### Errors\n\n| Code | When |\n|---|---|\n| `404 user_id_failed` | `user_id` is `0` or any non-positive integer. There is **no shortcut** for the authenticated user — always pass a real numeric id. |\n| `403 private_profile` | The target user's profile is private and the requester does not have access. |",
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "description": "Target user's numeric Simkl id (positive integer). For the authenticated user, first call [`POST /users/settings`](/api-reference/simkl/get-user-settings) and pass back `account.id`. Passing `0` returns `404 user_id_failed`.",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": "51"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserStats"
                },
                "example": {
                  "total_mins": 908554,
                  "movies": {
                    "total_mins": 171969,
                    "plantowatch": {
                      "mins": 18938,
                      "count": 173
                    },
                    "completed": {
                      "mins": 171852,
                      "count": 1558
                    }
                  },
                  "tv": {
                    "total_mins": 242560,
                    "watching": {
                      "watched_episodes_count": 2612,
                      "count": 41,
                      "left_to_watch_episodes": 10276,
                      "left_to_watch_mins": 411040,
                      "total_episodes_count": 12888
                    },
                    "hold": {
                      "watched_episodes_count": 1157,
                      "count": 41,
                      "left_to_watch_episodes": 828,
                      "left_to_watch_mins": 33120,
                      "total_episodes_count": 1985
                    },
                    "plantowatch": {
                      "watched_episodes_count": 243,
                      "count": 118,
                      "left_to_watch_episodes": 12961,
                      "left_to_watch_mins": 518440,
                      "total_episodes_count": 13204
                    },
                    "completed": {
                      "watched_episodes_count": 2111,
                      "count": 55
                    }
                  },
                  "anime": {
                    "total_mins": 494025,
                    "watching": {
                      "watched_episodes_count": 1747,
                      "count": 21,
                      "left_to_watch_episodes": 410,
                      "left_to_watch_mins": 10250,
                      "total_episodes_count": 2157
                    },
                    "hold": {
                      "watched_episodes_count": 97,
                      "count": 23,
                      "left_to_watch_episodes": 462,
                      "left_to_watch_mins": 11550,
                      "total_episodes_count": 559
                    },
                    "plantowatch": {
                      "watched_episodes_count": 2324,
                      "count": 719,
                      "left_to_watch_episodes": 7829,
                      "left_to_watch_mins": 195725,
                      "total_episodes_count": 10153
                    },
                    "completed": {
                      "watched_episodes_count": 17255,
                      "count": 1291
                    }
                  },
                  "watched_last_week": {
                    "total_mins": 130,
                    "movies_mins": 130,
                    "tv_mins": 0,
                    "anime_mins": 0
                  }
                }
              }
            }
          },
          "403": {
            "description": "The target user's profile is private and the requester does not have access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "private_profile",
                  "code": 403
                }
              }
            }
          },
          "404": {
            "description": "`user_id` is `0` or any non-positive integer. There is no shortcut for the authenticated user — always pass the real numeric id from `account.id` (returned by `POST /users/settings`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "user_id_failed",
                  "code": 404
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/ClientIdFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "tags": [
          "Users"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/get-user-stats",
          "metadata": {
            "sidebarTitle": "User stats"
          }
        },
        "security": [
          {
            "clientId": []
          },
          {
            "simklApiKey": []
          },
          {
            "clientId": [],
            "bearerAuth": []
          },
          {
            "simklApiKey": [],
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": false,
          "description": "This endpoint takes no body — it's `POST` for historical reasons.",
          "content": {
            "application/json": {
              "example": {}
            }
          }
        }
      }
    },
    "/oauth/pin/{user_code}": {
      "get": {
        "operationId": "get-oauth-pin-user-code",
        "summary": "Poll PIN code for the access token",
        "description": "Step 3 of the **PIN flow**. Poll this endpoint every `interval` seconds (returned in step 1, currently `5`) to learn whether the user has entered the code. **Stop polling when `expires_in` (currently `900` seconds) elapses** and prompt the user to restart.\n\n#### Possible responses\n\n| Body | Meaning |\n|---|---|\n| `{ \"result\": \"OK\", \"access_token\": \"…\" }` | User authorized. Save the token and stop polling. |\n| `{ \"result\": \"KO\", \"message\": \"Authorization pending\" }` | Keep polling at the returned `interval`. |\n\nAfter receiving the `access_token`, send it as `Authorization: Bearer <token>` on every authenticated request.\n\n<Note>\n**Polling a code that doesn't exist (anymore) returns a fresh init response.** If you keep polling after a successful authorization, the server has already deleted the original `user_code` row and this endpoint falls through to the *create-a-new-code* branch — you'll get back the same shape as `GET /oauth/pin` (with a brand-new `user_code` different from the one you polled). Treat any response that contains `device_code` as \"the original code is gone\" and stop polling. The same thing happens for any unknown `user_code` (typos, expired codes that have been garbage-collected).\n</Note>\n\n<Card title=\"PIN flow walkthrough\" icon=\"key\" href=\"/api-reference/pin\" horizontal>\n Device authorization for TVs, consoles, smart watches, and CLI tools — show a 5-character code, the user enters it at simkl.com/pin, the app polls for the access token.\n</Card>",
        "parameters": [
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "name": "user_code",
            "in": "path",
            "description": "Get this from previous step",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "PIN poll result. The body shape depends on whether the user has entered the code yet.",
            "headers": {},
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PinPollComplete",
                      "title": "Complete (token issued)"
                    },
                    {
                      "$ref": "#/components/schemas/PinPollPending",
                      "title": "Pending (waiting for user)"
                    }
                  ],
                  "description": "One of two shapes — `result: \"OK\"` with `access_token` when complete, or `result: \"KO\"` with `\"Authorization pending\"` while waiting. (Polling an unknown / deleted `user_code` returns a fresh init response shape with a new `user_code`, same as `GET /oauth/pin`.)"
                },
                "examples": {
                  "pending": {
                    "summary": "User has not entered the code yet (keep polling)",
                    "value": {
                      "result": "KO",
                      "message": "Authorization pending"
                    }
                  },
                  "complete": {
                    "summary": "User has entered the code — save the access token",
                    "value": {
                      "result": "OK",
                      "access_token": "YOUR_ACCESS_TOKEN"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "PIN"
        ],
        "x-mint": {
          "href": "/api-reference/simkl/check-pin",
          "metadata": {
            "sidebarTitle": "Poll PIN"
          }
        },
        "security": [
          {
            "simklApiKey": []
          }
        ]
      }
    },
    "/calendar/{type}.json": {
      "get": {
        "operationId": "get-calendar-rolling",
        "summary": "Calendar (rolling 33-day window)",
        "tags": [
          "CDN data files"
        ],
        "servers": [
          {
            "url": "https://data.simkl.in",
            "description": "Simkl static-data CDN."
          }
        ],
        "security": [],
        "description": "Rolling **34-day calendar** of episode airings (TV / anime) or theatrical releases (movies): yesterday + the next ~33 days. The same data that powers the Simkl Calendar widget on simkl.com.\n\nUse this for \"what's airing now and next\" UIs. For wider grid views (previous / current / next month), use the [monthly archive](/api-reference/calendar) variant instead.\n\n**Update cadence:** regenerated every 6 hours by the build pipeline. **CDN cache TTL: 5 hours** (`Cache-Control: max-age=18000`). The Cloudflare edge ignores query strings — appending `?nocache=…` won't bust the cache. Use `If-None-Match: <ETag>` for `304 Not Modified` revalidation if you want to skip the body transfer.\n\nStill send the standard URL params (`client_id`, `app-name`, `app-version`) and the `User-Agent` header on every request — same project-wide convention, even though `data.simkl.in` ignores them. See [Headers and required parameters](/conventions/headers).\n\n#### Per-type variations\n\n| File | Item shape |\n|---|---|\n| `/calendar/tv.json` | TV episode airings. Each item has `episode.season` + `episode.episode`. |\n| `/calendar/anime.json` | Anime episode airings. `episode.season` omitted (AniDB sequential numbering). `anime_type` present. |\n| `/calendar/movie_release.json` | Movie premieres. No `episode` block. |\n\n#### Date conventions\n\n| Field | Format | Meaning |\n|---|---|---|\n| `date` | ISO 8601 with TZ offset (e.g. `2026-05-16T00:00:00-05:00`) | The actual airing/release timestamp for the calendar entry. Use this for sorting and display. |\n| `release_date` | `YYYY-MM-DD` | The original premiere date of the title (not the per-episode date). |\n",
        "parameters": [
          {
            "name": "type",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "tv",
                "anime",
                "movie_release"
              ]
            },
            "example": "tv",
            "description": "`tv` = TV episode airings. `anime` = anime episode airings. `movie_release` = upcoming movie releases."
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Array of calendar entries.",
            "headers": {
              "Cache-Control": {
                "description": "Cloudflare edge cache TTL. `max-age=18000` (5 hours) for calendar files; `max-age=3600` (1 hour) for trending + DVD files.",
                "schema": {
                  "type": "string",
                  "example": "max-age=18000"
                }
              },
              "Last-Modified": {
                "description": "Timestamp the file was last regenerated by the build pipeline.",
                "schema": {
                  "type": "string",
                  "format": "http-date",
                  "example": "Sun, 17 May 2026 22:12:02 GMT"
                }
              },
              "Expires": {
                "description": "Absolute expiry timestamp computed from `Cache-Control`. Use either header — both reflect the same TTL.",
                "schema": {
                  "type": "string",
                  "format": "http-date",
                  "example": "Mon, 18 May 2026 03:12:02 GMT"
                }
              },
              "ETag": {
                "description": "Entity tag. Often weak (`W/\"...\"`). Use with `If-None-Match` for `304 Not Modified` revalidation.",
                "schema": {
                  "type": "string",
                  "example": "W/\"6a0a3d32-244523\""
                }
              },
              "Vary": {
                "description": "Always `Accept-Encoding` — content-encoding (gzip/br) varies the cache key.",
                "schema": {
                  "type": "string",
                  "example": "Accept-Encoding"
                }
              },
              "cf-cache-status": {
                "description": "Cloudflare cache decision. `HIT` = served from edge cache. `MISS` = forwarded to origin, fresh fetch. `EXPIRED` = stale-but-served while edge refreshes in background. Devs can ignore this header in most cases — it's informational.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "EXPIRED",
                    "DYNAMIC",
                    "BYPASS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CalendarItem"
                  }
                },
                "examples": {
                  "calendar_tv_rolling": {
                    "summary": "TV — first item from the rolling-window file",
                    "value": [
                      {
                        "title": "Ruin Road",
                        "poster": null,
                        "date": "2026-05-16T00:00:00-05:00",
                        "release_date": "2016-10-15",
                        "rank": 0,
                        "ratings": {
                          "simkl": {
                            "rating": 0,
                            "votes": 0
                          }
                        },
                        "url": "https://simkl.com/tv/1520136/ruin-road",
                        "ids": {
                          "simkl_id": 1520136,
                          "slug": "ruin-road",
                          "tmdb": "94605",
                          "imdb": "tt8009878"
                        },
                        "episode": {
                          "season": 1,
                          "episode": 1,
                          "url": "https://simkl.com/tv/1520136/ruin-road/1/1"
                        }
                      }
                    ]
                  },
                  "calendar_anime_rolling": {
                    "summary": "Anime — note `anime_type`, `mal` ID, and `episode.season` omission",
                    "value": [
                      {
                        "title": "Battle Through The Heavens Season 5",
                        "poster": "16/1616285768161214da",
                        "date": "2026-05-16T00:00:00+09:00",
                        "release_date": "2022-07-31",
                        "rank": 368,
                        "ratings": {
                          "simkl": {
                            "rating": 8.4,
                            "votes": 1240
                          }
                        },
                        "url": "https://simkl.com/anime/1972214/dou-po-cangqiong-nian-fan",
                        "ids": {
                          "simkl_id": 1972214,
                          "slug": "dou-po-cangqiong-nian-fan",
                          "tmdb": "208589",
                          "mal": "55050"
                        },
                        "episode": {
                          "episode": 168,
                          "url": "https://simkl.com/anime/1972214/dou-po-cangqiong-nian-fan/1/168"
                        },
                        "anime_type": "ona"
                      }
                    ]
                  },
                  "calendar_movies_rolling": {
                    "summary": "Movies — no `episode` block, no `anime_type`",
                    "value": [
                      {
                        "title": "Forever Your Maternal Animal",
                        "poster": "19/198116293daaceb5d1",
                        "date": "2026-05-16T00:00:00-05:00",
                        "release_date": "2026-05-16",
                        "rank": 0,
                        "ratings": {
                          "simkl": {
                            "rating": 0,
                            "votes": 0
                          }
                        },
                        "url": "https://simkl.com/movies/3069405/forever-your-maternal-animal",
                        "ids": {
                          "simkl_id": 3069405,
                          "slug": "forever-your-maternal-animal",
                          "tmdb": "1483927",
                          "imdb": "tt35742108"
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "404": {
            "description": "File not found. Returned for invalid `file` / `type` / `year` / `month` path values that don't match a generated file. Body is plain-text HTML from the edge proxy (`openresty`) — NOT JSON. Treat any non-2xx as no-data.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                },
                "example": "<html>\n<head><title>404 Not Found</title></head>\n<body>\n<center><h1>404 Not Found</h1></center>\n<hr><center>openresty</center>\n</body>\n</html>\n"
              }
            }
          }
        },
        "x-mint": {
          "href": "/api-reference/calendar",
          "metadata": {
            "sidebarTitle": "Calendar (rolling)"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "calendar_tv_rolling",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/calendar/tv.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "calendar_anime_rolling",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/calendar/anime.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "calendar_movies_rolling",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/calendar/movie_release.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/calendar/{year}/{month}/{type}.json": {
      "get": {
        "operationId": "get-calendar-monthly",
        "summary": "Calendar (monthly archive)",
        "tags": [
          "CDN data files"
        ],
        "servers": [
          {
            "url": "https://data.simkl.in",
            "description": "Simkl static-data CDN."
          }
        ],
        "security": [],
        "description": "Per-month archive of TV episodes / anime episodes / movie releases. Use for **wider calendar grid views** (e.g. a 3-month strip showing previous / current / next month) and **historical lookups**.\n\n**Update cadence:** the current month is regenerated every 6 hours; the previous 12 months every 24 hours; archives older than 12 months are immutable (rarely change). **CDN cache TTL: 5 hours** (same as the rolling file). The Cloudflare edge ignores query strings.\n\nSame item shape as the [rolling-window file](/api-reference/calendar) — see that page for the per-type field tables and the `date` vs `release_date` distinction.\n\nStill send the standard URL params (`client_id`, `app-name`, `app-version`) and the `User-Agent` header on every request — same project-wide convention, even though `data.simkl.in` ignores them. See [Headers and required parameters](/conventions/headers).\n\n#### Path\n\n`/calendar/{year}/{month}/{type}.json`\n\n| Segment | Format | Notes |\n|---|---|---|\n| `year` | 4-digit integer | e.g. `2026`. |\n| `month` | 1–12 integer | **Bare integer, NO zero-padding.** `/calendar/2026/5/tv.json` works; `/calendar/2026/05/tv.json` returns **404**. Common gotcha for clients using `f\"{month:02d}\"` or `str(month).zfill(2)` — strip the padding before building the path. |\n| `type` | `tv` / `anime` / `movie_release` | Same enum as the rolling file. |\n",
        "parameters": [
          {
            "name": "year",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 2000
            },
            "example": 2024,
            "description": "Four-digit year."
          },
          {
            "name": "month",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 12
            },
            "example": 1,
            "description": "Month number, 1-12. Single digit accepted (the path-template uses an integer, no zero-padding)."
          },
          {
            "name": "type",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "tv",
                "anime",
                "movie_release"
              ]
            },
            "example": "tv",
            "description": "`tv` / `anime` / `movie_release` — same semantics as the rolling-window file."
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Array of calendar entries for the requested month.",
            "headers": {
              "Cache-Control": {
                "description": "Cloudflare edge cache TTL. `max-age=18000` (5 hours) for calendar files; `max-age=3600` (1 hour) for trending + DVD files.",
                "schema": {
                  "type": "string",
                  "example": "max-age=18000"
                }
              },
              "Last-Modified": {
                "description": "Timestamp the file was last regenerated by the build pipeline.",
                "schema": {
                  "type": "string",
                  "format": "http-date",
                  "example": "Sun, 17 May 2026 22:12:02 GMT"
                }
              },
              "Expires": {
                "description": "Absolute expiry timestamp computed from `Cache-Control`. Use either header — both reflect the same TTL.",
                "schema": {
                  "type": "string",
                  "format": "http-date",
                  "example": "Mon, 18 May 2026 03:12:02 GMT"
                }
              },
              "ETag": {
                "description": "Entity tag. Often weak (`W/\"...\"`). Use with `If-None-Match` for `304 Not Modified` revalidation.",
                "schema": {
                  "type": "string",
                  "example": "W/\"6a0a3d32-244523\""
                }
              },
              "Vary": {
                "description": "Always `Accept-Encoding` — content-encoding (gzip/br) varies the cache key.",
                "schema": {
                  "type": "string",
                  "example": "Accept-Encoding"
                }
              },
              "cf-cache-status": {
                "description": "Cloudflare cache decision. `HIT` = served from edge cache. `MISS` = forwarded to origin, fresh fetch. `EXPIRED` = stale-but-served while edge refreshes in background. Devs can ignore this header in most cases — it's informational.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "EXPIRED",
                    "DYNAMIC",
                    "BYPASS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CalendarItem"
                  }
                },
                "examples": {
                  "calendar_monthly_tv_2026_05": {
                    "summary": "Monthly archive — TV, May 2026 (path: /calendar/2026/5/tv.json)",
                    "value": [
                      {
                        "title": "Miraculous Zag Chibi",
                        "poster": "72/7211312d154ae25cc",
                        "date": "2026-05-01T00:00:00-05:00",
                        "release_date": "2018-08-31",
                        "rank": 27098,
                        "ratings": {
                          "simkl": {
                            "rating": 7.5,
                            "votes": 12
                          }
                        },
                        "url": "https://simkl.com/tv/868792/miraculous-zag-chibi",
                        "ids": {
                          "simkl_id": 868792,
                          "slug": "miraculous-zag-chibi",
                          "tmdb": "82929",
                          "imdb": "tt8634464"
                        },
                        "episode": {
                          "season": 1,
                          "episode": 1,
                          "url": "https://simkl.com/tv/868792/miraculous-zag-chibi/1/1"
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "404": {
            "description": "File not found. Returned for invalid `file` / `type` / `year` / `month` path values that don't match a generated file. Body is plain-text HTML from the edge proxy (`openresty`) — NOT JSON. Treat any non-2xx as no-data.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                },
                "example": "<html>\n<head><title>404 Not Found</title></head>\n<body>\n<center><h1>404 Not Found</h1></center>\n<hr><center>openresty</center>\n</body>\n</html>\n"
              }
            }
          }
        },
        "x-mint": {
          "href": "/api-reference/calendar",
          "metadata": {
            "sidebarTitle": "Calendar (monthly)"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "calendar_monthly_tv_2026_05",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/calendar/2026/5/tv.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "calendar_monthly_anime_2026_05",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/calendar/2026/5/anime.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "calendar_monthly_movies_2026_05",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/calendar/2026/5/movie_release.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/discover/trending/{file}.json": {
      "get": {
        "operationId": "get-trending-combined",
        "summary": "Trending — combined (movies + tv + anime)",
        "tags": [
          "CDN data files"
        ],
        "servers": [
          {
            "url": "https://data.simkl.in",
            "description": "Simkl static-data CDN."
          }
        ],
        "security": [],
        "description": "Single JSON file containing **all three categories** (movies + tv + anime) — top trending titles in one fetch. Use when you want to render a multi-category trending homepage in one round-trip.\n\n**Update cadence:** `today_*` files refresh **hourly**; `week_*` and `month_*` files refresh **daily**. **CDN cache TTL: 1 hour** (`Cache-Control: max-age=3600`).\n\n**Size variants:** `_100` returns the top 100 items per category (≈300 items total); `_500` returns the top 500 per category (≈1500 items total). Pick the smaller file unless your UI actually needs the long tail — the `_500` files are ~5× larger.\n\nStill send the standard URL params (`client_id`, `app-name`, `app-version`) and the `User-Agent` header on every request — same project-wide convention, even though `data.simkl.in` ignores them. See [Headers and required parameters](/conventions/headers).\n\n<Warning>\n**Attribution required.** When you display trending data, the section title must credit Simkl — e.g. \"Simkl Trending Movies\", \"Trending on Simkl Today\". See [Trending data files → Attribution](/api-reference/trending#linking-back-websites-only).\n</Warning>\n",
        "parameters": [
          {
            "name": "file",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "today_100",
                "today_500",
                "week_100",
                "week_500",
                "month_100",
                "month_500"
              ]
            },
            "example": "today_100",
            "description": "Timeframe and size: `today_*` (last 24h, refreshes hourly), `week_*` (last 7 days, daily), `month_*` (last 30 days, daily). `_100` = top 100 items per category; `_500` = top 500."
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Object with `movies`, `tv`, and `anime` arrays.",
            "headers": {
              "Cache-Control": {
                "description": "Cloudflare edge cache TTL. `max-age=18000` (5 hours) for calendar files; `max-age=3600` (1 hour) for trending + DVD files.",
                "schema": {
                  "type": "string",
                  "example": "max-age=18000"
                }
              },
              "Last-Modified": {
                "description": "Timestamp the file was last regenerated by the build pipeline.",
                "schema": {
                  "type": "string",
                  "format": "http-date",
                  "example": "Sun, 17 May 2026 22:12:02 GMT"
                }
              },
              "Expires": {
                "description": "Absolute expiry timestamp computed from `Cache-Control`. Use either header — both reflect the same TTL.",
                "schema": {
                  "type": "string",
                  "format": "http-date",
                  "example": "Mon, 18 May 2026 03:12:02 GMT"
                }
              },
              "ETag": {
                "description": "Entity tag. Often weak (`W/\"...\"`). Use with `If-None-Match` for `304 Not Modified` revalidation.",
                "schema": {
                  "type": "string",
                  "example": "W/\"6a0a3d32-244523\""
                }
              },
              "Vary": {
                "description": "Always `Accept-Encoding` — content-encoding (gzip/br) varies the cache key.",
                "schema": {
                  "type": "string",
                  "example": "Accept-Encoding"
                }
              },
              "cf-cache-status": {
                "description": "Cloudflare cache decision. `HIT` = served from edge cache. `MISS` = forwarded to origin, fresh fetch. `EXPIRED` = stale-but-served while edge refreshes in background. Devs can ignore this header in most cases — it's informational.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "EXPIRED",
                    "DYNAMIC",
                    "BYPASS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrendingCombinedResponse"
                },
                "examples": {
                  "trending_combined_today_100": {
                    "summary": "Combined — today_100, first item from each category (real arrays are 100 long)",
                    "value": {
                      "movies": [
                        {
                          "title": "Project Hail Mary",
                          "url": "/movie/1306562/project-hail-mary",
                          "poster": "19/195417372d9325feb5",
                          "fanart": "19/19676837733d10098c",
                          "ids": {
                            "simkl_id": 1306562,
                            "slug": "project-hail-mary",
                            "imdb": "tt12262116",
                            "letterslug": "project-hail-mary",
                            "traktmslug": "project-hail-mary-2026",
                            "tmdb": "693134",
                            "tvdbslug": "project-hail-mary",
                            "tvdb": "338953"
                          },
                          "release_date": "03/15/2026",
                          "rank": 197,
                          "drop_rate": "0.2%",
                          "watched": 281,
                          "plan_to_watch": 3468,
                          "ratings": {
                            "simkl": {
                              "rating": 8.5,
                              "votes": 145
                            },
                            "imdb": {
                              "rating": 8.1,
                              "votes": 14200
                            }
                          },
                          "country": "us",
                          "runtime": "2h 37m",
                          "status": "ended",
                          "dvd_date": "05/12/2026",
                          "metadata": "March 15, 2026 • Budget $200M • Box office $660M",
                          "overview": "Science teacher Ryland Grace wakes up on a spaceship light years from home with no recollection of who he is or how he got there...",
                          "genres": [
                            "Science Fiction",
                            "Adventure",
                            "Drama",
                            "Thriller"
                          ],
                          "trailer": "tvd7UUHzdhA",
                          "theater": "03/15/2026"
                        }
                      ],
                      "tv": [
                        {
                          "title": "The Boys",
                          "url": "/tv/967226/the-boys",
                          "poster": "19/196289114d7f60aa05",
                          "fanart": "19/193246838c98747f7c",
                          "ids": {
                            "simkl_id": 967226,
                            "slug": "the-boys",
                            "imdb": "tt1190634",
                            "tvdbslug": "the-boys-2019",
                            "trakttvslug": "the-boys-2019",
                            "mdlslug": "the-boys",
                            "tvdb": "355567",
                            "tmdb": "76479"
                          },
                          "release_date": "07/26/2019",
                          "rank": 268,
                          "drop_rate": "2.7%",
                          "watched": 567,
                          "plan_to_watch": 5117,
                          "ratings": {
                            "simkl": {
                              "rating": 8.7,
                              "votes": 2240
                            },
                            "imdb": {
                              "rating": 8.7,
                              "votes": 612000
                            }
                          },
                          "country": "us",
                          "runtime": "1h 2m",
                          "status": "ongoing",
                          "total_episodes": 40,
                          "network": "Prime Video",
                          "metadata": "2019 - Now • Prime Video • 40 episodes",
                          "overview": "In a world where superheroes embrace the darker side of their massive celebrity and fame...",
                          "genres": [
                            "Action",
                            "Drama",
                            "Science Fiction",
                            "Suspense",
                            "Crime",
                            "Comedy"
                          ],
                          "trailer": "tcrNsIaQkb4"
                        }
                      ],
                      "anime": [
                        {
                          "title": "Daemons of the Shadow Realm",
                          "url": "/anime/2832222/yomi-no-tsugai",
                          "poster": "18/18668015b82669c58c",
                          "fanart": "19/197819852b84731a2b",
                          "ids": {
                            "simkl_id": 2832222,
                            "slug": "yomi-no-tsugai",
                            "mal": "53391",
                            "anilist": "168380",
                            "kitsu": "46939",
                            "imdb": "tt27889060",
                            "tvdbslug": "yomi-no-tsugai",
                            "trakttvslug": "yomi-no-tsugai",
                            "anidb": "17832",
                            "tvdb": "433879",
                            "tmdb": "224412"
                          },
                          "release_date": "04/04/2026",
                          "rank": 692,
                          "drop_rate": "0.8%",
                          "watched": 338,
                          "plan_to_watch": 991,
                          "ratings": {
                            "simkl": {
                              "rating": 7.6,
                              "votes": 178
                            },
                            "mal": {
                              "rating": 7.34,
                              "votes": 5430
                            }
                          },
                          "country": "jp",
                          "runtime": "25m",
                          "status": "ongoing",
                          "anime_type": "tv",
                          "total_episodes": 24,
                          "network": "Tokyo MX",
                          "metadata": "2026 - Now • Tokyo MX • 24 episodes",
                          "overview": "In a world where certain humans command mighty supernatural duos called Daemons...",
                          "genres": [
                            "Action",
                            "Fantasy",
                            "Adventure",
                            "Drama"
                          ],
                          "trailer": "NYFJqJGvUHE"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "File not found. Returned for invalid `file` / `type` / `year` / `month` path values that don't match a generated file. Body is plain-text HTML from the edge proxy (`openresty`) — NOT JSON. Treat any non-2xx as no-data.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                },
                "example": "<html>\n<head><title>404 Not Found</title></head>\n<body>\n<center><h1>404 Not Found</h1></center>\n<hr><center>openresty</center>\n</body>\n</html>\n"
              }
            }
          }
        },
        "x-mint": {
          "href": "/api-reference/trending",
          "metadata": {
            "sidebarTitle": "Trending (combined)"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "trending_combined_today_100",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/discover/trending/today_100.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "trending_combined_week_100",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/discover/trending/week_100.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "trending_combined_month_500",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/discover/trending/month_500.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/discover/trending/{type}/{file}.json": {
      "get": {
        "operationId": "get-trending-by-type",
        "summary": "Trending — single category (movies / tv / anime)",
        "tags": [
          "CDN data files"
        ],
        "servers": [
          {
            "url": "https://data.simkl.in",
            "description": "Simkl static-data CDN."
          }
        ],
        "security": [],
        "description": "Single-category trending file — a flat array (no per-category wrapping). Use when you only render one of movies / tv / anime — smaller payload than the [combined file](/api-reference/trending) variant.\n\n**Update cadence:** same as the combined file. `today_*` hourly, `week_*` and `month_*` daily. **CDN cache TTL: 1 hour.**\n\nStill send the standard URL params (`client_id`, `app-name`, `app-version`) and the `User-Agent` header on every request. See [Headers and required parameters](/conventions/headers).\n\n<Warning>\n**Attribution required.** See [Trending data files → Attribution](/api-reference/trending#linking-back-websites-only).\n</Warning>\n",
        "parameters": [
          {
            "name": "type",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "movies",
                "tv",
                "anime"
              ]
            },
            "example": "movies"
          },
          {
            "name": "file",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "today_100",
                "today_500",
                "week_100",
                "week_500",
                "month_100",
                "month_500"
              ]
            },
            "example": "today_100",
            "description": "Timeframe and size — same matrix as the combined file."
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Flat array of trending entries for the requested category.",
            "headers": {
              "Cache-Control": {
                "description": "Cloudflare edge cache TTL. `max-age=18000` (5 hours) for calendar files; `max-age=3600` (1 hour) for trending + DVD files.",
                "schema": {
                  "type": "string",
                  "example": "max-age=18000"
                }
              },
              "Last-Modified": {
                "description": "Timestamp the file was last regenerated by the build pipeline.",
                "schema": {
                  "type": "string",
                  "format": "http-date",
                  "example": "Sun, 17 May 2026 22:12:02 GMT"
                }
              },
              "Expires": {
                "description": "Absolute expiry timestamp computed from `Cache-Control`. Use either header — both reflect the same TTL.",
                "schema": {
                  "type": "string",
                  "format": "http-date",
                  "example": "Mon, 18 May 2026 03:12:02 GMT"
                }
              },
              "ETag": {
                "description": "Entity tag. Often weak (`W/\"...\"`). Use with `If-None-Match` for `304 Not Modified` revalidation.",
                "schema": {
                  "type": "string",
                  "example": "W/\"6a0a3d32-244523\""
                }
              },
              "Vary": {
                "description": "Always `Accept-Encoding` — content-encoding (gzip/br) varies the cache key.",
                "schema": {
                  "type": "string",
                  "example": "Accept-Encoding"
                }
              },
              "cf-cache-status": {
                "description": "Cloudflare cache decision. `HIT` = served from edge cache. `MISS` = forwarded to origin, fresh fetch. `EXPIRED` = stale-but-served while edge refreshes in background. Devs can ignore this header in most cases — it's informational.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "EXPIRED",
                    "DYNAMIC",
                    "BYPASS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TrendingItem"
                  }
                },
                "examples": {
                  "trending_movies_today_100": {
                    "summary": "Movies-only — today_100, first item (real array is 100 long)",
                    "value": [
                      {
                        "title": "Project Hail Mary",
                        "url": "/movie/1306562/project-hail-mary",
                        "poster": "19/195417372d9325feb5",
                        "fanart": "19/19676837733d10098c",
                        "ids": {
                          "simkl_id": 1306562,
                          "slug": "project-hail-mary",
                          "imdb": "tt12262116",
                          "letterslug": "project-hail-mary",
                          "traktmslug": "project-hail-mary-2026",
                          "tmdb": "693134",
                          "tvdbslug": "project-hail-mary",
                          "tvdb": "338953"
                        },
                        "release_date": "03/15/2026",
                        "rank": 197,
                        "drop_rate": "0.2%",
                        "watched": 281,
                        "plan_to_watch": 3468,
                        "ratings": {
                          "simkl": {
                            "rating": 8.5,
                            "votes": 145
                          },
                          "imdb": {
                            "rating": 8.1,
                            "votes": 14200
                          }
                        },
                        "country": "us",
                        "runtime": "2h 37m",
                        "status": "ended",
                        "dvd_date": "05/12/2026",
                        "metadata": "March 15, 2026 • Budget $200M • Box office $660M",
                        "overview": "Science teacher Ryland Grace wakes up on a spaceship light years from home...",
                        "genres": [
                          "Science Fiction",
                          "Adventure",
                          "Drama",
                          "Thriller"
                        ],
                        "trailer": "tvd7UUHzdhA",
                        "theater": "03/15/2026"
                      }
                    ]
                  }
                }
              }
            }
          },
          "404": {
            "description": "File not found. Returned for invalid `file` / `type` / `year` / `month` path values that don't match a generated file. Body is plain-text HTML from the edge proxy (`openresty`) — NOT JSON. Treat any non-2xx as no-data.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                },
                "example": "<html>\n<head><title>404 Not Found</title></head>\n<body>\n<center><h1>404 Not Found</h1></center>\n<hr><center>openresty</center>\n</body>\n</html>\n"
              }
            }
          }
        },
        "x-mint": {
          "href": "/api-reference/trending",
          "metadata": {
            "sidebarTitle": "Trending (by type)"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "trending_movies_today_100",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/discover/trending/movies/today_100.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "trending_tv_today_100",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/discover/trending/tv/today_100.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "trending_anime_today_100",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/discover/trending/anime/today_100.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    },
    "/discover/dvd/{file}.json": {
      "get": {
        "operationId": "get-trending-dvd",
        "summary": "DVD releases (movies only)",
        "tags": [
          "CDN data files"
        ],
        "servers": [
          {
            "url": "https://data.simkl.in",
            "description": "Simkl static-data CDN."
          }
        ],
        "security": [],
        "description": "Most-watched **DVD / Blu-ray releases**. Movies only. Mirrors the [Simkl DVD Releases](https://simkl.com/movies/dvd-releases/) page.\n\nItems carry the standard trending fields plus `dvd_date` (physical release date) and `theater` (original theatrical date).\n\n**Update cadence:** once per day. **CDN cache TTL: 1 hour.**\n\nStill send the standard URL params (`client_id`, `app-name`, `app-version`) and the `User-Agent` header on every request. See [Headers and required parameters](/conventions/headers).\n\n<Warning>\n**Attribution required.** See [Trending data files → Attribution](/api-reference/trending#linking-back-websites-only).\n</Warning>\n",
        "parameters": [
          {
            "name": "file",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "releases_100",
                "releases_500"
              ]
            },
            "example": "releases_100"
          },
          {
            "$ref": "#/components/parameters/ClientIdQuery"
          },
          {
            "$ref": "#/components/parameters/AppNameQuery"
          },
          {
            "$ref": "#/components/parameters/AppVersionQuery"
          },
          {
            "$ref": "#/components/parameters/UserAgentHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Array of trending movie entries focused on recent DVD/Blu-ray releases.",
            "headers": {
              "Cache-Control": {
                "description": "Cloudflare edge cache TTL. `max-age=18000` (5 hours) for calendar files; `max-age=3600` (1 hour) for trending + DVD files.",
                "schema": {
                  "type": "string",
                  "example": "max-age=18000"
                }
              },
              "Last-Modified": {
                "description": "Timestamp the file was last regenerated by the build pipeline.",
                "schema": {
                  "type": "string",
                  "format": "http-date",
                  "example": "Sun, 17 May 2026 22:12:02 GMT"
                }
              },
              "Expires": {
                "description": "Absolute expiry timestamp computed from `Cache-Control`. Use either header — both reflect the same TTL.",
                "schema": {
                  "type": "string",
                  "format": "http-date",
                  "example": "Mon, 18 May 2026 03:12:02 GMT"
                }
              },
              "ETag": {
                "description": "Entity tag. Often weak (`W/\"...\"`). Use with `If-None-Match` for `304 Not Modified` revalidation.",
                "schema": {
                  "type": "string",
                  "example": "W/\"6a0a3d32-244523\""
                }
              },
              "Vary": {
                "description": "Always `Accept-Encoding` — content-encoding (gzip/br) varies the cache key.",
                "schema": {
                  "type": "string",
                  "example": "Accept-Encoding"
                }
              },
              "cf-cache-status": {
                "description": "Cloudflare cache decision. `HIT` = served from edge cache. `MISS` = forwarded to origin, fresh fetch. `EXPIRED` = stale-but-served while edge refreshes in background. Devs can ignore this header in most cases — it's informational.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "EXPIRED",
                    "DYNAMIC",
                    "BYPASS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TrendingItem"
                  }
                },
                "examples": {
                  "dvd_releases_100": {
                    "summary": "DVD — releases_100, first item (real array is 100 long)",
                    "value": [
                      {
                        "title": "Project Hail Mary",
                        "url": "/movie/1306562/project-hail-mary",
                        "poster": "19/195417372d9325feb5",
                        "fanart": "19/19676837733d10098c",
                        "ids": {
                          "simkl_id": 1306562,
                          "slug": "project-hail-mary",
                          "imdb": "tt12262116",
                          "letterslug": "project-hail-mary",
                          "traktmslug": "project-hail-mary-2026",
                          "tmdb": "693134",
                          "tvdbslug": "project-hail-mary",
                          "tvdb": "338953"
                        },
                        "release_date": "03/15/2026",
                        "rank": 197,
                        "drop_rate": "0.2%",
                        "watched": 5588,
                        "plan_to_watch": 3468,
                        "ratings": {
                          "simkl": {
                            "rating": 8.5,
                            "votes": 145
                          },
                          "imdb": {
                            "rating": 8.1,
                            "votes": 14200
                          }
                        },
                        "country": "us",
                        "runtime": "2h 37m",
                        "status": "ended",
                        "dvd_date": "05/12/2026",
                        "metadata": "March 15, 2026 • Budget $200M • Box office $660M",
                        "overview": "Science teacher Ryland Grace wakes up on a spaceship light years from home...",
                        "genres": [
                          "Science Fiction",
                          "Adventure",
                          "Drama",
                          "Thriller"
                        ],
                        "trailer": "tvd7UUHzdhA",
                        "theater": "03/15/2026"
                      }
                    ]
                  }
                }
              }
            }
          },
          "404": {
            "description": "File not found. Returned for invalid `file` / `type` / `year` / `month` path values that don't match a generated file. Body is plain-text HTML from the edge proxy (`openresty`) — NOT JSON. Treat any non-2xx as no-data.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                },
                "example": "<html>\n<head><title>404 Not Found</title></head>\n<body>\n<center><h1>404 Not Found</h1></center>\n<hr><center>openresty</center>\n</body>\n</html>\n"
              }
            }
          }
        },
        "x-mint": {
          "href": "/api-reference/trending",
          "metadata": {
            "sidebarTitle": "Trending (DVD)"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "dvd_releases_100",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/discover/dvd/releases_100.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          },
          {
            "lang": "Shell",
            "label": "dvd_releases_500",
            "source": "curl -H \"User-Agent: my-app-name/1.0\" \\\n  \"https://data.simkl.in/discover/dvd/releases_500.json?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0\""
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "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": {
            "description": "TVDB ID or slug.",
            "example": "153021",
            "type": "string"
          },
          "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"
        }
      },
      "ExternalRating": {
        "type": "object",
        "description": "External-source rating.",
        "properties": {
          "rating": {
            "type": "number",
            "minimum": 0,
            "maximum": 10,
            "description": "Rating value (0–10)."
          },
          "votes": {
            "type": "integer",
            "description": "Number of votes contributing to the rating."
          }
        }
      },
      "RankedExternalRating": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ExternalRating"
          },
          {
            "type": "object",
            "properties": {
              "rank": {
                "type": "integer",
                "description": "Rank in the source's ordering (lower = better)."
              }
            }
          }
        ]
      },
      "WatchlistStatus": {
        "type": "string",
        "enum": [
          "watching",
          "plantowatch",
          "hold",
          "completed",
          "dropped"
        ],
        "description": "User watchlist status. Movies skip `watching` and `hold` — see /conventions/list-statuses."
      },
      "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": "string",
            "description": "TMDb movie ID.",
            "example": "27205"
          },
          "netflix": {
            "type": "string",
            "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": "string",
            "description": "TMDb show ID.",
            "example": "66732"
          },
          "tvdb": {
            "description": "TVDB show ID (integer) or slug (string).",
            "example": "305288",
            "type": "string"
          },
          "netflix": {
            "type": "string",
            "description": "Netflix show ID."
          },
          "hulu": {
            "type": "string",
            "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": "string",
            "description": "TMDb show or movie ID (depending on anime_type).",
            "example": "1429"
          },
          "tvdb": {
            "description": "TVDB show ID (integer) or slug (string).",
            "example": "267440",
            "type": "string"
          },
          "mal": {
            "type": "string",
            "description": "MyAnimeList ID.",
            "example": "16498"
          },
          "anidb": {
            "type": "string",
            "description": "AniDB ID. Specifying just this is enough for anime lookups.",
            "example": "9541"
          },
          "anilist": {
            "type": "string",
            "description": "AniList ID.",
            "example": "16498"
          },
          "kitsu": {
            "type": "string",
            "description": "Kitsu ID.",
            "example": "7442"
          },
          "anisearch": {
            "type": "string",
            "description": "aniSearch ID."
          },
          "animeplanet": {
            "type": "string",
            "description": "Anime-Planet slug."
          },
          "livechart": {
            "type": "string",
            "description": "LiveChart ID."
          },
          "anfo": {
            "type": "string",
            "description": "AnimeNewsNetwork-style anfo ID."
          },
          "ann": {
            "type": "string",
            "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": "string",
            "description": "TVDB episode ID.",
            "example": "4274616"
          },
          "anidb": {
            "type": "string",
            "description": "AniDB episode ID.",
            "example": "142278"
          }
        },
        "additionalProperties": false
      },
      "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.\n\n**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"
              }
            }
          }
        }
      },
      "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"
        ]
      },
      "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"
          }
        }
      },
      "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"
        ]
      },
      "MovieDetail": {
        "type": "object",
        "description": "Full movie record returned by `GET /movies/{id}`. The response shape is the same regardless of any `extended` query value — the parameter is a legacy no-op for this endpoint. Responses are Cloudflare-cached by Simkl ID. See [Null and missing values](/conventions/null-values) for the nullable-field semantics used below.",
        "required": [
          "title",
          "year",
          "type",
          "ids"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "Display title in the response language (defaults to English unless the request's `language` overrides it)."
          },
          "year": {
            "type": "integer",
            "description": "Release year."
          },
          "type": {
            "type": "string",
            "enum": [
              "movie"
            ],
            "description": "Always `movie` on this endpoint."
          },
          "ids": {
            "$ref": "#/components/schemas/Ids"
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Position in Simkl's popularity ranking. Null when not ranked."
          },
          "droprate": {
            "type": [
              "string",
              "null"
            ],
            "description": "Percentage of users who started watching but dropped, e.g. `\"0.1%\"`. Type 4 null when the metric isn't computed."
          },
          "poster": {
            "type": [
              "string",
              "null"
            ],
            "description": "Poster image path. Compose the full URL via [Images](/conventions/images). Type 4 null when no poster on file."
          },
          "fanart": {
            "type": [
              "string",
              "null"
            ],
            "description": "Background/hero image path. Type 4 null when no fanart on file."
          },
          "released": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Initial release date (`YYYY-MM-DD`). Type 4 null when unknown."
          },
          "runtime": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Runtime in minutes. Type 4 null when not on file."
          },
          "director": {
            "type": [
              "string",
              "null"
            ],
            "description": "Primary director. Type 4 null when unknown."
          },
          "certification": {
            "type": [
              "string",
              "null"
            ],
            "description": "Content rating (e.g. `PG-13`, `R`). Type 4 null when not rated for the response country."
          },
          "budget": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Production budget in USD. Type 4 null when not on file."
          },
          "revenue": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Box-office revenue in USD. Type 4 null when not on file."
          },
          "overview": {
            "type": [
              "string",
              "null"
            ],
            "description": "Plot synopsis. Type 4 null when no overview is available."
          },
          "genres": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Genre names."
          },
          "country": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 production country code."
          },
          "language": {
            "type": "string",
            "description": "ISO 639-1 language code in UPPERCASE."
          },
          "alt_titles": {
            "type": "array",
            "description": "Localized and alternate titles. May contain many entries for popular titles.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "lang": {
                  "type": "integer",
                  "description": "Simkl internal language code."
                },
                "type": {
                  "$ref": "#/components/schemas/AltTitleType"
                }
              }
            }
          },
          "ratings": {
            "type": "object",
            "description": "Ratings keyed by source. Movies always carry `simkl` and `imdb`.",
            "properties": {
              "simkl": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "imdb": {
                "$ref": "#/components/schemas/ExternalRating"
              }
            },
            "additionalProperties": {
              "$ref": "#/components/schemas/ExternalRating"
            }
          },
          "trailers": {
            "type": [
              "array",
              "null"
            ],
            "description": "YouTube-hosted trailers and promo clips. Type 4 null when no trailers on file.",
            "items": {
              "type": "object",
              "required": [
                "youtube"
              ],
              "properties": {
                "name": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
                },
                "youtube": {
                  "type": "string",
                  "description": "YouTube video ID (not a full URL)."
                },
                "size": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Max video resolution height (720, 1080, 2160)."
                }
              }
            }
          },
          "release_dates": {
            "type": "array",
            "description": "Per-country release event timeline.",
            "items": {
              "type": "object",
              "required": [
                "iso_3166_1",
                "results"
              ],
              "properties": {
                "iso_3166_1": {
                  "type": "string",
                  "description": "ISO 3166-1 alpha-2 country code."
                },
                "results": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "type",
                      "release_date"
                    ],
                    "properties": {
                      "type": {
                        "type": "integer",
                        "description": "Release-event type: 1 = premiere, 2 = theatrical limited, 3 = theatrical wide, 4 = digital, 5 = physical, 6 = TV."
                      },
                      "release_date": {
                        "type": "string",
                        "format": "date"
                      }
                    }
                  }
                }
              }
            }
          },
          "users_recommendations": {
            "type": "array",
            "description": "Mini media objects suggested by Simkl based on this title's viewers.",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "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)."
                },
                "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)."
                },
                "type": {
                  "type": "string"
                },
                "ids": {
                  "type": "object",
                  "properties": {
                    "simkl": {
                      "type": "integer"
                    },
                    "slug": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "additionalProperties": true
      },
      "ShowDetail": {
        "type": "object",
        "description": "Full TV show record returned by `GET /tv/{id}`. Cloudflare-cached by Simkl ID. The `extended` query param is a legacy no-op here.",
        "required": [
          "title",
          "year",
          "type",
          "ids"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "year": {
            "type": "integer",
            "description": "First-aired year."
          },
          "type": {
            "type": "string",
            "enum": [
              "show"
            ],
            "description": "Always `show` on this endpoint. (The canonical media type for TV records is `show` — `tv` is reserved for the URL/route segment.) Live-verified 2026-05-14."
          },
          "ids": {
            "$ref": "#/components/schemas/Ids"
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "droprate": {
            "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": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "fanart": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "runtime": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Episode runtime in minutes (most common length). Type 4 null when unknown."
          },
          "certification": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). ISO 3166-1 alpha-2 country of origin."
          },
          "overview": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "genres": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "network": {
            "type": [
              "string",
              "null"
            ],
            "description": "Originating network or streamer (e.g. `HBO`, `Netflix`). Type 4 null when unknown."
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Production lifecycle bucket. **Closed set** of three values; the value is computed from the catalog's `Status` column plus the next-release timestamp at request time:\n\n- `tba` — air date is in the future (next-release timestamp > now)\n- `ended` — catalog status is `Ended`\n- `airing` — everything else (currently releasing, ongoing, hiatus)\n\nNote this is the **detail-endpoint** status. Listing endpoints (/anime/airing, /anime/best, etc.) use a wider enum from `::` (`returning series`, `ongoing`, `released`, `canceled`, `planned`, `in production`, `post production`, `rumored`, `upcoming`) — different shape, document separately.",
            "enum": [
              "tba",
              "ended",
              "airing",
              null
            ]
          },
          "first_aired": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Series premiere date."
          },
          "last_aired": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Date of the most recently aired episode."
          },
          "airs": {
            "type": [
              "object",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Recurring airing schedule (day-of-week, time, timezone). Fields vary; expect at least the broadcasting day for ongoing shows.",
            "additionalProperties": true
          },
          "total_episodes": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Total episode count across all aired and announced seasons."
          },
          "year_start_end": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Display-friendly range like `2008-2013`, or `2011-` for ongoing."
          },
          "ratings": {
            "type": "object",
            "description": "Ratings keyed by source. TV shows always carry `simkl` and `imdb`.",
            "properties": {
              "simkl": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "imdb": {
                "$ref": "#/components/schemas/ExternalRating"
              }
            },
            "additionalProperties": {
              "$ref": "#/components/schemas/ExternalRating"
            }
          },
          "trailers": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
                },
                "youtube": {
                  "type": "string"
                },
                "size": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
                }
              }
            },
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "users_recommendations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "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)."
                },
                "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)."
                },
                "type": {
                  "type": "string"
                },
                "ids": {
                  "type": "object",
                  "properties": {
                    "simkl": {
                      "type": "integer"
                    },
                    "slug": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "additionalProperties": true
      },
      "AnimeDetail": {
        "type": "object",
        "description": "Full anime record returned by `GET /anime/{id}`. Shares most fields with `ShowDetail` and adds anime-specific keys: `anime_type`, `en_title`, `studios`, `relations`, `season_name_year`, `mapped_tvdb_seasons`, plus extra `ids` (`mal`, `anidb`, `anilist`, `kitsu`). Cloudflare-cached by Simkl ID. The `extended` query param is a legacy no-op here. The anime detail handler is `include`d from the TV detail handler ( → `include ''`), so the response shape is identical to `ShowDetail` plus the anime-specific fields below.",
        "required": [
          "title",
          "year",
          "type",
          "ids",
          "anime_type"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "Original-language title (often romanized Japanese for anime)."
          },
          "en_title": {
            "type": [
              "string",
              "null"
            ],
            "description": "Localized English title when available. Type 4 null when no English title is on file (e.g. older classics like Death Note return an empty string here)."
          },
          "year": {
            "type": "integer"
          },
          "type": {
            "type": "string",
            "enum": [
              "anime"
            ],
            "description": "Always `anime` on this endpoint."
          },
          "anime_type": {
            "$ref": "#/components/schemas/AnimeFormat"
          },
          "ids": {
            "$ref": "#/components/schemas/Ids"
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "droprate": {
            "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": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "fanart": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "runtime": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Episode runtime in minutes."
          },
          "certification": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "Almost always `JP` for anime. Type 4 null on rare productions."
          },
          "overview": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "genres": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "network": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Originating TV station / streamer."
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "tba",
              "ended",
              "airing",
              null
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Production lifecycle bucket. **Closed set** of three values; the value is computed from the catalog's `Status` column plus the next-release timestamp at request time:\n\n- `tba` — air date is in the future (next-release timestamp > now)\n- `ended` — catalog status is `Ended`\n- `airing` — everything else (currently releasing, ongoing, hiatus)\n\nNote this is the **detail-endpoint** status. Listing endpoints (/anime/airing, /anime/best, etc.) use a wider enum from `::` (`returning series`, `ongoing`, `released`, `canceled`, `planned`, `in production`, `post production`, `rumored`, `upcoming`) — different shape, document separately."
          },
          "first_aired": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "last_aired": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "airs": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "total_episodes": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "year_start_end": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "season_name_year": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Display string like `Spring 2019` indicating the broadcasting cour."
          },
          "mapped_tvdb_seasons": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "AniDB/Simkl season numbers mapped onto the corresponding TVDB season numbers (anime catalogues split seasons differently between databases)."
          },
          "studios": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Production studios. Each entry typically carries a `name` and other identifiers."
          },
          "relations": {
            "type": "array",
            "description": "Related-titles graph: prequels, sequels, side stories, alternate versions. Each entry carries a small media-object plus a `relation_type` and `is_direct` flag indicating the relation.",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "title": {
                  "type": "string"
                },
                "en_title": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
                },
                "year": {
                  "type": "integer"
                },
                "anime_type": {
                  "$ref": "#/components/schemas/AnimeFormat"
                },
                "relation_type": {
                  "type": "string"
                },
                "is_direct": {
                  "type": "boolean"
                },
                "ids": {
                  "$ref": "#/components/schemas/Ids"
                }
              }
            }
          },
          "alt_titles": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "lang": {
                  "type": "integer"
                },
                "type": {
                  "$ref": "#/components/schemas/AltTitleType"
                }
              }
            }
          },
          "ratings": {
            "type": "object",
            "description": "Ratings keyed by source. Anime always carry `simkl` and `mal`; classic anime also include `imdb` when an IMDb entry exists.",
            "properties": {
              "simkl": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "mal": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "imdb": {
                "$ref": "#/components/schemas/ExternalRating"
              }
            },
            "additionalProperties": {
              "$ref": "#/components/schemas/ExternalRating"
            }
          },
          "trailers": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
                },
                "youtube": {
                  "type": "string"
                },
                "size": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
                }
              }
            },
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "users_recommendations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "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)."
                },
                "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)."
                },
                "type": {
                  "type": "string"
                },
                "ids": {
                  "type": "object",
                  "properties": {
                    "simkl": {
                      "type": "integer"
                    },
                    "slug": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "additionalProperties": true
      },
      "EpisodeDetail": {
        "type": "object",
        "description": "Episode listing entry returned by `GET /tv/episodes/{id}`. Cloudflare-cached by parent show ID. Nullable fields here follow [Null and missing values · Type 4 (unknown / data not on file)](/conventions/null-values).",
        "required": [
          "title",
          "type",
          "ids"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "Episode title in the response language."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Synopsis. Type 4 null when no synopsis is on file."
          },
          "season": {
            "type": "integer",
            "description": "Season number (1-based)."
          },
          "episode": {
            "type": "integer",
            "description": "Episode number within the season (1-based)."
          },
          "type": {
            "$ref": "#/components/schemas/EpisodeType"
          },
          "aired": {
            "type": "boolean",
            "description": "`true` if the episode has aired, `false` if it's still upcoming."
          },
          "img": {
            "type": [
              "string",
              "null"
            ],
            "description": "Episode still image path. Compose via [Images](/conventions/images). Type 4 null when no still is on file."
          },
          "date": {
            "type": [
              "string",
              "null"
            ],
            "description": "Air date+time in the originating network's timezone (e.g. `2011-04-17T21:00:00-05:00`). Type 4 null when the schedule isn't on file."
          },
          "ids": {
            "type": "object",
            "required": [
              "simkl_id"
            ],
            "properties": {
              "simkl_id": {
                "type": "integer",
                "description": "Simkl's internal numeric ID for this episode. Distinct from `ids.simkl` on the parent show."
              }
            }
          }
        }
      },
      "AnimeEpisodeDetail": {
        "type": "object",
        "description": "Anime episode listing entry returned by `GET /anime/episodes/{id}`. Same shape as `EpisodeDetail` except:\n\n- `season` is **omitted entirely** (Type 2 null) for regular TV-style anime episodes — AniDB numbers anime sequentially, not by season. Specials and movies that show up in the listing may carry `season`.\n- Adds an optional `tvdb` object with the corresponding TVDB season/episode mapping when available. AniDB and TVDB number anime differently, so this is the bridge for anime apps that index against TVDB.",
        "required": [
          "episode",
          "ids",
          "title",
          "type"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "season": {
            "type": "integer",
            "description": "Only present for specials and movies; omitted for regular TV-numbered episodes."
          },
          "episode": {
            "type": "integer",
            "description": "AniDB-style sequential episode number."
          },
          "type": {
            "$ref": "#/components/schemas/EpisodeType"
          },
          "aired": {
            "type": "boolean"
          },
          "img": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "date": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
          },
          "tvdb": {
            "type": "object",
            "description": "TVDB season/episode mapping for cross-referencing against TVDB-indexed catalogues. Omitted when no TVDB mapping is on file.",
            "properties": {
              "season": {
                "type": "integer"
              },
              "episode": {
                "type": "integer"
              }
            }
          },
          "ids": {
            "type": "object",
            "required": [
              "simkl_id"
            ],
            "properties": {
              "simkl_id": {
                "type": "integer"
              }
            }
          }
        }
      },
      "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"
        ]
      },
      "OAuthTokenRequest": {
        "type": "object",
        "required": [
          "code",
          "client_id",
          "grant_type"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Authorization code returned to your `redirect_uri`."
          },
          "client_id": {
            "type": "string",
            "description": "Your application's client_id."
          },
          "client_secret": {
            "type": "string",
            "description": "Your application's `client_secret`. Confidential flow only — mutually exclusive with `code_verifier`. Public clients (mobile / SPA / desktop) MUST NOT embed this value in shipped code; use the [PKCE flow](/api-reference/oauth-pkce) instead."
          },
          "redirect_uri": {
            "type": "string",
            "format": "uri",
            "example": "https://yourdomain.com/oauth.html",
            "description": "URL where the user was sent back with the `code`. Required on the confidential flow. On PKCE, required only if you sent one to `/oauth/authorize`. When sent, must match a URL registered for the app **byte-for-byte** (scheme, host, port, path, trailing slash, casing)."
          },
          "code_verifier": {
            "type": "string",
            "description": "PKCE code verifier (43–128 unreserved characters). Required on the PKCE flow — mutually exclusive with `client_secret`. Send the **original verifier**; Simkl re-derives the SHA-256 challenge and matches it against the `code_challenge` you sent on `/oauth/authorize`. On mismatch the response is `401 secret_error` with `\"PKCE verification failed\"` in the message field."
          },
          "grant_type": {
            "type": "string",
            "enum": [
              "authorization_code"
            ],
            "default": "authorization_code"
          }
        },
        "oneOf": [
          {
            "required": [
              "client_secret",
              "redirect_uri"
            ],
            "title": "Standard (client_secret)"
          },
          {
            "required": [
              "code_verifier"
            ],
            "title": "PKCE (code_verifier)"
          }
        ],
        "description": "Body for `POST /oauth/token`. Send `grant_type=authorization_code` plus the `code` you received at `redirect_uri`. Either `client_secret` (standard flow) or `code_verifier` (PKCE) must be present."
      },
      "OAuthTokenResponse": {
        "type": "object",
        "required": [
          "access_token",
          "token_type",
          "scope",
          "expires_in"
        ],
        "properties": {
          "access_token": {
            "type": "string",
            "description": "Long-lived bearer token. Save it securely; there is no refresh-token equivalent.",
            "example": "abc123def456"
          },
          "token_type": {
            "type": "string",
            "description": "Always `bearer` (lowercase, despite RFC 6750's canonical `Bearer` capitalization). Use case-insensitive matching when comparing.",
            "example": "bearer"
          },
          "scope": {
            "type": "string",
            "description": "Currently always `public`. Simkl does not have a scope system — tokens implicitly grant all permissions the user has approved for the app. The `scope` field is a placeholder kept for compatibility with OAuth 2.0 token-response shape; ignore its value.",
            "example": "public",
            "enum": [
              "public"
            ]
          },
          "expires_in": {
            "type": "integer",
            "description": "Token lifetime in seconds (RFC 6749 §5.1). Always `157680000` (about 5 years). The value is effectively infinite for practical session lengths — Simkl tokens remain valid until the user revokes the app from [Connected Apps settings](https://simkl.com/settings/connected-apps/). There is no `refresh_token`; if a 401 arrives before this lifetime expires, the user revoked your app — re-run the OAuth flow.",
            "example": 157680000
          }
        },
        "description": "Successful response from `POST /oauth/token`. Carries `access_token`, `token_type: bearer`, `scope: public`, and `expires_in: 157680000` (5 years). Notable omission vs RFC 6749 §5.1: no `refresh_token` — Simkl tokens are long-lived but not refreshable. A 401 on a subsequent authenticated call means the user revoked the app; re-run OAuth."
      },
      "PinCodeResponse": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string",
            "example": "OK"
          },
          "device_code": {
            "type": "string"
          },
          "user_code": {
            "type": "string",
            "example": "5G6JAH"
          },
          "verification_uri": {
            "type": "string",
            "example": "https://simkl.com/pin",
            "description": "Where the user enters `user_code`. RFC 8628 §3.2 spelling. Read this field."
          },
          "verification_url": {
            "type": "string",
            "example": "https://simkl.com/pin",
            "description": "Alias for `verification_uri` — same value, kept for back-compat. New code should read `verification_uri`."
          },
          "expires_in": {
            "type": "integer",
            "example": 900
          },
          "interval": {
            "type": "integer",
            "example": 5
          }
        },
        "description": "Step 1 response from `GET /oauth/pin`. Display `user_code`, point the user at `verification_uri`, and poll `GET /oauth/pin/{user_code}` every `interval` seconds until `expires_in` elapses."
      },
      "ActivityShowBlock": {
        "type": "object",
        "description": "Per-domain timestamps for TV shows and anime. Both types share the full five-status set (watching, plantowatch, hold, dropped, completed). Each timestamp is an ISO-8601 datetime, or `null` if the user has never had activity in that bucket — a *Type 1* null (\"never happened yet\", see [Null-value conventions](/conventions/null-values)).",
        "required": [
          "all",
          "rated_at",
          "playback",
          "plantowatch",
          "watching",
          "completed",
          "hold",
          "dropped",
          "removed_from_list"
        ],
        "properties": {
          "all": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Latest update across this domain. Fast first-pass check before drilling into per-status fields."
          },
          "rated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped on any rating add/change/remove for this domain. After a bump, call `GET /sync/ratings/{type}/{rating}` with `date_from` to fetch only the changed ratings."
          },
          "playback": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped on any scrobble/playback activity. After a bump, call `GET /sync/playback/{type}` to refresh in-progress sessions."
          },
          "plantowatch": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped when items move into or out of the `plantowatch` bucket."
          },
          "watching": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped when items move into or out of the `watching` bucket, or when episodes are marked/unmarked watched."
          },
          "completed": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped when items move into or out of the `completed` bucket."
          },
          "hold": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped when items move into or out of the `hold` bucket."
          },
          "dropped": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped when items move into or out of the `dropped` bucket."
          },
          "removed_from_list": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped when items are removed from the user's library entirely. `date_from` won't surface removals — to reconcile, call [`GET /sync/all-items/{type}/{status}`](/api-reference/simkl/get-all-items) with `extended=simkl_ids_only` (cheapest payload — just the IDs) and diff against your local cache. Walkthrough: [Detecting deletions](/guides/sync#phase-2-continuous-sync)."
          }
        }
      },
      "ActivityMovieBlock": {
        "type": "object",
        "description": "Per-domain timestamps for movies. Movies are single-session content, so this block **does not include `watching` or `hold`** — those keys are omitted entirely (not null). See [Watchlist statuses](/conventions/list-statuses) for the per-type matrix.",
        "required": [
          "all",
          "rated_at",
          "playback",
          "plantowatch",
          "completed",
          "dropped",
          "removed_from_list"
        ],
        "properties": {
          "all": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Latest update across movies."
          },
          "rated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped on any movie rating add/change/remove."
          },
          "playback": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped on any movie scrobble/playback activity."
          },
          "plantowatch": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped when movies move into or out of `plantowatch`."
          },
          "completed": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped when movies move into or out of `completed`."
          },
          "dropped": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped when movies move into or out of `dropped`."
          },
          "removed_from_list": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Bumped when movies are removed from the user's library entirely. `date_from` won't surface removals — call [`GET /sync/all-items/movies/{status}`](/api-reference/simkl/get-all-items) with `extended=simkl_ids_only` (cheapest payload — just the IDs) and diff against your local cache. Walkthrough: [Detecting deletions](/guides/sync#phase-2-continuous-sync)."
          }
        }
      },
      "Activities": {
        "type": "object",
        "description": "Last-activity envelope returned by `GET /sync/activities`. Use `all` as the cheapest first-pass check, then drill into a per-domain block only when its `all` has moved.",
        "required": [
          "all",
          "settings",
          "tv_shows",
          "anime",
          "movies"
        ],
        "properties": {
          "all": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Newest timestamp across every domain and bucket. Best first-level check — if this hasn't moved since your last sync, nothing has changed."
          },
          "settings": {
            "$ref": "#/components/schemas/ActivitySettingsBlock"
          },
          "tv_shows": {
            "$ref": "#/components/schemas/ActivityShowBlock"
          },
          "anime": {
            "$ref": "#/components/schemas/ActivityShowBlock"
          },
          "movies": {
            "$ref": "#/components/schemas/ActivityMovieBlock"
          }
        }
      },
      "ActivitySettingsBlock": {
        "type": "object",
        "description": "Top-level settings change marker. Bumped when the user changes any setting at https://simkl.com/settings/ (display name, time zone, privacy, etc.).",
        "required": [
          "all"
        ],
        "properties": {
          "all": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). Most recent change to account settings, or `null` if the user has never changed any setting since signup."
          }
        }
      },
      "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."
          }
        }
      },
      "PlaybackSession": {
        "type": "object",
        "description": "A saved (paused) playback session.",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Internal playback session ID. Use to delete via DELETE /sync/playback/{id}."
          },
          "progress": {
            "type": "number",
            "description": "Saved progress percentage 0–100."
          },
          "watched_at": {
            "type": "string",
            "format": "date-time"
          },
          "movie": {
            "$ref": "#/components/schemas/Movie"
          },
          "show": {
            "$ref": "#/components/schemas/Show"
          },
          "anime": {
            "$ref": "#/components/schemas/Anime"
          },
          "episode": {
            "$ref": "#/components/schemas/Episode"
          }
        }
      },
      "AddToListRequest": {
        "type": "object",
        "description": "Body for `POST /sync/add-to-list`. Moves items into one of the user's Watchlist statuses. Items go under `movies[]`, `shows[]`, or `anime[]` — Simkl resolves anime titles correctly under either `shows[]` or `anime[]`, so match the field to your data type when known.",
        "required": [
          "to"
        ],
        "properties": {
          "to": {
            "$ref": "#/components/schemas/WatchlistStatus"
          },
          "movies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Movie"
            }
          },
          "shows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Show"
            }
          },
          "anime": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Show"
            },
            "description": "Array of anime entries (same shape as `shows[]`)."
          }
        }
      },
      "HistoryRequest": {
        "type": "object",
        "description": "Body for `/sync/history` and `/sync/history/remove`. Items go under `movies[]`, `shows[]`, or `anime[]` — Simkl resolves anime titles correctly under either `shows[]` or `anime[]`, so match the field to your data type when known.",
        "properties": {
          "movies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Movie"
            }
          },
          "shows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Show"
            }
          },
          "episodes": {
            "type": "array",
            "description": "Top-level convenience array for marking episode-level history without nesting. The server wraps each entry into a synthetic single-season show. Each item carries the same shape as items under `shows[].seasons[].episodes[]` plus the parent `show` reference.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "anime": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Show"
            },
            "description": "Array of anime entries (same shape as `shows[]`)."
          }
        }
      },
      "RatingItem": {
        "type": "object",
        "required": [
          "rating",
          "ids"
        ],
        "properties": {
          "rating": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10
          },
          "rated_at": {
            "type": "string",
            "format": "date-time"
          },
          "ids": {
            "$ref": "#/components/schemas/Ids"
          }
        }
      },
      "RatingsRequest": {
        "type": "object",
        "description": "Body for `/sync/ratings` and `/sync/ratings/remove`. The `rating` field on each item is required for /sync/ratings, ignored for /sync/ratings/remove.",
        "properties": {
          "movies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RatingItem"
            }
          },
          "shows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RatingItem"
            }
          },
          "anime": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RatingItem"
            }
          }
        }
      },
      "PinPollPending": {
        "type": "object",
        "description": "PIN flow polling response while waiting for the user to enter the code.",
        "properties": {
          "result": {
            "type": "string",
            "example": "KO"
          },
          "message": {
            "type": "string",
            "example": "Authorization pending"
          }
        }
      },
      "PinPollComplete": {
        "type": "object",
        "description": "PIN flow polling response after the user has entered the code.",
        "properties": {
          "result": {
            "type": "string",
            "example": "OK"
          },
          "access_token": {
            "type": "string"
          }
        }
      },
      "WatchedLookupItem": {
        "type": "object",
        "description": "An item to look up — pass any one or more external IDs (Simkl resolves to canonical record). For per-episode watched-status lookup, also pair `season` + `episode`.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Ids"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "show",
                  "movie",
                  "anime"
                ],
                "description": "Item type. Helps the lookup find the right title when the same external ID could match multiple types. Optional but recommended.",
                "example": "show"
              },
              "season": {
                "type": "integer",
                "minimum": 0,
                "description": "For episode-level lookup: which season. Pair with `episode`. Per-episode results are returned alongside the title-level `result` field.",
                "example": 1
              },
              "episode": {
                "type": "integer",
                "minimum": 1,
                "description": "For episode-level lookup: which episode within the `season`. Pair with `season`. Result reflects whether the user has watched that specific episode.",
                "example": 3
              }
            }
          }
        ]
      },
      "WatchedLookupRequest": {
        "type": "array",
        "description": "Array of items to look up. Each item carries one or more external IDs.",
        "items": {
          "$ref": "#/components/schemas/WatchedLookupItem"
        }
      },
      "AddToListResponse": {
        "type": "object",
        "description": "Response from `POST /sync/add-to-list`.",
        "properties": {
          "added": {
            "type": "object",
            "properties": {
              "movies": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "title": {
                      "type": "string",
                      "example": "The Walking Dead"
                    },
                    "year": {
                      "type": "integer",
                      "example": 2010
                    },
                    "to": {
                      "$ref": "#/components/schemas/WatchlistStatus"
                    },
                    "ids": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Echoed IDs from the request."
                    }
                  },
                  "description": "Item echoed back from the request. The `to` field may differ from what you sent — Simkl silently downgrades `completed` to `watching` (for currently-airing titles) or `plantowatch` (for unreleased titles)."
                }
              },
              "shows": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "title": {
                      "type": "string",
                      "example": "The Walking Dead"
                    },
                    "year": {
                      "type": "integer",
                      "example": 2010
                    },
                    "to": {
                      "$ref": "#/components/schemas/WatchlistStatus"
                    },
                    "ids": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Echoed IDs from the request."
                    }
                  },
                  "description": "Item echoed back from the request. The `to` field may differ from what you sent — Simkl silently downgrades `completed` to `watching` (for currently-airing titles) or `plantowatch` (for unreleased titles)."
                }
              },
              "anime": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "title": {
                      "type": "string",
                      "example": "The Walking Dead"
                    },
                    "year": {
                      "type": "integer",
                      "example": 2010
                    },
                    "to": {
                      "$ref": "#/components/schemas/WatchlistStatus"
                    },
                    "ids": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Echoed IDs from the request."
                    }
                  },
                  "description": "Item echoed back from the request. The `to` field may differ from what you sent — Simkl silently downgrades `completed` to `watching` (for currently-airing titles) or `plantowatch` (for unreleased titles)."
                }
              }
            }
          },
          "not_found": {
            "$ref": "#/components/schemas/NotFoundReport"
          }
        }
      },
      "NotFoundReport": {
        "type": "object",
        "description": "Items Simkl could not match. Inspect this to surface diagnostics back to your users. Anime entries that fail to resolve land in `shows` regardless of which top-level array they were sent under — there is no separate `anime` bucket in not_found.",
        "properties": {
          "movies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Movie"
            }
          },
          "shows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Show"
            }
          },
          "episodes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Show"
            }
          }
        }
      },
      "SyncStatusItem": {
        "type": "object",
        "description": "Per-item result of a sync write.",
        "properties": {
          "request": {
            "type": "object",
            "description": "Echo of the input item."
          },
          "response": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "watching",
                  "plantowatch",
                  "hold",
                  "dropped",
                  "completed",
                  "removed"
                ],
                "description": "Resulting list status."
              },
              "simkl_type": {
                "type": "string",
                "enum": [
                  "movie",
                  "tv",
                  "anime"
                ]
              },
              "anime_type": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
              }
            }
          },
          "rewatch_id": {
            "type": "integer",
            "description": "Present when a rewatch session was created or resumed by this call. Use this value on subsequent writes to update the same session."
          },
          "rewatch_status": {
            "type": "string",
            "enum": [
              "active",
              "completed",
              "closed"
            ],
            "description": "Lifecycle state of the rewatch session referenced by `rewatch_id`. Writable values: `active`, `closed`, and (movies only) `completed`. For TV / anime, `completed` is silently clamped to `closed` — only coverage of every aired regular episode (specials in season 0 don't count) promotes a show session to `completed`. A `closed` write against a coverage-earned `completed` session is a no-op. Resuming a finished session without `rewatch_id` requires a `last_watched_at` / `watched_at` that pinpoints the target row; bare `is_rewatch: true` (no `rewatch_status`) always targets the singleton `active` session. See [Rewatches guide → Session states](/guides/rewatches#session-states)."
          }
        }
      },
      "HistoryAddResponse": {
        "type": "object",
        "description": "Response from `POST /sync/history`. Note: `not_found.shows` includes any anime entries that failed to resolve, regardless of whether they were sent under `anime[]` or `shows[]` — there is no separate `not_found.anime` bucket.",
        "properties": {
          "added": {
            "type": "object",
            "properties": {
              "movies": {
                "type": "integer",
                "description": "New items added to the user's `Completed` movies list."
              },
              "shows": {
                "type": "integer",
                "description": "New shows added to the user's library."
              },
              "episodes": {
                "type": "integer",
                "description": "Number of episodes marked watched."
              },
              "statuses": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SyncStatusItem"
                }
              }
            }
          },
          "not_found": {
            "$ref": "#/components/schemas/NotFoundReport"
          }
        }
      },
      "HistoryRemoveResponse": {
        "type": "object",
        "description": "Counts of items removed plus any IDs Simkl could not match.",
        "properties": {
          "deleted": {
            "type": "object",
            "properties": {
              "movies": {
                "type": "integer",
                "description": "Number of movies removed from the user's library.",
                "example": 1
              },
              "shows": {
                "type": "integer",
                "description": "Number of shows removed from the user's library entirely (only counts items where you sent the show without `seasons`/`episodes`).",
                "example": 0
              },
              "episodes": {
                "type": "integer",
                "description": "Number of individual episodes unmarked as watched. The parent show stays in the user's library.",
                "example": 4
              }
            },
            "required": [
              "movies",
              "shows",
              "episodes"
            ]
          },
          "not_found": {
            "type": "object",
            "description": "Per-type lists of input items Simkl could not match. **There is no `not_found.episodes` array** — even when you targeted specific episodes, only the parent movie/show object lands here if the lookup failed.",
            "properties": {
              "movies": {
                "type": "array",
                "items": {
                  "type": "object"
                },
                "description": "Input movie objects Simkl could not match."
              },
              "shows": {
                "type": "array",
                "items": {
                  "type": "object"
                },
                "description": "Input show/anime objects Simkl could not match."
              }
            },
            "required": [
              "movies",
              "shows"
            ]
          }
        },
        "required": [
          "deleted",
          "not_found"
        ]
      },
      "RatingsAddResponse": {
        "type": "object",
        "description": "Response from `POST /sync/ratings`.",
        "properties": {
          "added": {
            "type": "object",
            "properties": {
              "movies": {
                "type": "integer"
              },
              "shows": {
                "type": "integer"
              },
              "statuses": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SyncStatusItem"
                }
              }
            }
          },
          "not_found": {
            "$ref": "#/components/schemas/NotFoundReport"
          }
        }
      },
      "UserStats": {
        "type": "object",
        "description": "Aggregate watch statistics for a user.",
        "properties": {
          "user": {
            "type": "object",
            "properties": {
              "id": {
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "joined_at": {
                "type": "string",
                "format": "date-time"
              },
              "avatar": {
                "type": "string",
                "format": "uri"
              },
              "gender": {
                "type": "string"
              },
              "loc": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
              },
              "age": {
                "type": "string",
                "description": "Age in years, pre-formatted as a string like `\"30 years\"`. Empty string if the user has not set their birthday or has disabled age display. Pre-formatted by the server — clients should display verbatim rather than parsing.",
                "example": "30 years"
              },
              "type": {
                "$ref": "#/components/schemas/AccountPlan"
              }
            }
          },
          "total_mins": {
            "type": "integer",
            "description": "Total minutes watched across movies, TV, and anime."
          },
          "movies": {
            "type": "object"
          },
          "tv": {
            "type": "object"
          },
          "anime": {
            "type": "object"
          },
          "watched_last_week": {
            "type": "object"
          }
        }
      },
      "UserSettings": {
        "type": "object",
        "description": "Authenticated user's profile and account settings.",
        "properties": {
          "user": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "joined_at": {
                "type": "string",
                "format": "date-time"
              },
              "gender": {
                "type": "string"
              },
              "avatar": {
                "type": "string",
                "format": "uri"
              },
              "bio": {
                "type": "string"
              },
              "loc": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
              },
              "age": {
                "type": "string",
                "description": "Age in years, pre-formatted as a string like `\"30 years\"`. Empty string if the user has not set their birthday or has disabled age display. Pre-formatted by the server — clients should display verbatim rather than parsing.",
                "example": "30 years"
              }
            }
          },
          "account": {
            "type": "object",
            "properties": {
              "id": {
                "type": "integer"
              },
              "timezone": {
                "type": "string",
                "example": "Europe/Madrid"
              },
              "type": {
                "$ref": "#/components/schemas/AccountPlan"
              }
            }
          }
        }
      },
      "RecentlyWatchedBackground": {
        "type": "object",
        "description": "Metadata about the user's most recently watched item. Returned by `GET /users/recently-watched-background/{user_id}` when called WITHOUT the `?image=` query param. The `poster` and `fanart` fields are catalog image keys (the on-disk path prefix) — to render the actual JPG, either call the same endpoint again with `?image=poster` (or `?image=fanart`) to get a 302 redirect to the JPG, or concatenate manually: `https://simkl.net/posters/<poster>_0.jpg` / `https://simkl.net/fanart/<fanart>_0.jpg`.",
        "required": [
          "id",
          "url",
          "title"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Simkl id of the most recently watched item.",
            "example": 17465
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical `simkl.com/<type>/<id>/<slug>` URL — drop into a card heading or share button.",
            "example": "https://simkl.com/tv/17465/game-of-thrones"
          },
          "title": {
            "type": "string",
            "description": "Display title of the most recently watched item.",
            "example": "Game of Thrones"
          },
          "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). When present, the poster image key (e.g. `\"17/17465abcd\"`) — render as `https://simkl.net/posters/<this>_0.jpg`.",
            "example": "17/17465posterkey"
          },
          "fanart": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values). When present, the fanart image key — render as `https://simkl.net/fanart/<this>_0.jpg`.",
            "example": "17/17465fanartkey"
          }
        }
      },
      "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"
          }
        }
      },
      "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"
          }
        }
      },
      "RatingsRemoveResponse": {
        "type": "object",
        "description": "Counts of ratings cleared plus any IDs Simkl could not match.",
        "properties": {
          "deleted": {
            "type": "object",
            "properties": {
              "movies": {
                "type": "integer",
                "description": "Number of movies for which a rating was cleared (or that matched but had no rating to begin with — the counter increments unconditionally on successful match).",
                "example": 1
              },
              "shows": {
                "type": "integer",
                "description": "Number of shows or anime for which a rating was cleared. Anime is folded under `shows` (same as on `POST /sync/ratings`).",
                "example": 0
              }
            },
            "required": [
              "movies",
              "shows"
            ]
          },
          "not_found": {
            "type": "object",
            "description": "Per-type lists of input items Simkl could not match. No `anime` key — anime is folded under `shows`.",
            "properties": {
              "movies": {
                "type": "array",
                "items": {
                  "type": "object"
                },
                "description": "Input movie objects Simkl could not match."
              },
              "shows": {
                "type": "array",
                "items": {
                  "type": "object"
                },
                "description": "Input show/anime objects Simkl could not match."
              }
            },
            "required": [
              "movies",
              "shows"
            ]
          }
        },
        "required": [
          "deleted",
          "not_found"
        ]
      },
      "RatingsAddRequest": {
        "type": "object",
        "description": "Request body for adding/updating ratings. Each item must include `rating` (1–10 integer). To unset a rating without re-rating, use [`POST /sync/ratings/remove`](/api-reference/simkl/remove-ratings) instead. Items go under `movies[]`, `shows[]`, or `anime[]` — Simkl resolves anime titles correctly under either `shows[]` or `anime[]`, so match the field to your data type when known.",
        "properties": {
          "movies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RatingItem"
            }
          },
          "shows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RatingItem"
            }
          },
          "anime": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RatingItem"
            },
            "description": "Array of anime entries (same shape as `shows[]`)."
          }
        }
      },
      "RatingsRemoveRequest": {
        "type": "object",
        "description": "Request body for removing ratings. The `rating` field is not needed — identify items by `ids` (or `title` + `year`), and Simkl clears any rating set on them. To set or change a rating, use [`POST /sync/ratings`](/api-reference/simkl/add-ratings) instead. Items go under `movies[]`, `shows[]`, or `anime[]` — Simkl resolves anime titles correctly under either `shows[]` or `anime[]`, so match the field to your data type when known.",
        "properties": {
          "movies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RatingItem"
            }
          },
          "shows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RatingItem"
            }
          },
          "anime": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RatingItem"
            },
            "description": "Array of anime entries (same shape as `shows[]`)."
          }
        }
      },
      "CalendarItem": {
        "title": "Calendar entry",
        "type": "object",
        "description": "A single calendar entry. The same shape appears in both the rolling-window file (`/calendar/{type}.json`) and the monthly archive (`/calendar/{year}/{month}/{type}.json`). Per-type variations: TV / anime items carry an `episode` block; movie files do not. Anime items additionally carry `anime_type`.",
        "properties": {
          "title": {
            "type": "string",
            "description": "Display title."
          },
          "poster": {
            "type": [
              "string",
              "null"
            ],
            "description": "Image path fragment. Combine with the prefixes in [Image conventions](/conventions/images) — for example `https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`. **Type 4 null** — `null` when no poster is on file. See [Null and missing values](/conventions/null-values#type-4)."
          },
          "date": {
            "type": "string",
            "description": "Air/release timestamp with the catalog's timezone offset (e.g. `2026-05-16T00:00:00-05:00` for US TV, `+09:00` for Japanese anime). Use this for chronological sorting and timezone-aware display.",
            "example": "2026-05-16T00:00:00-05:00"
          },
          "release_date": {
            "type": "string",
            "format": "date",
            "description": "Original premiere date in `YYYY-MM-DD` format. The show or movie's first-ever release (not the per-episode air date — that's in `date`).",
            "example": "2016-10-15"
          },
          "rank": {
            "type": "integer",
            "description": "Simkl popularity rank. `0` for items that aren't yet ranked (very common on new / regional titles). Lower non-zero values = more popular."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Absolute simkl.com URL (with slug).",
            "example": "https://simkl.com/tv/1520136/ruin-road"
          },
          "ratings": {
            "type": "object",
            "description": "Aggregate ratings keyed by source (`simkl`, `imdb`, `mal`). Only sources with on-file data appear.",
            "additionalProperties": {
              "$ref": "#/components/schemas/ExternalRating"
            }
          },
          "ids": {
            "type": "object",
            "description": "External and Simkl IDs for the item. Always carries `simkl_id` and `slug`. `tmdb` is near-universal. `imdb` appears on TV / movies; `mal` on anime. Additional slug variants (`letterslug`, `traktmslug`, `tvdbslug`, `trakttvslug`, `mdlslug`, etc.) may appear on items that have those platform links — the response is permissive.",
            "additionalProperties": true,
            "properties": {
              "simkl_id": {
                "type": "integer",
                "description": "Canonical Simkl ID."
              },
              "slug": {
                "type": "string",
                "description": "Simkl URL slug."
              },
              "imdb": {
                "type": "string",
                "description": "IMDb ID (`tt…`)."
              },
              "tmdb": {
                "type": "string",
                "description": "TMDB ID."
              },
              "tvdb": {
                "type": "string",
                "description": "TVDB ID."
              },
              "mal": {
                "type": "string",
                "description": "MyAnimeList ID."
              },
              "anidb": {
                "type": "string",
                "description": "AniDB ID."
              },
              "anilist": {
                "type": "string",
                "description": "AniList ID."
              },
              "kitsu": {
                "type": "string",
                "description": "Kitsu ID."
              }
            },
            "required": [
              "simkl_id",
              "slug"
            ]
          },
          "episode": {
            "type": "object",
            "description": "**TV / anime only.** Episode reference for the airing. Movies omit this block entirely.",
            "properties": {
              "season": {
                "type": "integer",
                "description": "Season number. **Present on TV; omitted on anime** (anime uses AniDB sequential numbering — no seasons). Type 2 null (key absence) on anime."
              },
              "episode": {
                "type": "integer",
                "description": "Episode number within the season (1-based)."
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Absolute simkl.com URL for the episode."
              }
            },
            "required": [
              "episode",
              "url"
            ]
          },
          "anime_type": {
            "type": "string",
            "enum": [
              "tv",
              "movie",
              "ova",
              "ona",
              "special",
              "music"
            ],
            "description": "**Anime files only.** Catalog format for the title. Movies and TV files omit this key entirely."
          }
        },
        "required": [
          "title",
          "date",
          "release_date",
          "rank",
          "url",
          "ids"
        ]
      },
      "TrendingItem": {
        "title": "Trending entry",
        "type": "object",
        "description": "A single trending entry. Used by `/discover/trending/*` and `/discover/dvd/*` files. Per-type fields: TV / anime carry `total_episodes` + `network`; movies carry `dvd_date` + `theater`; anime additionally carries `anime_type`.",
        "properties": {
          "title": {
            "type": "string",
            "example": "Project Hail Mary"
          },
          "url": {
            "type": "string",
            "description": "Relative simkl.com path (prepend `https://simkl.com`). Note: this is RELATIVE on trending files, unlike calendar entries which return absolute URLs.",
            "example": "/movie/1306562/project-hail-mary"
          },
          "poster": {
            "type": "string"
          },
          "fanart": {
            "type": "string"
          },
          "rank": {
            "type": "integer"
          },
          "drop_rate": {
            "type": "string",
            "description": "Percentage of users who dropped, pre-formatted (e.g. `\"1.6%\"`).",
            "example": "0.2%"
          },
          "watched": {
            "type": "integer",
            "description": "Number of users who watched in the timeframe."
          },
          "plan_to_watch": {
            "type": "integer"
          },
          "release_date": {
            "type": "string",
            "description": "`MM/DD/YYYY` format (different from calendar files which use `YYYY-MM-DD`).",
            "example": "03/15/2026"
          },
          "country": {
            "type": "string",
            "example": "us"
          },
          "runtime": {
            "type": "string",
            "example": "2h 37m"
          },
          "status": {
            "type": "string",
            "description": "Title status (e.g. `ended`, `ongoing`)."
          },
          "genres": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "trailer": {
            "type": "string",
            "description": "YouTube video ID (just the ID — prepend `https://youtube.com/watch?v=`)."
          },
          "overview": {
            "type": "string"
          },
          "metadata": {
            "type": "string",
            "description": "Pre-formatted summary line for display (e.g. `'March 15, 2026 • Budget $200M • Box office $660M'`)."
          },
          "ratings": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/ExternalRating"
            }
          },
          "ids": {
            "type": "object",
            "description": "External and Simkl IDs for the item. Trending entries carry the richest ID set in the API — expect 8+ keys per item including platform-specific slug variants. Additional slug variants (`letterslug`, `traktmslug`, `tvdbslug`, `trakttvslug`, `mdlslug`, etc.) may appear on items that have those platform links — the response is permissive.",
            "additionalProperties": true,
            "properties": {
              "simkl_id": {
                "type": "integer",
                "description": "Canonical Simkl ID."
              },
              "slug": {
                "type": "string",
                "description": "Simkl URL slug."
              },
              "imdb": {
                "type": "string",
                "description": "IMDb ID (`tt…`)."
              },
              "tmdb": {
                "type": "string",
                "description": "TMDB ID."
              },
              "tvdb": {
                "type": "string",
                "description": "TVDB ID."
              },
              "mal": {
                "type": "string",
                "description": "MyAnimeList ID."
              },
              "anidb": {
                "type": "string",
                "description": "AniDB ID."
              },
              "anilist": {
                "type": "string",
                "description": "AniList ID."
              },
              "kitsu": {
                "type": "string",
                "description": "Kitsu ID."
              }
            },
            "required": [
              "simkl_id",
              "slug"
            ]
          },
          "total_episodes": {
            "type": "integer",
            "description": "**TV / anime only.** Total episode count."
          },
          "network": {
            "type": "string",
            "description": "**TV / anime only.** Broadcasting network."
          },
          "anime_type": {
            "type": "string",
            "enum": [
              "tv",
              "movie",
              "ova",
              "ona",
              "special",
              "music"
            ],
            "description": "**Anime only.**"
          },
          "dvd_date": {
            "type": "string",
            "description": "**Movies only.** `MM/DD/YYYY` DVD/Blu-ray release date."
          },
          "theater": {
            "type": "string",
            "description": "**Movies only.** `MM/DD/YYYY` theatrical release date."
          }
        },
        "required": [
          "title",
          "url",
          "rank",
          "ids"
        ]
      },
      "TrendingCombinedResponse": {
        "title": "Trending — combined response",
        "type": "object",
        "description": "Returned by `/discover/trending/{file}.json`. Three arrays of trending items, one per category. Each category is independently ranked.",
        "properties": {
          "movies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrendingItem"
            }
          },
          "tv": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrendingItem"
            }
          },
          "anime": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrendingItem"
            }
          }
        },
        "required": [
          "movies",
          "tv",
          "anime"
        ]
      },
      "EpisodeType": {
        "type": "string",
        "enum": [
          "episode",
          "special"
        ],
        "description": "Episode classification. `episode` for regular numbered episodes, `special` for one-off content (specials, clip shows, behind-the-scenes, picture dramas, etc.). On TV episode lists specials follow the regular run; on anime listings specials and movies share this enum."
      },
      "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."
      },
      "AltTitleType": {
        "type": "string",
        "enum": [
          "official",
          "short",
          "synonym",
          "original"
        ],
        "description": "Classification of an entry in `alt_titles`. `official` = broadcaster/distributor-supplied localization, `short` = shortened form, `synonym` = community-supplied alias, `original` = original-language title (typically Japanese for anime)."
      },
      "AccountPlan": {
        "type": "string",
        "enum": [
          "free",
          "pro",
          "vip"
        ],
        "description": "Simkl account plan tier. `free` is the default; `pro` and `vip` are paid tiers that unlock higher rate limits and additional features. Some endpoints gate behavior on this value."
      },
      "WatchedLookupResponse": {
        "type": "array",
        "description": "One result per input item, in input order. See the operation description for the full per-item shape and how the optional episode-breakdown fields are gated on the `extended` query parameter.",
        "items": {
          "type": "object",
          "description": "One result, in the same order as the request array. Echoes the input identifiers (so you can correlate without index gymnastics) and adds the watch-status fields.",
          "properties": {
            "result": {
              "description": "`true` if the user has watched (or is watching) the item, `false` if Simkl matched the IDs but the item isn't in the user's library, or the literal string `\"not_found\"` if Simkl couldn't resolve the IDs to any catalog entry.",
              "oneOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "string",
                  "enum": [
                    "not_found"
                  ]
                }
              ],
              "example": true
            },
            "simkl": {
              "type": "integer",
              "description": "Canonical Simkl ID. Omitted when `result: \"not_found\"`.",
              "example": 2090
            },
            "list": {
              "type": [
                "string",
                "null"
              ],
              "enum": [
                "watching",
                "completed",
                "plantowatch",
                "hold",
                "dropped",
                null
              ],
              "description": "Current watchlist status. **Type 4 null** — `null` when the item resolved to a Simkl record but isn't in any of the user's lists. See [Null and missing values](/conventions/null-values).",
              "example": "completed"
            },
            "last_watched_at": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time",
              "description": "ISO-8601 timestamp of the most recent watch event for this item. **Type 4 null** — `null` if the item has never been watched. See [Null and missing values](/conventions/null-values).",
              "example": "2026-05-15T00:35:15Z"
            },
            "episodes_total": {
              "type": "integer",
              "description": "Present only with `extended=episodes` or `extended=counters` (shows/anime).",
              "example": 177
            },
            "episodes_aired": {
              "type": "integer",
              "description": "Present only with `extended=episodes` or `extended=counters`.",
              "example": 177
            },
            "episodes_to_be_aired": {
              "type": "integer",
              "description": "Present only with `extended=episodes` or `extended=counters`.",
              "example": 0
            },
            "episodes_watched": {
              "type": "integer",
              "description": "Present only with `extended=episodes` or `extended=counters`.",
              "example": 177
            },
            "seasons": {
              "type": "array",
              "description": "Per-season breakdown. Present only with `extended=episodes` or `extended=counters` (shows/anime). With `extended=counters` alone, the inner `episodes[]` array is omitted.",
              "items": {
                "type": "object",
                "properties": {
                  "number": {
                    "type": "integer",
                    "example": 1
                  },
                  "episodes_total": {
                    "type": "integer",
                    "example": 6
                  },
                  "episodes_aired": {
                    "type": "integer",
                    "example": 6
                  },
                  "episodes_to_be_aired": {
                    "type": "integer",
                    "example": 0
                  },
                  "episodes_watched": {
                    "type": "integer",
                    "example": 6
                  },
                  "episodes": {
                    "type": "array",
                    "description": "Per-episode array. Present with `extended=episodes`, omitted with `extended=counters` alone.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "number": {
                          "type": "integer",
                          "example": 1
                        },
                        "watched": {
                          "type": "boolean",
                          "example": true
                        },
                        "aired": {
                          "type": "boolean",
                          "example": true
                        },
                        "last_watched_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "Per-episode last-watched timestamp. **Type 4 null** — `null` if the user has marked the title completed but Simkl has no specific per-episode timestamp. See [Null and missing values](/conventions/null-values).",
                          "example": null
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "additionalProperties": true
        }
      },
      "AllItemsEntry": {
        "type": "object",
        "description": "One item in the user's library. The exact set of fields present depends on the `extended` query parameter:\n\n- **no `extended`** (default): metadata fields + `<show|movie>` block with `ids` + watch state\n- **`extended=simkl_ids_only`**: ONLY `<show|movie>.ids: {simkl, slug}` — smallest payload, ideal for `date_from` deltas\n- **`extended=ids_only`**: ONLY `<show|movie>.ids` including all external IDs (imdb, tmdb, tvdb, mal, anidb, anilist, kitsu)\n- **`extended=full`**: adds `<show|movie>.runtime` and (for shows/anime with episodes loaded) `seasons[].episodes[]`\n- **`extended=full_anime_seasons`**: same as `full` plus `mapped_tvdb_seasons` on anime entries",
        "properties": {
          "added_to_watchlist_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the user added this item to their watchlist. **Type 4 null** — `null` for legacy entries without a recorded add-time. See [Null and missing values](/conventions/null-values).",
            "example": "2026-05-15T00:35:15Z"
          },
          "last_watched_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp of the most recent watch event. **Type 4 null** — `null` if the user has never watched any episode (e.g. `plantowatch` items). See [Null and missing values](/conventions/null-values).",
            "example": "2026-05-15T00:35:15Z"
          },
          "user_rated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the user set their rating. **Type 4 null** — `null` if not rated. See [Null and missing values](/conventions/null-values)."
          },
          "user_rating": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "maximum": 10,
            "description": "The user's rating (1-10). **Type 4 null** — `null` if not rated. See [Null and missing values](/conventions/null-values)."
          },
          "status": {
            "type": "string",
            "enum": [
              "watching",
              "plantowatch",
              "hold",
              "completed",
              "dropped"
            ],
            "description": "Current watchlist status. Movies skip `watching` and `hold` per [Watchlist statuses](/conventions/list-statuses)."
          },
          "last_watched": {
            "type": [
              "string",
              "null"
            ],
            "description": "Most recently watched episode marker (e.g. `\"S05E16\"`). **Type 4 null** — `null` on movies (no episodes) and on shows/anime where no episode has been watched yet.",
            "example": "S05E16"
          },
          "next_to_watch": {
            "type": [
              "string",
              "null"
            ],
            "description": "Next episode marker (e.g. `\"S08E03\"`). **Type 4 null** — `null` when caught up, when status is `completed`/`dropped`, or on movies.",
            "example": "S08E03"
          },
          "watched_episodes_count": {
            "type": "integer",
            "description": "Number of episodes the user has watched. `0` for `plantowatch` items and movies."
          },
          "total_episodes_count": {
            "type": "integer",
            "description": "Total episodes in the series (including unaired). `0` on movies."
          },
          "not_aired_episodes_count": {
            "type": "integer",
            "description": "Episodes that haven't aired yet. `0` on movies and completed series."
          },
          "show": {
            "type": "object",
            "description": "Present for `shows` and `anime` entries (mutually exclusive with `movie`).",
            "properties": {
              "title": {
                "type": "string",
                "example": "The Walking Dead"
              },
              "poster": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Type 4 null — no poster on file for this title. See [Null and missing values](/conventions/null-values).",
                "example": "16/16913426086fc13"
              },
              "year": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Type 4 null — release year not on file. See [Null and missing values](/conventions/null-values).",
                "example": 2010
              },
              "runtime": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Type 4 null — episode runtime not on file. Present only with `extended=full` or `extended=full_anime_seasons`. See [Null and missing values](/conventions/null-values).",
                "example": 43
              },
              "ids": {
                "type": "object",
                "additionalProperties": true,
                "description": "Always includes `simkl` + `slug`. With `extended=ids_only` or higher, includes all external IDs Simkl has on file (imdb, tmdb, tvdb, mal, anidb, anilist, kitsu, etc.)."
              }
            }
          },
          "movie": {
            "type": "object",
            "description": "Present for `movies` entries (mutually exclusive with `show`).",
            "properties": {
              "title": {
                "type": "string",
                "example": "The Godfather"
              },
              "poster": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Type 4 null — no poster on file for this title. See [Null and missing values](/conventions/null-values)."
              },
              "year": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Type 4 null — release year not on file. See [Null and missing values](/conventions/null-values)."
              },
              "runtime": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Type 4 null — runtime not on file. Present only with `extended=full`. See [Null and missing values](/conventions/null-values)."
              },
              "ids": {
                "type": "object",
                "additionalProperties": true,
                "description": "Always includes `simkl` + `slug`. With `extended=ids_only` or higher, includes all external IDs."
              }
            }
          },
          "anime_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "tv",
              "movie",
              "ova",
              "ona",
              "special",
              "music video",
              null
            ],
            "description": "Type 4 null — anime_type unknown for this title. Present only on `anime[]` entries. The MyAnimeList-style classification of the anime title. See [Null and missing values](/conventions/null-values)."
          },
          "mapped_tvdb_seasons": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Present only on `anime[]` entries with `extended=full_anime_seasons`. TVDB season numbers this anime maps to."
          },
          "memo": {
            "oneOf": [
              {
                "title": "Public memo",
                "type": "object",
                "description": "Public memo — visible to other Simkl users on the owner's profile. Returned when `is_private: false`.",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The memo body. Markdown is not parsed — Simkl stores and returns it as plain text.",
                    "example": "Best season of the show — rewatching with friends next month."
                  },
                  "is_private": {
                    "type": "boolean",
                    "description": "`false` for the public branch — anyone visiting the owner's profile can read this memo.",
                    "enum": [
                      false
                    ],
                    "example": false
                  }
                },
                "required": [
                  "text",
                  "is_private"
                ],
                "example": {
                  "text": "Best season of the show — rewatching with friends next month.",
                  "is_private": false
                }
              },
              {
                "title": "Private memo",
                "type": "object",
                "description": "Private memo — only the owner can see this. Returned when `is_private: true`. Other Simkl users hitting the owner's profile won't see the `text`.",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The memo body. Plain text. Hidden from other users.",
                    "example": "Remember to email Mom about ep 7 before she watches it."
                  },
                  "is_private": {
                    "type": "boolean",
                    "description": "`true` for the private branch — only the owner sees this memo.",
                    "enum": [
                      true
                    ],
                    "example": true
                  }
                },
                "required": [
                  "text",
                  "is_private"
                ],
                "example": {
                  "text": "Remember to email Mom about ep 7 before she watches it.",
                  "is_private": true
                }
              },
              {
                "title": "No memo set",
                "type": "object",
                "description": "Empty object `{}` — returned when the user has not set a memo on this item. The key is still present in the response so client code can check `memo` without a guard.",
                "additionalProperties": false,
                "example": {}
              }
            ],
            "description": "Present only with `memos=yes`. The user's per-item memo, or an empty object `{}` when no memo is set. See [`POST /sync/history`](/api-reference/simkl/add-to-history) for setting memos."
          },
          "next_to_watch_info": {
            "type": "object",
            "description": "Present only with `next_watch_info=yes` AND `status: watching` AND there is a next episode to watch.",
            "properties": {
              "title": {
                "type": "string",
                "example": "How the West Was 1010001"
              },
              "season": {
                "type": "integer",
                "description": "Omitted for anime entries."
              },
              "episode": {
                "type": "integer"
              },
              "date": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "Type 4 null — release date not on file for the next episode. Format is ISO-8601 with timezone offset. See [Null and missing values](/conventions/null-values)."
              }
            }
          },
          "seasons": {
            "type": "array",
            "description": "Per-season breakdown. Present only with `extended=full` (or `extended=full_anime_seasons`) AND the item is `watching` (or `include_all_episodes=yes` for `completed`/`dropped`).",
            "items": {
              "type": "object",
              "properties": {
                "number": {
                  "type": "integer"
                },
                "episodes": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "number": {
                        "type": "integer"
                      },
                      "watched_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "Per-episode watch timestamp. Present only with `episode_watched_at=yes`."
                      },
                      "tvdb": {
                        "type": "object",
                        "description": "Present only with `extended=full_anime_seasons` on anime entries.",
                        "properties": {
                          "season": {
                            "type": "integer"
                          },
                          "episode": {
                            "type": "integer"
                          }
                        }
                      },
                      "ids": {
                        "type": "object",
                        "description": "Present only with `episode_tvdb_id=yes`.",
                        "properties": {
                          "tvdb_id": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "is_rewatch": {
            "type": "boolean",
            "description": "Present only with `allow_rewatch=yes`. `true` on synthesized rewatch-session entries; `false` on the canonical entry. See the [Rewatches guide](/guides/rewatches). Simkl Pro / VIP feature."
          },
          "rewatch_id": {
            "type": "integer",
            "description": "Present only on rewatch entries (`is_rewatch: true`)."
          },
          "rewatch_status": {
            "type": "string",
            "enum": [
              "active",
              "completed",
              "closed"
            ],
            "description": "Present only on rewatch entries."
          }
        },
        "additionalProperties": true
      },
      "AllItemsResponse": {
        "type": "object",
        "description": "Top-level dict keyed by `shows`, `movies`, and `anime`. Each key is an array of `AllItemsEntry` objects. **Keys are present only when there's at least one item in that bucket** — an empty library returns `{}`; a library with only movies returns `{ movies: [...] }` with no `shows` or `anime` keys.",
        "properties": {
          "shows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AllItemsEntry"
            }
          },
          "movies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AllItemsEntry"
            }
          },
          "anime": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AllItemsEntry"
            }
          }
        }
      },
      "SearchByTextIds": {
        "type": "object",
        "description": "ID block returned on every search result item. `simkl_id` and `slug` are always present; `tmdb` is only present when a TMDB link record exists for the title.",
        "properties": {
          "simkl_id": {
            "type": "integer",
            "description": "Canonical Simkl ID for the title."
          },
          "slug": {
            "type": "string",
            "description": "URL slug parsed from the simkl.com canonical URL (everything after the last `/`). Response-only — never send on requests."
          },
          "tmdb": {
            "type": "string",
            "description": "TMDB ID, when a link record exists. For TV/anime this is the TMDB TV ID; for movies it's the TMDB movie ID."
          }
        },
        "required": [
          "simkl_id",
          "slug"
        ]
      },
      "SearchByTextMovieItem": {
        "title": "Movie result",
        "type": "object",
        "description": "One movie search result. `endpoint_type` is the constant `\"movies\"` (plural even though the path is `/search/movie`). Extended fields (`all_titles`, `url`, `rank`, `ratings`) only appear when the call includes `extended=full`.",
        "properties": {
          "title": {
            "type": "string"
          },
          "year": {
            "type": "integer"
          },
          "endpoint_type": {
            "type": "string",
            "enum": [
              "movies"
            ],
            "description": "Constant for movie search results."
          },
          "poster": {
            "type": [
              "string",
              "null"
            ],
            "description": "Image path fragment. Combine with the prefixes in [Image conventions](/conventions/images) — for example `https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`. **Type 4 null** — `null` when no poster image is on file. See [Null and missing values](/conventions/null-values)."
          },
          "ids": {
            "$ref": "#/components/schemas/SearchByTextIds"
          },
          "all_titles": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Aliases / localized variants. Extended mode only, and only when the catalog has more than one title."
          },
          "url": {
            "type": "string",
            "description": "Relative simkl.com URL. Extended mode only."
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Simkl popularity rank. **Type 4 null** — `null` when the item is not yet ranked or the catalog sentinel value (≥ 999999) is present. See [Null and missing values](/conventions/null-values)."
          },
          "ratings": {
            "type": "object",
            "description": "External-source ratings block. Each sub-key is present only when the corresponding rating record exists.",
            "properties": {
              "simkl": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "imdb": {
                "$ref": "#/components/schemas/ExternalRating"
              }
            }
          }
        },
        "required": [
          "title",
          "year",
          "endpoint_type",
          "poster",
          "ids"
        ]
      },
      "SearchByTextTVItem": {
        "title": "TV result",
        "type": "object",
        "description": "One TV search result. `endpoint_type` is the constant `\"tv\"`. Extended fields (`url`, `ep_count`, `rank`, `status`, `ratings`) only appear when the call includes `extended=full`.",
        "properties": {
          "title": {
            "type": "string"
          },
          "year": {
            "type": "integer"
          },
          "endpoint_type": {
            "type": "string",
            "enum": [
              "tv"
            ],
            "description": "Constant for TV search results."
          },
          "poster": {
            "type": [
              "string",
              "null"
            ],
            "description": "Image path fragment. Combine with the prefixes in [Image conventions](/conventions/images) — for example `https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`. **Type 4 null** — `null` when no poster image is on file. See [Null and missing values](/conventions/null-values)."
          },
          "ids": {
            "$ref": "#/components/schemas/SearchByTextIds"
          },
          "url": {
            "type": "string",
            "description": "Relative simkl.com URL. Extended mode only."
          },
          "ep_count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Total episode count. **Type 4 null** — `null` when no count is on file yet. See [Null and missing values](/conventions/null-values)."
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Simkl popularity rank. **Type 4 null** — `null` when the item is not yet ranked or the catalog sentinel value (≥ 999999) is present. See [Null and missing values](/conventions/null-values)."
          },
          "status": {
            "type": "string",
            "enum": [
              "tba",
              "ended",
              "airing"
            ],
            "description": "Airing status (extended mode only)."
          },
          "ratings": {
            "type": "object",
            "description": "External-source ratings block. Each sub-key is present only when the corresponding rating record exists.",
            "properties": {
              "simkl": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "imdb": {
                "$ref": "#/components/schemas/ExternalRating"
              }
            }
          }
        },
        "required": [
          "title",
          "year",
          "endpoint_type",
          "poster",
          "ids"
        ]
      },
      "SearchByTextAnimeItem": {
        "title": "Anime result",
        "type": "object",
        "description": "One anime search result. `endpoint_type` is the constant `\"anime\"`. `title_romaji` and `type` are always present on anime items; `title_en` is only present when an English-localized title is on file. Extended fields (`all_titles`, `url`, `ep_count`, `rank`, `status`, `ratings`) only appear when the call includes `extended=full`.",
        "properties": {
          "title": {
            "type": "string"
          },
          "title_en": {
            "type": "string",
            "description": "English-localized title. Optional even on anime — only present when one is on file."
          },
          "title_romaji": {
            "type": "string",
            "description": "Romaji title slot — currently mirrors `title` for every anime item. Always present on anime results."
          },
          "year": {
            "type": "integer"
          },
          "endpoint_type": {
            "type": "string",
            "enum": [
              "anime"
            ],
            "description": "Constant for anime search results."
          },
          "type": {
            "type": "string",
            "enum": [
              "tv",
              "movie",
              "ova",
              "ona",
              "special",
              "music"
            ],
            "description": "Anime catalog type. Always lowercase."
          },
          "poster": {
            "type": [
              "string",
              "null"
            ],
            "description": "Image path fragment. Combine with the prefixes in [Image conventions](/conventions/images) — for example `https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`. **Type 4 null** — `null` when no poster image is on file. See [Null and missing values](/conventions/null-values)."
          },
          "ids": {
            "$ref": "#/components/schemas/SearchByTextIds"
          },
          "all_titles": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Aliases / localized variants. Extended mode only, and only when the catalog has more than one title."
          },
          "url": {
            "type": "string",
            "description": "Relative simkl.com URL. Extended mode only."
          },
          "ep_count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Total episode count. **Type 4 null** — `null` when no count is on file yet. See [Null and missing values](/conventions/null-values)."
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Simkl popularity rank. **Type 4 null** — `null` when the item is not yet ranked or the catalog sentinel value (≥ 999999) is present. See [Null and missing values](/conventions/null-values)."
          },
          "status": {
            "type": "string",
            "enum": [
              "tba",
              "ended",
              "airing"
            ],
            "description": "Airing status (extended mode only)."
          },
          "ratings": {
            "type": "object",
            "description": "External-source ratings block. Each sub-key is present only when the corresponding rating record exists. `mal` carries an extra `rank` field — see RankedExternalRating.",
            "properties": {
              "simkl": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "imdb": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "mal": {
                "$ref": "#/components/schemas/RankedExternalRating"
              }
            }
          }
        },
        "required": [
          "title",
          "title_romaji",
          "year",
          "endpoint_type",
          "type",
          "poster",
          "ids"
        ]
      },
      "SearchByFileEpisodeIds": {
        "type": "object",
        "description": "Episode IDs — just the Simkl episode ID. Cross-source IDs sit on the parent show.",
        "properties": {
          "simkl": {
            "type": "integer",
            "description": "Simkl episode ID. Use with `/tv/episodes/{id}` or `/anime/episodes/{id}`."
          }
        },
        "required": [
          "simkl"
        ]
      },
      "SearchByFileShowIds": {
        "type": "object",
        "additionalProperties": true,
        "description": "Show / movie IDs returned by Simkl's link database. `simkl` is always present; other keys appear when a link record exists. Common keys: `imdb`, `tmdb`/`tmdbtv`, `tvdb`/`tvdbslug`, `trakttvslug`/`traktmslug`, plus anime-specific `mal`, `anidb`, `anilist`, `kitsu`, `crunchyroll`, `animeplanet`, `anisearch`, `livechart`. Movies also see `letterslug` (Letterboxd), `tvdbm`/`tvdbmslug`, `boxd`, `moviedb`. See [Supported ID keys](/conventions/standard-media-objects#supported-id-keys).",
        "properties": {
          "simkl": {
            "type": "integer",
            "description": "Canonical Simkl ID."
          }
        },
        "required": [
          "simkl"
        ]
      },
      "SearchByFileEpisodeBlock": {
        "type": "object",
        "description": "Matched episode metadata. Present only on `type: \"episode\"` responses.",
        "properties": {
          "title": {
            "type": "string",
            "description": "Episode title."
          },
          "season": {
            "type": "integer",
            "description": "Season number."
          },
          "episode": {
            "type": "integer",
            "description": "Episode number within the season."
          },
          "multipart": {
            "type": "boolean",
            "description": "`true` when the input filename was multi-part and `part > 1` selected this episode."
          },
          "ids": {
            "$ref": "#/components/schemas/SearchByFileEpisodeIds"
          }
        },
        "required": [
          "title",
          "season",
          "episode",
          "multipart",
          "ids"
        ]
      },
      "SearchByFileShowBlock": {
        "type": "object",
        "description": "Show metadata (TV or anime).",
        "properties": {
          "title": {
            "type": "string"
          },
          "year": {
            "type": "integer"
          },
          "ids": {
            "$ref": "#/components/schemas/SearchByFileShowIds"
          }
        },
        "required": [
          "title",
          "year",
          "ids"
        ]
      },
      "SearchByFileMovieBlock": {
        "type": "object",
        "description": "Movie metadata.",
        "properties": {
          "title": {
            "type": "string"
          },
          "year": {
            "type": "integer"
          },
          "ids": {
            "$ref": "#/components/schemas/SearchByFileShowIds"
          }
        },
        "required": [
          "title",
          "year",
          "ids"
        ]
      },
      "SearchByFileEpisodeMatch": {
        "title": "Episode match",
        "type": "object",
        "description": "Filename matched a TV/anime episode. Carries both the show (parent) and the specific matched episode.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "episode"
            ],
            "description": "Discriminator — pinned to `\"episode\"` for this variant."
          },
          "episode": {
            "$ref": "#/components/schemas/SearchByFileEpisodeBlock"
          },
          "show": {
            "$ref": "#/components/schemas/SearchByFileShowBlock"
          }
        },
        "required": [
          "type",
          "episode",
          "show"
        ]
      },
      "SearchByFileShowMatch": {
        "title": "Show match",
        "type": "object",
        "description": "Filename matched a show but no specific episode could be identified (rare — usually parser confidence dropped).",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "show"
            ],
            "description": "Discriminator — pinned to `\"show\"` for this variant."
          },
          "show": {
            "$ref": "#/components/schemas/SearchByFileShowBlock"
          }
        },
        "required": [
          "type",
          "show"
        ]
      },
      "SearchByFileMovieMatch": {
        "title": "Movie match",
        "type": "object",
        "description": "Filename matched a movie.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "movie"
            ],
            "description": "Discriminator — pinned to `\"movie\"` for this variant."
          },
          "movie": {
            "$ref": "#/components/schemas/SearchByFileMovieBlock"
          }
        },
        "required": [
          "type",
          "movie"
        ]
      },
      "SearchRandomItem": {
        "title": "Single item (no limit)",
        "type": "object",
        "description": "Single random item — returned when `limit` is omitted. Service-specific keys (`{service}_id`, `{service}_url`) are included when `service != simkl` AND the matched title has a link record for that service.",
        "additionalProperties": true,
        "properties": {
          "simkl_id": {
            "type": "integer",
            "description": "Simkl ID of the random title."
          },
          "simkl_url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical Simkl URL (with slug)."
          },
          "netflix_id": {
            "type": "string",
            "description": "Netflix title ID — present when `service=netflix` and the title has a Netflix link."
          },
          "netflix_url": {
            "type": "string",
            "format": "uri",
            "description": "Netflix watch URL — present when `service=netflix` and link exists."
          },
          "crunchy_id": {
            "type": "string",
            "description": "Crunchyroll slug — present when `service=crunchy` and link exists."
          },
          "crunchy_url": {
            "type": "string",
            "format": "uri",
            "description": "Crunchyroll watch URL — present when `service=crunchy` and link exists."
          },
          "hulu_id": {
            "type": "string",
            "description": "Hulu title ID — present when `service=hulu` and link exists."
          },
          "hulu_url": {
            "type": "string",
            "format": "uri",
            "description": "Hulu watch URL — present when `service=hulu` and link exists."
          }
        },
        "required": [
          "simkl_id",
          "simkl_url"
        ]
      },
      "SearchRandomItemArray": {
        "title": "Array of items (limit set)",
        "type": "array",
        "description": "Array form — returned when `limit` is set. Capped server-side at 50.",
        "items": {
          "$ref": "#/components/schemas/SearchRandomItem"
        }
      },
      "SearchRandomNotFound": {
        "title": "No matches",
        "type": "object",
        "description": "Returned (status 200) when no item matches the supplied filters.",
        "properties": {
          "error": {
            "type": "string",
            "enum": [
              "not_found"
            ],
            "description": "Constant `\"not_found\"`."
          }
        },
        "required": [
          "error"
        ]
      },
      "ChangesResponse": {
        "title": "Changes response",
        "type": "object",
        "description": "Catalog IDs that changed in the requested window, grouped by type. Each key is OPTIONAL — keys whose bucket is empty are omitted entirely. An all-empty response is `{}`.",
        "additionalProperties": false,
        "properties": {
          "movies": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Simkl IDs of movies whose metadata changed in the window."
          },
          "shows": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Simkl IDs of TV shows whose metadata changed in the window."
          },
          "anime": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Simkl IDs of anime whose metadata changed in the window."
          }
        }
      },
      "GenresItem": {
        "title": "Discover entry",
        "type": "object",
        "description": "A single entry from any of the genre-filter endpoints (/movies/genres/*, /tv/genres/*, /anime/genres/*). All three share this shape via the same server-side handler. Per-type variations: anime items carry `anime_type`; movie items carry `ids.tmdb`.",
        "properties": {
          "title": {
            "type": "string",
            "description": "Display title."
          },
          "year": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Premiere year (from the release date). **Type 4 null** when the catalog has no release date on file. See [Null and missing values](/conventions/null-values#type-4)."
          },
          "date": {
            "type": [
              "string",
              "null"
            ],
            "description": "Release / first-air timestamp with the catalog's timezone offset (e.g. `2014-11-05T00:00:00-05:00` for US releases, `+09:00` for anime). **Type 4 null** when no release date is on file. See [Null and missing values](/conventions/null-values#type-4)."
          },
          "url": {
            "type": "string",
            "description": "Relative simkl.com path with slug. Prepend `https://simkl.com` to deep-link. Each catalog uses its own prefix: `/movies/{simkl_id}/{slug}` for movies, `/tv/{simkl_id}/{slug}` for TV, `/anime/{simkl_id}/{slug}` for anime.",
            "example": "/movies/430306/avengers-endgame"
          },
          "poster": {
            "type": [
              "string",
              "null"
            ],
            "description": "Image path fragment. Combine with the prefixes in [Image conventions](/conventions/images) — for example `https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`. **Type 4 null** when no poster on file. See [Null and missing values](/conventions/null-values#type-4)."
          },
          "fanart": {
            "type": [
              "string",
              "null"
            ],
            "description": "Image path fragment for fanart. Combine with the prefixes in [Image conventions](/conventions/images) — for example `https://wsrv.nl/?url=https://simkl.in/fanart/{fanart}_medium.webp&q=90`. **Type 4 null** when no fanart on file. See [Null and missing values](/conventions/null-values#type-4)."
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Simkl popularity rank. **Type 4 null** when the item is not yet ranked or the catalog sentinel value (>= 999999) is present. See [Null and missing values](/conventions/null-values#type-4)."
          },
          "ratings": {
            "type": "object",
            "description": "Aggregate ratings. Always carries `simkl`. TV / movies additionally carry `imdb`; anime carries `mal` instead.",
            "properties": {
              "simkl": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "imdb": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "mal": {
                "$ref": "#/components/schemas/ExternalRating"
              }
            }
          },
          "ids": {
            "type": "object",
            "description": "Identifier block. `simkl_id` + `slug` are always present. `tmdb` appears on movie items (the discover query requires a TMDB-linked record — items without one are filtered out).",
            "additionalProperties": true,
            "properties": {
              "simkl_id": {
                "type": "integer"
              },
              "slug": {
                "type": "string"
              },
              "tmdb": {
                "type": "string",
                "description": "Movie items only."
              }
            },
            "required": [
              "simkl_id",
              "slug"
            ]
          },
          "anime_type": {
            "type": "string",
            "enum": [
              "tv",
              "movie",
              "ova",
              "ona",
              "special",
              "music"
            ],
            "description": "**Anime items only.** Catalog format."
          }
        },
        "required": [
          "title",
          "url",
          "ids"
        ]
      },
      "GenresResponse": {
        "title": "Discover response",
        "oneOf": [
          {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GenresItem"
            },
            "title": "Array of items"
          },
          {
            "type": "null",
            "title": "No match",
            "description": "Returned (status 200) when a path segment matches no records — most commonly an unknown `genre` slug."
          }
        ]
      },
      "BestItem": {
        "title": "Best-of item",
        "type": "object",
        "description": "One entry from `/tv/best/{filter}` or `/anime/best/{filter}`. All filters share the base shape. The `votes` field is only there when `filter=voted`; the `watched` field is only there when `filter=watched`.",
        "properties": {
          "title": {
            "type": "string",
            "description": "Display title."
          },
          "year": {
            "type": "integer",
            "description": "Premiere year."
          },
          "poster": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — no poster on file. See [Null and missing values](/conventions/null-values#type-4). When present, it's an image path fragment — build the full URL using the patterns in [Image conventions](/conventions/images) (e.g. `https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`)."
          },
          "url": {
            "type": "string",
            "description": "simkl.com URL relative to the root, with the slug appended.",
            "example": "/tv/11121/breaking-bad"
          },
          "ids": {
            "type": "object",
            "description": "`simkl_id` and `slug` are always present.",
            "properties": {
              "simkl_id": {
                "type": "integer"
              },
              "slug": {
                "type": "string"
              }
            },
            "required": [
              "simkl_id",
              "slug"
            ]
          },
          "ratings": {
            "type": "object",
            "description": "Aggregate ratings. Always carries `simkl`. TV items carry `imdb`; anime items carry `mal` (the other key isn't present at all).",
            "properties": {
              "simkl": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "imdb": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "mal": {
                "$ref": "#/components/schemas/ExternalRating"
              }
            }
          },
          "votes": {
            "type": "integer",
            "description": "Total IMDB / MAL vote count (whichever applies). Only present when you call with `filter=voted` — absent from items on other filters."
          },
          "watched": {
            "type": "integer",
            "description": "Number of Simkl users who watched this title this month. Only present when you call with `filter=watched` — absent from items on other filters."
          }
        },
        "required": [
          "title",
          "year",
          "url",
          "ids",
          "ratings"
        ]
      },
      "BestResponse": {
        "title": "Best-of response",
        "oneOf": [
          {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BestItem"
            },
            "title": "Array of items"
          },
          {
            "type": "null",
            "title": "No match",
            "description": "Returned (status 200) when a `?type=` filter narrows the top 60 results to zero matches — most commonly `/tv/best/all?type=documentary`."
          }
        ]
      },
      "PremieresNewItem": {
        "title": "Item from ?param=new (with rank + ratings)",
        "type": "object",
        "description": "Items returned when you call `/tv/premieres/new` or `/anime/premieres/new`. Includes `rank` and `ratings` on top of the base fields. Anime items also carry `anime_type`.",
        "properties": {
          "title": {
            "type": "string",
            "description": "Display title."
          },
          "year": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Type 4 null — release date isn't known yet. See [Null and missing values](/conventions/null-values#type-4). Otherwise the premiere year as an integer."
          },
          "date": {
            "type": "string",
            "description": "Release date as an ISO-8601 timestamp with timezone offset. TV uses `-05:00`, anime uses `+09:00` (Japan time).",
            "example": "2026-05-18T00:00:00-05:00"
          },
          "url": {
            "type": "string",
            "description": "simkl.com URL relative to the root, with the slug appended. Non-ASCII characters in the slug come URL-encoded — don't encode them a second time.",
            "example": "/tv/2750099/you%E2%80%99re-killing-me"
          },
          "poster": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — no poster on file. See [Null and missing values](/conventions/null-values#type-4). When present, it's an image path fragment — build the full URL using the patterns in [Image conventions](/conventions/images) (e.g. `https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`)."
          },
          "ids": {
            "type": "object",
            "description": "`simkl_id` and `slug` are always present.",
            "properties": {
              "simkl_id": {
                "type": "integer"
              },
              "slug": {
                "type": "string"
              }
            },
            "required": [
              "simkl_id",
              "slug"
            ]
          },
          "anime_type": {
            "type": "string",
            "enum": [
              "tv",
              "movie",
              "ova",
              "ona",
              "special",
              "music"
            ],
            "description": "Anime catalog items only. Catalog format."
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Type 4 null — title isn't ranked yet. See [Null and missing values](/conventions/null-values#type-4). When present, the Simkl popularity rank (lower is more popular)."
          },
          "ratings": {
            "type": "object",
            "description": "Aggregate ratings. Always carries `simkl`. TV items carry `imdb`; anime items carry `mal`.",
            "properties": {
              "simkl": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "imdb": {
                "$ref": "#/components/schemas/ExternalRating"
              },
              "mal": {
                "$ref": "#/components/schemas/ExternalRating"
              }
            }
          }
        },
        "required": [
          "title",
          "url",
          "ids",
          "date"
        ]
      },
      "PremieresSoonItem": {
        "title": "Item from ?param=soon (no rank or ratings)",
        "type": "object",
        "description": "Items returned when you call `/tv/premieres/soon` (or any path value other than `new`), or the anime equivalent. These titles haven't aired yet — the `rank` and `ratings` fields are absent entirely (not just `null`). Anime items carry `anime_type`.",
        "properties": {
          "title": {
            "type": "string",
            "description": "Display title."
          },
          "year": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Type 4 null — release date isn't known yet. See [Null and missing values](/conventions/null-values#type-4). Otherwise the premiere year as an integer."
          },
          "date": {
            "type": "string",
            "description": "Release date as an ISO-8601 timestamp with timezone offset. TV uses `-05:00`, anime uses `+09:00` (Japan time).",
            "example": "2026-05-18T00:00:00-05:00"
          },
          "url": {
            "type": "string",
            "description": "simkl.com URL relative to the root, with the slug appended. Non-ASCII characters in the slug come URL-encoded — don't encode them a second time.",
            "example": "/tv/2750099/you%E2%80%99re-killing-me"
          },
          "poster": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type 4 null — no poster on file. See [Null and missing values](/conventions/null-values#type-4). When present, it's an image path fragment — build the full URL using the patterns in [Image conventions](/conventions/images) (e.g. `https://wsrv.nl/?url=https://simkl.in/posters/{poster}_m.webp&q=90`)."
          },
          "ids": {
            "type": "object",
            "description": "`simkl_id` and `slug` are always present.",
            "properties": {
              "simkl_id": {
                "type": "integer"
              },
              "slug": {
                "type": "string"
              }
            },
            "required": [
              "simkl_id",
              "slug"
            ]
          },
          "anime_type": {
            "type": "string",
            "enum": [
              "tv",
              "movie",
              "ova",
              "ona",
              "special",
              "music"
            ],
            "description": "Anime catalog items only. Catalog format."
          }
        },
        "required": [
          "title",
          "url",
          "ids",
          "date"
        ]
      },
      "PremieresResponse": {
        "title": "Premieres response",
        "oneOf": [
          {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PremieresNewItem"
            },
            "title": "Items for ?param=new (with rank + ratings)"
          },
          {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PremieresSoonItem"
            },
            "title": "Items for ?param=soon (no rank or ratings)"
          }
        ]
      }
    },
    "securitySchemes": {
      "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"
      },
      "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"
      }
    },
    "parameters": {
      "PageParam": {
        "name": "page",
        "in": "query",
        "required": false,
        "description": "Page number for paginated endpoints (1-based).",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1,
          "maximum": 20
        }
      },
      "LimitParam": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Number of results per page.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 10,
          "maximum": 60
        }
      },
      "LimitGenresParam": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 60,
          "default": 60
        },
        "description": "Items per page. Capped at 60."
      },
      "SyncTypePathParam": {
        "name": "type",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "enum": [
            "shows",
            "movies",
            "anime"
          ]
        },
        "description": "Library type."
      },
      "DateFromParam": {
        "name": "date_from",
        "in": "query",
        "required": false,
        "description": "ISO-8601 timestamp. Returns only items updated since this time. Use the value saved from `/sync/activities`.",
        "schema": {
          "type": "string",
          "format": "date-time"
        },
        "example": "2024-05-01T12:00:00Z"
      },
      "ExtendedParam": {
        "name": "extended",
        "in": "query",
        "required": false,
        "description": "Comma-separated list of extra fields to include in the response. See [Extended info](/conventions/extended-info).",
        "schema": {
          "type": "string"
        },
        "examples": {
          "minimal": {
            "value": "simple",
            "summary": "Minimal payload"
          },
          "full": {
            "value": "full",
            "summary": "Everything Simkl has"
          },
          "with-overview": {
            "value": "overview,genres,theater",
            "summary": "Selective Discover fields"
          }
        }
      },
      "ClientCountryParam": {
        "name": "user-country",
        "in": "query",
        "required": false,
        "description": "ISO country code. Required when `extended=theater` to know which release date applies.",
        "schema": {
          "type": "string",
          "example": "us",
          "pattern": "^[a-zA-Z]{2}$"
        }
      },
      "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"
      },
      "ExtendedFullQuery": {
        "name": "extended",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "full"
          ]
        },
        "example": "full",
        "description": "Set to `full` to receive the full metadata record (overview, genres, ratings, trailers, external IDs, etc.). When omitted you get a minimal title/year/IDs response. See [Extended info](/conventions/extended-info)."
      },
      "AllowRewatchQuery": {
        "name": "allow_rewatch",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "yes",
            "no"
          ],
          "default": "no"
        },
        "example": "yes",
        "description": "Opt into rewatch tracking. When `yes`, `POST /sync/history` records an additional rewatch session instead of being a no-op for already-watched items, and `GET /sync/all-items` returns one extra entry per saved rewatch session alongside the item's normal entry. Available to Simkl **Pro** and **VIP** users — non-Pro callers see no effect even with the flag set.\n\n⚠️ **Do not enable this flag until you've read the [Rewatches guide](/guides/rewatches) end-to-end and implemented the precautions.** Used carelessly (on retries, on every scrobble event, on importer re-runs, without pinning `rewatch_id` after the first write), it will pollute the user's history stats and rewatches panel with phantom sessions. The flag should be gated behind explicit user intent — a dedicated \"Rewatch\" button — never on background or automated flows. Also expose a per-user *Track rewatches* toggle in your app's settings (default off) — not every user wants the rewatch-session complexity.\n\nLimits: up to **50 rewatches per item** (movie, show, or anime), and any two watch events on the **same item** (movie or episode) must be at least **2 days apart** — a new rewatch within 48 hours of the previous watch of that same item collapses into the same session (it's a rewatch, not a rewind 😄). Full walkthrough — session lifecycle (`active` / `completed` / `closed` with bidirectional transitions), episode-level tracking, reading sessions back from `GET /sync/all-items`, and ready-made code for simkl.com-style UI patterns — in the [Rewatches guide](/guides/rewatches)."
      },
      "AllItemsExtendedQuery": {
        "name": "extended",
        "in": "query",
        "description": "Controls response richness. Omit for the default (summary fields only — status, counters, `last_watched` / `next_to_watch` markers, no episode arrays).\n\n- `simkl_ids_only` — smallest payload: just `ids.simkl` per item. Ideal for the deletion-reconciliation diff in continuous sync.\n- `ids_only` — same, plus external IDs (`imdb`, `tmdb`, `tvdb`, `mal`, …).\n- `full` — **required to get the per-episode `seasons[].episodes[]` arrays**; without it, `episode_watched_at` and `include_all_episodes` do nothing. Necessary but not always sufficient: on its own it loads episodes for `watching` / `hold` / `plantowatch` items only — `completed` and `dropped` additionally need `include_all_episodes`. The only extra *metadata* field it adds is `runtime`.\n- `full_anime_seasons` — like `full`, plus TVDB season/episode mapping on anime (`mapped_tvdb_seasons` at the show level, a `tvdb` block per episode).\n\n**This endpoint does not return `overview`, `fanart`, `genres`, or `ratings` at any `extended` value** — it returns watch state plus a compact item stub (`title`, `poster`, `year`, `ids`, and `runtime` on `full`). For catalog metadata, call the detail endpoints ([`/movies/{id}`](/api-reference/simkl/get-movie), [`/tv/{id}`](/api-reference/simkl/get-tv-show), [`/anime/{id}`](/api-reference/simkl/get-anime)).\n\nLarge payload on `full` / `full_anime_seasons` — pair with `date_from` for continuous sync. The one expected full-library use is a one-time episode baseline on first sync (see the [Sync guide → Phase 1](/guides/sync#phase-1-initial-sync)).",
        "schema": {
          "type": "string",
          "enum": [
            "full",
            "full_anime_seasons",
            "simkl_ids_only",
            "ids_only"
          ]
        },
        "example": "full"
      },
      "AllItemsNextWatchInfoQuery": {
        "name": "next_watch_info",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "yes"
          ]
        },
        "description": "When `yes`, attaches a `next_to_watch_info` object to each watched item, indicating the next episode to watch."
      },
      "AllItemsEpisodeTvdbIdQuery": {
        "name": "episode_tvdb_id",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "yes"
          ]
        },
        "description": "When `yes`, includes TVDB IDs on each episode in episode-bearing responses."
      },
      "AllItemsLanguageQuery": {
        "name": "language",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "en"
          ]
        },
        "example": "en",
        "description": "`en` forces English titles. It's the only accepted value — any other value is ignored and titles fall back to the user's profile language."
      },
      "AllItemsAnimeTypeQuery": {
        "name": "anime_type",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "movies"
          ]
        },
        "description": "When `movies`, restricts the `anime` results to anime-movie subtype only."
      },
      "AllItemsEpisodeWatchedAtQuery": {
        "name": "episode_watched_at",
        "in": "query",
        "description": "`yes` adds per-episode `watched_at` timestamps to every loaded episode. **Requires `extended=full`** (or `extended=full_anime_seasons`) — it's a modifier on already-loaded episodes, so on its own it does nothing. To also cover `completed` / `dropped` items, combine with `include_all_episodes` (which itself also requires `extended=full`). Pair with `date_from` for continuous sync — significantly larger response.",
        "schema": {
          "type": "string",
          "const": "yes"
        },
        "example": "yes"
      },
      "AllItemsIncludeAllEpisodesQuery": {
        "name": "include_all_episodes",
        "in": "query",
        "description": "Three-value flag that controls per-episode loading on canonical entries. **Requires `extended=full`** — it has no effect on its own.\n\n- `no` *(default)* — Episode lists are loaded only for items in `watching`, `plantowatch`, and `hold` statuses. Items in `completed` and `dropped` skip episode loading entirely (you get only `watched_episodes_count`).\n- `yes` — Load episode lists for **every** status. For completed entries with no per-episode data recorded, synthesizes virtual episode rows stamped with the item's last-watched time (the same timestamp is shared across all synthesized rows). Complete coverage, approximate dates.\n- `original` — Load episode lists for every status, but **skip** virtual-episode synthesis. Completed entries get only their real recorded rows with real dates — which can be **fewer** than `watched_episodes_count` for an item the user marked complete in a single action. Treat the count as authoritative for how many episodes are watched, and the rows for which ones and when.\n\nIndependent of `allow_rewatch=yes` — combine the two when you need both canonical episode lists AND rewatch session episode lists in one response. Pair with `date_from` for continuous sync since the response can be much larger when episodes load for completed-bucket items.",
        "schema": {
          "type": "string",
          "enum": [
            "yes",
            "original",
            "no"
          ],
          "default": "no"
        },
        "example": "yes"
      },
      "AllItemsMemosQuery": {
        "name": "memos",
        "in": "query",
        "description": "`yes` includes the user's per-item `memo` object (`text` capped at 140 chars, plus `is_private`) in addition to all other data. Field name is singular `memo`; empty memos render as `{}`.",
        "schema": {
          "type": "string",
          "const": "yes"
        },
        "example": "yes"
      },
      "AllItemsTypeQuery": {
        "name": "type",
        "in": "path",
        "description": "One of `shows`, `movies`, `anime`, or `all`. Pass `all` to skip filtering on type even when the runtime accepts the segment-less form, so for spec strictness this is `true`. To call without it in practice, just drop the segment from the URL.",
        "schema": {
          "type": "string",
          "enum": [
            "movies",
            "shows",
            "anime",
            "all"
          ],
          "example": "all"
        },
        "example": "anime",
        "required": true
      },
      "AllItemsStatusQuery": {
        "name": "status",
        "in": "path",
        "description": "One of `watching`, `plantowatch`, `hold`, `completed`, `dropped`, or `all`. Movies accept only `plantowatch`, `completed`, `dropped`, and `all`; TV and anime accept all six. Pass `all` to skip filtering on status — `/sync/all-items/{type}/all` returns every status for that type.",
        "schema": {
          "$ref": "#/components/schemas/WatchlistStatus",
          "enum": [
            "watching",
            "plantowatch",
            "hold",
            "completed",
            "dropped",
            "all"
          ],
          "example": "all"
        },
        "example": "completed",
        "required": true
      },
      "PlaybackLimitQuery": {
        "name": "limit",
        "in": "query",
        "description": "Slice your result to the first N items. Default: 10000",
        "schema": {
          "type": "number"
        }
      },
      "PlaybackHideWatchedQuery": {
        "name": "hide_watched",
        "in": "query",
        "schema": {
          "type": "string",
          "enum": [
            "true",
            "false"
          ],
          "default": "true"
        },
        "description": "When `true`, hides items already watched after the pause was created."
      },
      "PlaybackDateFromQuery": {
        "name": "date_from",
        "in": "query",
        "description": "Filter sessions from this date",
        "schema": {
          "type": "string"
        }
      },
      "PlaybackDateToQuery": {
        "name": "date_to",
        "in": "query",
        "description": "Filter sessions until this date",
        "schema": {
          "type": "string"
        }
      },
      "PlaybackTypeQuery": {
        "name": "type",
        "in": "path",
        "description": "`episodes` or `movies` to filter by item type. To get all paused playbacks of both kinds, call `GET /sync/playback`. Strictness; drop the segment from the URL to call without it.",
        "schema": {
          "type": "string",
          "enum": [
            "movies",
            "episodes"
          ]
        },
        "example": "movies",
        "required": true
      },
      "UserRatingsTypeQuery": {
        "name": "type",
        "in": "path",
        "description": "Which media type to return ratings for. Unrecognized values are silently ignored (no `400`) and you'll get cross-type results back — see the description's \"Silent fallbacks\" table.",
        "schema": {
          "type": "string",
          "enum": [
            "movies",
            "shows",
            "anime"
          ]
        },
        "example": "anime",
        "required": true
      },
      "UserRatingsRatingQuery": {
        "name": "rating",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^(10|[1-9])(,(10|[1-9]))*$"
        },
        "description": "Which rating bucket(s) to return. Accepted forms:\n\n- A single value `1`–`10` (e.g. `9`).\n- A comma-separated list (e.g. `8,9,10`).\n- To get **every rated item** of this type, pass the full list: `1,2,3,4,5,6,7,8,9,10`. This is the only way to scope the response to actually-rated items — omitting the segment or passing a non-digit value (like `all`) returns the user's entire library for that type, including unrated rows with `user_rating: null`.\n\nValues outside `1`–`10` are accepted by the URL parser but never match a real rating, so you'll just get an empty response.",
        "example": "8,9,10"
      },
      "BestFilterParam": {
        "name": "filter",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "enum": [
            "month",
            "all",
            "year",
            "voted",
            "watched"
          ]
        },
        "example": "all",
        "description": "Which top-rated bucket to return. Unknown values fall back to `all`."
      },
      "BestTVTypeParam": {
        "name": "type",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "series",
            "documentary",
            "entertainment",
            "animation"
          ]
        },
        "example": "series",
        "description": "Optional. Narrow by show type. Unknown values are ignored. Watch out: `type=documentary` can return a bare `null` body when no documentaries are in the top 60."
      },
      "BestAnimeTypeParam": {
        "name": "type",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "all",
            "tv",
            "movies",
            "ovas",
            "onas",
            "music"
          ]
        },
        "example": "tv",
        "description": "Optional. Narrow by anime format. Unknown values are ignored."
      },
      "PremieresParam": {
        "name": "param",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "enum": [
            "new",
            "soon"
          ]
        },
        "example": "new",
        "description": "`new` for recent releases (sorted newest first), `soon` for upcoming titles (sorted soonest first). Anything other than `new` behaves like `soon`."
      },
      "PremieresPageParam": {
        "name": "page",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 20
        },
        "example": 1,
        "description": "Page number (1-based). Maximum 20."
      },
      "PremieresLimitParam": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 60
        },
        "example": 60,
        "description": "Items per page. Maximum 60 — higher values are reduced to 60."
      },
      "PremieresTVTypeParam": {
        "name": "type",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "series",
            "documentary"
          ]
        },
        "example": "series",
        "description": "Optional. Narrow by show type. Unknown values are ignored — you get the full list."
      },
      "PremieresAnimeTypeParam": {
        "name": "type",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "all",
            "tv",
            "movies",
            "ovas",
            "onas",
            "music"
          ]
        },
        "example": "all",
        "description": "Optional. Narrow by anime format. Unknown values are ignored."
      }
    },
    "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
            }
          }
        }
      },
      "Forbidden": {
        "description": "Refused. The request was understood but the caller is not permitted to perform it — for example, a feature gated to Simkl Pro / VIP, or an action the user has not consented to.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "forbidden",
              "code": 403
            }
          }
        }
      },
      "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
            }
          }
        }
      },
      "Conflict": {
        "description": "The resource already exists or the operation is a duplicate.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "conflict",
              "code": 409
            }
          }
        }
      },
      "ClientIdFailed": {
        "description": "Your `client_id` is missing, wrong, disabled, or has hit a request limit. Verify in your [developer settings](https://simkl.com/settings/developer/).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "client_id_failed",
              "code": 412,
              "message": "Your client_id is wrong. Try another one"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests in too short a window. Back off and retry with exponential backoff — see [Rate limits](/resources/rate-limits) for the playbook.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "rate_limit",
              "code": 429
            }
          }
        }
      },
      "ServerError": {
        "description": "Something is broken on Simkl's side. Retry after a short delay. If it persists, report on the [Simkl Discord](https://discord.gg/MJsWNE4).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "internal",
              "code": 500
            }
          }
        }
      },
      "AllItemsListResponse": {
        "description": "OK",
        "headers": {},
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "type": "object",
                  "properties": {
                    "shows": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "added_to_watchlist_at": {
                            "type": "string"
                          },
                          "last_watched_at": {},
                          "user_rated_at": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "user_rating": {},
                          "last_watched": {},
                          "next_to_watch": {
                            "type": "string"
                          },
                          "watched_episodes_count": {
                            "type": "number"
                          },
                          "total_episodes_count": {
                            "type": "number"
                          },
                          "not_aired_episodes_count": {
                            "type": "number"
                          },
                          "show": {
                            "type": "object",
                            "properties": {
                              "title": {
                                "type": "string"
                              },
                              "poster": {
                                "type": "string"
                              },
                              "year": {
                                "type": "number"
                              },
                              "runtime": {
                                "type": "number"
                              },
                              "ids": {
                                "type": "object",
                                "properties": {
                                  "simkl": {
                                    "type": "number"
                                  },
                                  "slug": {
                                    "type": "string"
                                  },
                                  "imdb": {
                                    "type": "string"
                                  },
                                  "zap_2_it": {
                                    "type": "string"
                                  },
                                  "tmdb": {
                                    "type": "string"
                                  },
                                  "offen": {
                                    "type": "string"
                                  },
                                  "tvdb": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "anime": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "added_to_watchlist_at": {
                            "type": "string"
                          },
                          "last_watched_at": {
                            "type": "string"
                          },
                          "user_rated_at": {
                            "type": "string"
                          },
                          "user_rating": {
                            "type": [
                              "number",
                              "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"
                          },
                          "last_watched": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
                          },
                          "next_to_watch": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
                          },
                          "watched_episodes_count": {
                            "type": "number"
                          },
                          "total_episodes_count": {
                            "type": "number"
                          },
                          "not_aired_episodes_count": {
                            "type": "number"
                          },
                          "anime_type": {
                            "type": "string"
                          },
                          "show": {
                            "type": "object",
                            "properties": {
                              "title": {
                                "type": "string"
                              },
                              "poster": {
                                "type": "string"
                              },
                              "year": {
                                "type": "number"
                              },
                              "runtime": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "Type 4 null — data not on file in that field's slot. See [Null and missing values](/conventions/null-values)."
                              },
                              "ids": {
                                "type": "object",
                                "properties": {
                                  "simkl": {
                                    "type": "number"
                                  },
                                  "imdb": {
                                    "type": "string"
                                  },
                                  "mal": {
                                    "type": "string"
                                  },
                                  "anidb": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          }
                        },
                        "required": [
                          "added_to_watchlist_at",
                          "last_watched_at",
                          "user_rated_at",
                          "user_rating",
                          "status",
                          "last_watched",
                          "next_to_watch",
                          "anime_type",
                          "show"
                        ]
                      }
                    },
                    "movies": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "added_to_watchlist_at": {
                            "type": "string"
                          },
                          "last_watched_at": {
                            "type": "string"
                          },
                          "user_rated_at": {
                            "type": "string"
                          },
                          "user_rating": {},
                          "status": {
                            "type": "string"
                          },
                          "movie": {
                            "type": "object",
                            "properties": {
                              "title": {
                                "type": "string"
                              },
                              "poster": {
                                "type": "string"
                              },
                              "year": {
                                "type": "number"
                              },
                              "runtime": {
                                "type": "number"
                              },
                              "ids": {
                                "type": "object",
                                "properties": {
                                  "simkl": {
                                    "type": "number"
                                  },
                                  "imdb": {
                                    "type": "string"
                                  },
                                  "tmdb": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          }
                        },
                        "required": [
                          "added_to_watchlist_at",
                          "last_watched_at",
                          "user_rated_at",
                          "user_rating",
                          "status",
                          "movie"
                        ]
                      }
                    }
                  },
                  "title": "Default"
                },
                {
                  "type": "object",
                  "properties": {
                    "anime": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "added_to_watchlist_at": {
                            "type": "string"
                          },
                          "last_watched_at": {
                            "type": "string"
                          },
                          "user_rated_at": {
                            "type": "string"
                          },
                          "user_rating": {
                            "type": "number"
                          },
                          "status": {
                            "type": "string"
                          },
                          "last_watched": {
                            "type": "string"
                          },
                          "next_to_watch": {
                            "type": "string"
                          },
                          "show": {
                            "type": "object",
                            "properties": {
                              "title": {
                                "type": "string"
                              },
                              "year": {
                                "type": "number"
                              },
                              "runtime": {
                                "type": "number"
                              },
                              "ids": {
                                "type": "object",
                                "properties": {
                                  "simkl": {
                                    "type": "number"
                                  },
                                  "imdb": {
                                    "type": "string"
                                  },
                                  "mal": {
                                    "type": "string"
                                  },
                                  "anidb": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          },
                          "seasons": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "number": {
                                  "type": "number"
                                },
                                "episodes": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "number": {
                                        "type": "number"
                                      }
                                    },
                                    "required": [
                                      "number"
                                    ]
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "title": "With seasons"
                },
                {
                  "type": "object",
                  "properties": {
                    "anime": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "added_to_watchlist_at": {
                            "type": "string"
                          },
                          "last_watched_at": {
                            "type": "string"
                          },
                          "user_rated_at": {
                            "type": "string"
                          },
                          "user_rating": {
                            "type": "number"
                          },
                          "status": {
                            "type": "string"
                          },
                          "last_watched": {
                            "type": "string"
                          },
                          "next_to_watch": {
                            "type": "string"
                          },
                          "show": {
                            "type": "object",
                            "properties": {
                              "title": {
                                "type": "string"
                              },
                              "year": {
                                "type": "number"
                              },
                              "runtime": {
                                "type": "number"
                              },
                              "ids": {
                                "type": "object",
                                "properties": {
                                  "simkl": {
                                    "type": "number"
                                  },
                                  "imdb": {
                                    "type": "string"
                                  },
                                  "mal": {
                                    "type": "string"
                                  },
                                  "anidb": {
                                    "type": "string"
                                  },
                                  "tvdb": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          },
                          "tvdb_seasons": {
                            "type": "array",
                            "items": {
                              "type": "number"
                            }
                          },
                          "seasons": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "number": {
                                  "type": "number"
                                },
                                "episodes": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "number": {
                                        "type": "number"
                                      },
                                      "tvdb": {
                                        "type": "object",
                                        "properties": {
                                          "season": {
                                            "type": "number"
                                          },
                                          "episode": {
                                            "type": "number"
                                          }
                                        }
                                      }
                                    },
                                    "required": [
                                      "number",
                                      "tvdb"
                                    ]
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "title": "With episode timestamps (?episode_watched_at=yes)"
                },
                {
                  "type": "object",
                  "properties": {
                    "anime": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "added_to_watchlist_at": {
                            "type": "string"
                          },
                          "last_watched_at": {
                            "type": "string"
                          },
                          "user_rated_at": {
                            "type": "string"
                          },
                          "user_rating": {
                            "type": "number"
                          },
                          "status": {
                            "type": "string"
                          },
                          "last_watched": {
                            "type": "string"
                          },
                          "next_to_watch": {
                            "type": "string"
                          },
                          "memo": {
                            "type": "object",
                            "properties": {
                              "text": {
                                "type": "string",
                                "maxLength": 140,
                                "description": "Memo note text. Max 140 characters (server-enforced)."
                              },
                              "is_private": {
                                "type": "boolean"
                              }
                            }
                          },
                          "show": {
                            "type": "object",
                            "properties": {
                              "title": {
                                "type": "string"
                              },
                              "year": {
                                "type": "number"
                              },
                              "runtime": {
                                "type": "number"
                              },
                              "ids": {
                                "type": "object",
                                "properties": {
                                  "simkl": {
                                    "type": "number"
                                  },
                                  "imdb": {
                                    "type": "string"
                                  },
                                  "mal": {
                                    "type": "string"
                                  },
                                  "anidb": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "title": "With memos (?memos=yes)"
                }
              ],
              "description": "Response shape depends on the `{type}` path segment AND any extension query params (`extended=full`, `episode_watched_at=yes`, `memos=yes`). The \"Default\" variant shows what `type=all` returns; the rest show how anime sub-shapes change when an extension is on."
            },
            "examples": {
              "all-types": {
                "value": {
                  "shows": [
                    {
                      "added_to_watchlist_at": "2010-01-20T20:09:04.000Z",
                      "last_watched_at": null,
                      "user_rated_at": "2021-06-23T13:19:05.000Z",
                      "status": "hold",
                      "user_rating": null,
                      "last_watched": null,
                      "next_to_watch": "S01E01",
                      "watched_episodes_count": 0,
                      "total_episodes_count": 10,
                      "not_aired_episodes_count": 0,
                      "show": {
                        "title": "Emerald City",
                        "poster": "51/5152376528f644b91",
                        "year": 2017,
                        "runtime": 40,
                        "ids": {
                          "simkl": 583436,
                          "slug": "emerald-city",
                          "imdb": "tt3579018",
                          "zap2it": "EP02431429",
                          "tmdb": "62417",
                          "offen": "http://www.nbc.com/emerald-city",
                          "tvdb": "295779"
                        }
                      }
                    }
                  ],
                  "anime": [
                    {
                      "added_to_watchlist_at": "2010-01-20T20:09:04.000Z",
                      "last_watched_at": "2014-11-06T22:05:52.000Z",
                      "user_rated_at": "2021-06-23T13:19:05.000Z",
                      "user_rating": 10,
                      "status": "completed",
                      "last_watched": "E148",
                      "next_to_watch": null,
                      "watched_episodes_count": 150,
                      "total_episodes_count": 150,
                      "not_aired_episodes_count": 0,
                      "anime_type": "tv",
                      "show": {
                        "title": "Hunter x Hunter",
                        "poster": "83/83975f751784587",
                        "year": 2011,
                        "runtime": null,
                        "ids": {
                          "simkl": 40398,
                          "imdb": "tt2098220",
                          "mal": "11061",
                          "anidb": "8550"
                        }
                      }
                    },
                    {
                      "added_to_watchlist_at": "2010-01-20T20:09:04.000Z",
                      "last_watched_at": "2016-10-19T08:34:23.000Z",
                      "user_rated_at": "2021-06-23T13:19:05.000Z",
                      "user_rating": null,
                      "status": "plantowatch",
                      "last_watched": null,
                      "next_to_watch": "E01",
                      "anime_type": "tv",
                      "show": {
                        "title": "Ajin 2",
                        "year": 2016,
                        "runtime": 100,
                        "ids": {
                          "simkl": 581835,
                          "mal": "33253",
                          "anidb": "12111"
                        }
                      }
                    }
                  ],
                  "movies": [
                    {
                      "added_to_watchlist_at": "2010-01-20T20:09:04.000Z",
                      "last_watched_at": "2014-08-09T07:25:55.000Z",
                      "user_rated_at": "2021-06-23T13:19:05.000Z",
                      "user_rating": null,
                      "status": "completed",
                      "movie": {
                        "title": "Captain America: The First Avenger",
                        "poster": "84/842596c6291031c0",
                        "year": 2011,
                        "runtime": 120,
                        "ids": {
                          "simkl": 55328,
                          "imdb": "tt0458339",
                          "tmdb": "1771"
                        }
                      }
                    },
                    {
                      "added_to_watchlist_at": "2010-01-20T20:09:04.000Z",
                      "last_watched_at": "2014-08-16T18:45:20.000Z",
                      "user_rated_at": "2021-06-23T13:19:05.000Z",
                      "user_rating": null,
                      "status": "completed",
                      "movie": {
                        "title": "Maleficent",
                        "poster": "17/1722048af2197c9a7",
                        "year": 2014,
                        "runtime": 100,
                        "ids": {
                          "simkl": 195258,
                          "imdb": "tt1587310",
                          "tmdb": "102651"
                        }
                      }
                    }
                  ]
                },
                "summary": "All types"
              },
              "anime-minimal": {
                "value": {
                  "anime": [
                    {
                      "added_to_watchlist_at": "2010-01-20T20:09:04.000Z",
                      "last_watched_at": "2015-01-06T13:43:26.000Z",
                      "user_rated_at": "2021-06-23T13:19:05.000Z",
                      "user_rating": 9,
                      "status": "watching",
                      "last_watched": "S01E01",
                      "next_to_watch": "S01E02",
                      "show": {
                        "title": "Fate/Stay Night: Unlimited Blade Works",
                        "year": 2014,
                        "runtime": 100,
                        "ids": {
                          "simkl": 46116,
                          "imdb": "tt3621796",
                          "mal": "22297",
                          "anidb": "9977"
                        }
                      },
                      "seasons": [
                        {
                          "number": 1,
                          "episodes": [
                            {
                              "number": 1
                            },
                            {
                              "number": 2
                            },
                            {
                              "number": 3
                            },
                            {
                              "number": 4
                            },
                            {
                              "number": 5
                            },
                            {
                              "number": 6
                            },
                            {
                              "number": 7
                            },
                            {
                              "number": 8
                            },
                            {
                              "number": 9
                            },
                            {
                              "number": 10
                            },
                            {
                              "number": 11
                            },
                            {
                              "number": 12
                            }
                          ]
                        }
                      ]
                    }
                  ]
                },
                "summary": "Anime minimal"
              },
              "anime-with-status": {
                "value": {
                  "anime": [
                    {
                      "added_to_watchlist_at": "2010-01-20T20:09:04.000Z",
                      "last_watched_at": "2015-01-06T13:43:26.000Z",
                      "user_rated_at": "2021-06-23T13:19:05.000Z",
                      "user_rating": 9,
                      "status": "watching",
                      "last_watched": "S01E01",
                      "next_to_watch": "S01E02",
                      "show": {
                        "title": "Fate/Stay Night: Unlimited Blade Works",
                        "year": 2014,
                        "runtime": 100,
                        "ids": {
                          "simkl": 46116,
                          "imdb": "tt3621796",
                          "mal": "22297",
                          "anidb": "9977",
                          "tvdb": "278626"
                        }
                      },
                      "tvdb_seasons": [
                        2,
                        3
                      ],
                      "seasons": [
                        {
                          "number": 1,
                          "episodes": [
                            {
                              "number": 1,
                              "tvdb": {
                                "season": 1,
                                "episode": 1
                              }
                            },
                            {
                              "number": 2,
                              "tvdb": {
                                "season": 1,
                                "episode": 2
                              }
                            },
                            {
                              "number": 3,
                              "tvdb": {
                                "season": 1,
                                "episode": 3
                              }
                            },
                            {
                              "number": 4,
                              "tvdb": {
                                "season": 1,
                                "episode": 4
                              }
                            },
                            {
                              "number": 5,
                              "tvdb": {
                                "season": 1,
                                "episode": 5
                              }
                            },
                            {
                              "number": 6,
                              "tvdb": {
                                "season": 1,
                                "episode": 6
                              }
                            },
                            {
                              "number": 7,
                              "tvdb": {
                                "season": 1,
                                "episode": 7
                              }
                            },
                            {
                              "number": 8,
                              "tvdb": {
                                "season": 1,
                                "episode": 8
                              }
                            },
                            {
                              "number": 9,
                              "tvdb": {
                                "season": 1,
                                "episode": 9
                              }
                            },
                            {
                              "number": 10,
                              "tvdb": {
                                "season": 1,
                                "episode": 10
                              }
                            },
                            {
                              "number": 11,
                              "tvdb": {
                                "season": 1,
                                "episode": 11
                              }
                            },
                            {
                              "number": 12,
                              "tvdb": {
                                "season": 1,
                                "episode": 12
                              }
                            }
                          ]
                        }
                      ]
                    }
                  ]
                },
                "summary": "Anime with status"
              },
              "anime-with-episodes": {
                "value": {
                  "anime": [
                    {
                      "added_to_watchlist_at": "2010-01-20T20:09:04.000Z",
                      "last_watched_at": "2015-01-06T13:43:26.000Z",
                      "user_rated_at": "2021-06-23T13:19:05.000Z",
                      "user_rating": 9,
                      "status": "watching",
                      "last_watched": "S01E01",
                      "next_to_watch": "S01E02",
                      "memo": {
                        "text": "super memo.",
                        "is_private": true
                      },
                      "show": {
                        "title": "Fate/Stay Night: Unlimited Blade Works",
                        "year": 2014,
                        "runtime": 100,
                        "ids": {
                          "simkl": 46116,
                          "imdb": "tt3621796",
                          "mal": "22297",
                          "anidb": "9977"
                        }
                      }
                    }
                  ]
                },
                "summary": "Anime with episodes"
              }
            }
          }
        }
      },
      "PlaybackListResponse": {
        "description": "OK",
        "headers": {},
        "content": {
          "application/json": {
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/PlaybackSession"
              }
            },
            "example": [
              {
                "id": 123,
                "progress": 45.5,
                "paused_at": "2024-01-15T10:30:00.000Z",
                "type": "episode",
                "episode": {
                  "season": 1,
                  "episode": 5,
                  "title": "Episode 5",
                  "tvdb_season": 1,
                  "tvdb_number": 5
                },
                "show": {
                  "title": "Breaking Bad",
                  "year": 2008,
                  "ids": {
                    "simkl": 12345,
                    "slug": "breaking-bad",
                    "tmdb": "1429",
                    "imdb": "tt0903747"
                  }
                }
              },
              {
                "id": 124,
                "progress": 75,
                "paused_at": "2024-01-15T11:15:00.000Z",
                "type": "movie",
                "movie": {
                  "title": "Inception",
                  "year": 2010,
                  "ids": {
                    "simkl": 67890,
                    "slug": "inception",
                    "tmdb": "27205",
                    "imdb": "tt1375666"
                  }
                }
              }
            ]
          }
        }
      },
      "UserRatingsListResponse": {
        "description": "OK",
        "headers": {},
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "shows": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "last_watched_at": {
                        "type": "string"
                      },
                      "user_rated_at": {
                        "type": "string"
                      },
                      "user_rating": {
                        "type": "number"
                      },
                      "status": {
                        "type": "string"
                      },
                      "last_watched": {},
                      "next_to_watch": {
                        "type": "string"
                      },
                      "show": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "string"
                          },
                          "year": {
                            "type": "number"
                          },
                          "ids": {
                            "type": "object",
                            "properties": {
                              "simkl": {
                                "type": "number"
                              },
                              "imdb": {
                                "type": "string"
                              },
                              "tvdb": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "anime": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "last_watched_at": {
                        "type": "string"
                      },
                      "user_rated_at": {
                        "type": "string"
                      },
                      "user_rating": {
                        "type": "number"
                      },
                      "status": {
                        "type": "string"
                      },
                      "last_watched": {
                        "type": "string"
                      },
                      "next_to_watch": {},
                      "show": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "string"
                          },
                          "year": {
                            "type": "number"
                          },
                          "ids": {
                            "type": "object",
                            "properties": {
                              "simkl": {
                                "type": "number"
                              },
                              "imdb": {
                                "type": "string"
                              },
                              "mal": {
                                "type": "string"
                              },
                              "anidb": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "movies": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "last_watched_at": {
                        "type": "string"
                      },
                      "user_rated_at": {
                        "type": "string"
                      },
                      "user_rating": {
                        "type": "number"
                      },
                      "status": {
                        "type": "string"
                      },
                      "movie": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "string"
                          },
                          "year": {
                            "type": "number"
                          },
                          "ids": {
                            "type": "object",
                            "properties": {
                              "simkl": {
                                "type": "number"
                              },
                              "imdb": {
                                "type": "string"
                              },
                              "tmdb": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            },
            "example": {
              "shows": [
                {
                  "last_watched_at": "2016-09-12T13:00:30.000Z",
                  "user_rated_at": "2021-06-23T13:19:05.000Z",
                  "user_rating": 5,
                  "status": "dropped",
                  "last_watched": null,
                  "next_to_watch": "S01E01",
                  "show": {
                    "title": "The Last Ship",
                    "year": 2014,
                    "ids": {
                      "simkl": 42040,
                      "imdb": "tt2402207",
                      "tvdb": "269533"
                    }
                  }
                }
              ],
              "anime": [
                {
                  "last_watched_at": "2014-11-06T22:05:52.000Z",
                  "user_rated_at": "2021-06-23T13:19:05.000Z",
                  "user_rating": 10,
                  "status": "completed",
                  "last_watched": "E148",
                  "next_to_watch": null,
                  "show": {
                    "title": "Hunter x Hunter",
                    "year": 2011,
                    "ids": {
                      "simkl": 40398,
                      "imdb": "tt2098220",
                      "mal": "11061",
                      "anidb": "8550"
                    }
                  }
                }
              ],
              "movies": [
                {
                  "last_watched_at": "2014-08-16T18:45:20.000Z",
                  "user_rated_at": "2021-06-23T13:19:05.000Z",
                  "user_rating": 6,
                  "status": "completed",
                  "movie": {
                    "title": "Maleficent",
                    "year": 2014,
                    "ids": {
                      "simkl": 195258,
                      "imdb": "tt1587310",
                      "tmdb": "102651"
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
  },
  "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.\n\nSee [Standard media objects](/conventions/standard-media-objects) for the supported ID keys.\n\n<!-- IDS_TABLE_START -->\n\n### Supported ID keys\n\nInside any `ids` object, pass as many of these as you have. Simkl resolves to the canonical record.\n\n| ID key | Type | Example |\n|---|---|---|\n| `simkl` | integer | `49108`. Simkl's canonical ID. Most reliable. |\n| `imdb` | string | `tt1520211` |\n| `tmdb` | integer | `76757` (for TV, specify `type`) |\n| `tvdb` | int / string | `153021` or `the-walking-dead` |\n| `mal` | integer | `4246` (MyAnimeList) |\n| `anidb` | integer | `10846`. Specifying just this is enough for anime lookups. |\n| `anilist` | integer | `21` |\n| `kitsu` | integer | `12` |\n| `anisearch` | integer | `2227` |\n| `animeplanet` | string | `one-piece` |\n| `livechart` | integer | `321` |\n| `letterboxd` | string | `the-truman-show` |\n| `netflix` | integer | `70210890` (movie ID) |\n| `traktslug` | string | `john-wick-chapter-4-2023` |\n\n> 📖 Full reference: [Standard media objects](/conventions/standard-media-objects)\n\n<!-- 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.\n\nAll write endpoints accept arrays — batch aggressively. See [Standard media objects](/conventions/standard-media-objects) for the supported ID keys.\n\n<!-- IDS_TABLE_START -->\n\n### Supported ID keys\n\nInside any `ids` object, pass as many of these as you have. Simkl resolves to the canonical record.\n\n| ID key | Type | Example |\n|---|---|---|\n| `simkl` | integer | `49108`. Simkl's canonical ID. Most reliable. |\n| `imdb` | string | `tt1520211` |\n| `tmdb` | integer | `76757` (for TV, specify `type`) |\n| `tvdb` | int / string | `153021` or `the-walking-dead` |\n| `mal` | integer | `4246` (MyAnimeList) |\n| `anidb` | integer | `10846`. Specifying just this is enough for anime lookups. |\n| `anilist` | integer | `21` |\n| `kitsu` | integer | `12` |\n| `anisearch` | integer | `2227` |\n| `animeplanet` | string | `one-piece` |\n| `livechart` | integer | `321` |\n| `letterboxd` | string | `the-truman-show` |\n| `netflix` | integer | `70210890` (movie ID) |\n| `traktslug` | string | `john-wick-chapter-4-2023` |\n\n> 📖 Full reference: [Standard media objects](/conventions/standard-media-objects)\n\n<!-- IDS_TABLE_END -->",
      "externalDocs": {
        "description": "Sync guide",
        "url": "https://api.simkl.org/guides/sync"
      }
    },
    {
      "name": "Users",
      "description": "User profile, settings, and watch statistics."
    }
  ],
  "security": [
    {
      "clientId": []
    },
    {
      "simklApiKey": []
    }
  ],
  "externalDocs": {
    "description": "Simkl API documentation",
    "url": "https://api.simkl.org"
  }
}
