Skip to main content

Documentation Index

Fetch the complete documentation index at: https://api.simkl.org/llms.txt

Use this file to discover all available pages before exploring further.

Simkl uses AniDB as its primary metadata source for anime. Because the anime catalog is modeled differently than Western TV shows (often split per-cour or numbered absolutely), Simkl provides an automated cross-mapping system. This allows developers to interact with the anime catalog using standard TVDB/TMDB season-and-episode coordinates. This guide outlines the two primary integration paths, how the cross-mapping works under the hood with real-world examples, and how to write watch history and read catalog data.

Recommendation: Adopt Simkl’s Native Anime Catalog

If you are designing a new application or have the flexibility to add a dedicated Anime content type to your existing app, we strongly recommend using Simkl’s Native Anime Catalog (Path B) instead of treating anime as TV Shows.Why this is better:
  • No Season Discrepancies: Completely bypasses TMDB vs. TVDB season boundary disagreements.
  • 1:1 Native Syncing: Matches the data shape of major anime trackers (MyAnimeList, AniList, Kitsu, AniDB) for seamless 1:1 cross-platform syncing.
  • Rich Metadata: Access to anime-specific metadata like animation studios, airing calendars, and comprehensive franchise relationships (prequels, sequels, summaries, spin-offs).

The Two Integration Paths

Choose the path that fits your app’s existing metadata system:

Path A: TVDB/TMDB-Primary Tracker

Your app tracks general TV and uses TMDB or TVDB IDs. You want to sync anime without changing your TV-centric seasons/episodes structure.Uses Simkl’s automatic cross-mapping via the use_tvdb_anime_seasons flag.

Path B: Anime-Native App

Your app is dedicated to anime and uses MAL, AniDB, AniList, or Kitsu IDs. You deal with flat/absolute episode numbers directly.Bypasses cross-mapping and interacts directly with Simkl’s anime endpoints.

Integration Guide by App Type

Different app types require different integration strategies. Check the recommendations below to see which path and endpoints you should focus on:
Recommendation: Use Path A (TMDB/TVDB-Primary) for convenience, but see the best practices below for handling TMDB-primary boundary issues.
  • Syncing lists: Send history updates using TMDB or TVDB IDs, always passing "use_tvdb_anime_seasons": true.
  • Fetching library: Query GET /sync/all-items/anime?extended=full_anime_seasons. Use the mapped_tvdb_seasons array to know which seasons to render, and map the episodes back to your UI using tvdb.season and tvdb.episode.
  • Detail views: Use GET /anime/{id} to fetch details like studios and relations for anime shows.
Recommendation: Use Path A (TMDB/TVDB coordinates) for automated matching.
  • Real-time scrobbling: Send playback state to POST /scrobble/start using standard TVDB or TMDB IDs under the show key.
  • Why this is easy: You do not need to convert TVDB season/episodes to absolute numbers client-side. Simkl’s scrobbler handles the translation to absolute/cour-split anime entries automatically.
  • File-based scrobbling: If your scrobbler parses absolute numbers directly from filenames, you can optionally scrobble using absolute numbers under the anime object.
Recommendation: Use Path B (Anime-Native IDs).
  • Syncing lists: Send history updates using native database IDs (mal, anilist, anidb, kitsu) under the anime key.
  • Absolute numbering: Send flat, absolute episode numbers directly. Do not supply season coordinates.

Best Practices for TMDB-Primary Applications

Since TMDB is the most common metadata source for general media tracking applications, Simkl supports it fully. However, because TMDB’s season/episode definitions occasionally disagree with TVDB’s (which Simkl uses for mapping coordinates), you should use the following safe integration workflows:

The Safe Integration Workflow

If your application’s primary metadata source is TMDB, follow these rules to ensure perfect matching:
  1. Send Both IDs: Whenever writing to Simkl, include both the tmdb ID and the tvdb ID in your ids object. Simkl will resolve the show using the most reliable record.
  2. Translate to TVDB Coordinates on Writes: If you know TMDB and TVDB disagree on season boundaries for a specific anime, prioritize sending TVDB season and episode coordinates in the write payload when use_tvdb_anime_seasons: true is set.
  3. Use Simkl’s Native IDs as Fallbacks: If a show’s TVDB/TMDB seasons are severely misaligned or fragmented, look up the show on Simkl using Title + Year or external anime IDs (MAL/AniList), and sync it using Path B instead.

How the Cross-Mapping Works

Simkl stores a per-episode TVDB coordinate (tvdb.season, tvdb.episode) on every anime episode in the catalog. That coordinate maps directly from any TVDB- or TMDB-shaped seasons[N].episodes[M] payload to the exact Simkl record + episode the user means. The mapping handles every catalog shape uniformly.

Real-World Mapping Examples

The main TV story is split into six separate Simkl titles (one per broadcast cour). Each title’s episodes start at 1, and carry the TVDB coordinate it maps to:
Simkl cour-titleEpsFirst episode → TVDB
AOT S1 (39687, 2013)25Simkl ep 1 → TVDB S1E1
AOT Season 2 (439744, 2017)12Simkl ep 1 → TVDB S2E1
AOT Season 3 part 1 (694485, 2018)12Simkl ep 1 → TVDB S3E1
AOT Season 3 part 2 (931899, 2019)10Simkl ep 1 → TVDB S3E13
AOT Final Season (1120029, 2020)16Simkl ep 1 → TVDB S4E1
AOT Final Season part 2 (1579947, 2022)12Simkl ep 1 → TVDB S4E17
All six share TVDB ID 267440 and TMDB ID 1429. When you write to Season 3 Episode 13, Simkl automatically uses the episode offset mapping to route the write to episode 1 of AOT Season 3 Part 2 (931899).

Franchise Extensions (OVAs, Specials, Movies)

AniDB models specials, OVAs, films, and spin-offs as separate entries, which Simkl mirrors. Below is the inventory beyond the main TV cours:
Simkl titleTypeEpsTVDB cross-refTMDB cross-ref
AOT The Final Season special (1883416, 2023)special2267440 (parent TV)1429 (parent TV)
AOT: The Last Attack (2544548, 2024)movie11333100 (dedicated film)
AOT OAD (38688, 2013)ova8267440 (parent TV)1429 (parent TV)
AOT: No Regrets (419356, 2014)ova2
AOT: Wings of Freedom (49394, 2014)movie27398 (dedicated)1429 (parent TV) ⚠️
AOT: Roar of Awakening (732309, 2018)movie113398 (dedicated)1429 (parent TV) ⚠️
AOT: Chronicle (1358719, 2020)movie1140480 (dedicated)1429 (parent TV) ⚠️
AOT: Junior High (513950, 2015)tv12299882 (dedicated)63510 (dedicated TV)
Note: ⚠️ entries indicate parent-show fallback links on TMDB/TVDB instead of dedicated ones.

Path A: TMDB or TVDB Primary Integration

If your app uses TMDB or TVDB show IDs, you do not need to convert seasons/episodes to absolute numbers client-side. Simkl maps them automatically on both writes and reads.

1. Writing to Simkl (Syncing history/list additions)

When marking an episode as watched or adding a show to a list, send your TMDB/TVDB show ID along with standard seasons and episodes, and set use_tvdb_anime_seasons: true. Under the hood, this flag instructs the Simkl API to fetch the mapped franchise seasons/titles and route the TVDB coordinates to the correct under-the-hood Simkl anime record and episode.

Example Payload

For Attack on Titan Season 2 Episode 4 (using parent TV show TMDB ID 1429):
POST /sync/history
{
  "shows": [
    {
      "ids": { "tmdb": "1429" },
      "use_tvdb_anime_seasons": true,
      "seasons": [
        {
          "number": 2,
          "episodes": [{ "number": 4 }]
        }
      ]
    }
  ]
}
For One Piece Season 10 Episode 4 (using TMDB ID 37854):
POST /sync/history
{
  "shows": [
    {
      "ids": { "tmdb": "37854" },
      "use_tvdb_anime_seasons": true,
      "seasons": [
        {
          "number": 10,
          "episodes": [{ "number": 4 }]
        }
      ]
    }
  ]
}
Pro-tip: You can set use_tvdb_anime_seasons: true on all TV shows in your payload. For non-anime shows, the flag is a safe no-op. For anime, it automatically handles both per-cour split titles and absolute-numbered shows.

2. Reading from Simkl (Syncing watchlist & watch history)

When reading the user’s library, use extended=full_anime_seasons. This includes the TVDB/TMDB season cross-mapping in the response.
curl "https://api.simkl.com/sync/all-items/anime?extended=full_anime_seasons&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0" \
  -H "User-Agent: my-app-name/1.0" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Understanding the Response Fields

For anime shows, the response includes:
  • mapped_tvdb_seasons: An array of TVDB season numbers covered by this Simkl title. (e.g., [2] for Attack on Titan Season 2).
  • tvdb: { season, episode }: Attached to each episode object to map the AniDB/absolute episode back to the TMDB/TVDB coordinates.
Example response snippet:
{
  "anime": [
    {
      "show": {
        "title": "Shingeki no Kyojin Season 2",
        "ids": { "simkl": 439744, "tmdb": "1429" }
      },
      "mapped_tvdb_seasons": [2],
      "seasons": [
        {
          "number": 1,
          "episodes": [
            {
              "number": 1,
              "tvdb": { "season": 2, "episode": 1 }
            }
          ]
        }
      ]
    }
  ]
}

3. Scrobbling Playback

For media players, scrobble payloads are single-item envelopes. You do not need to set use_tvdb_anime_seasons. Send the payload under the standard show key using your TMDB/TVDB coordinates, and Simkl will resolve the anime mapping automatically.
POST /scrobble/start
{
  "progress": 0,
  "show": {
    "ids": { "tmdb": "1429" }
  },
  "episode": {
    "season": 2,
    "number": 4
  }
}

Path B: Anime-Native Integration

If your app uses anime-native IDs (MAL, AniList, AniDB, Kitsu), you bypass Simkl’s cross-mapping engine. External anime IDs have a 1:1 relationship with Simkl’s anime records.

1. Writing to Simkl

Use the anime array envelope, and supply flat/absolute episode numbers under episodes[] (do not include a season field).

Example Payload: Cour-Split Anime (Attack on Titan S2 Ep 4)

POST /sync/history
{
  "anime": [
    {
      "ids": {
        "mal": 25777,
        "anilist": 20958,
        "anidb": 10944
      },
      "episodes": [{ "number": 4 }]
    }
  ]
}

Example Payload: Absolute-Numbered Anime (One Piece Absolute Ep 403)

POST /sync/history
{
  "anime": [
    {
      "ids": {
        "mal": 21,
        "anilist": 21,
        "anidb": 69
      },
      "episodes": [{ "number": 403 }]
    }
  ]
}

2. Reading from Simkl (Syncing watchlist & watch history)

When reading the user’s library, perform a GET request to the anime-specific library endpoint:
curl "https://api.simkl.com/sync/all-items/anime?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0" \
  -H "User-Agent: my-app-name/1.0" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
The response returns entries in the anime array, with all mapped external IDs (MAL, AniList, AniDB, Kitsu, etc.) populated in the ids block. You can map these IDs directly to your app’s local database without any coordinate translation layers.

Example Response Snippet

{
  "anime": [
    {
      "added_to_watchlist_at": "2026-05-20T03:00:00-04:00",
      "status": "watching",
      "watched_episodes_count": 4,
      "total_episodes_count": 12,
      "anime": {
        "title": "Shingeki no Kyojin Season 2",
        "ids": {
          "simkl": 439744,
          "mal": "25777",
          "anilist": "20958",
          "anidb": "10944",
          "kitsu": "8756"
        }
      }
    }
  ]
}

Anime-Specific Catalog Fields

When querying Simkl’s catalog endpoints (e.g., GET /anime/{id}), you will encounter fields unique to the anime catalog:

1. anime_type

Differentiates the format of the entry. Useful for client-side filtering:
TypeMeaning
tvStandard broadcast television series
movieTheatrical film
ovaOriginal Video Animation (direct-to-video)
onaOriginal Net Animation (web-released)
specialSpecials, OADs, side stories
music videoMusic videos

2. relations[]

Lists prequels, sequels, summaries, and side-stories.
  • relation_type: Describes the relationship (e.g., prequel, sequel, summary, side story).
  • is_direct: true for immediate narrative continuations; false for spin-offs or wider connections.

3. Flat Episode Lists

Unlike standard TV episode lists, GET /anime/episodes/{id} returns a flat array of episodes. Standard episodes and specials alike omit the season field, carrying only episode (flat/absolute number) and a tvdb coordinate block.

Anime-Specific Endpoints + Parameters Reference

Writes

EndpointAnime-specific behavior
POST /sync/historyAccepts anime[] envelope (alternative to shows[]). The use_tvdb_anime_seasons: true flag on a shows[] entry routes TVDB season/episode coordinates to the correct under-the-hood Simkl record via per-episode cross-mapping.
POST /sync/history/removeSame shape and flags as /sync/history.
POST /sync/add-to-listSame shape and flags. Used to move anime into watching / plantowatch / hold / completed / dropped.
POST /scrobble/startSingle-item envelope: anime: { ids: {...} } + episode: { season, number } (for TMDB/TVDB IDs) or episode: { number } (for anime-native IDs). Resolves the title and matches the episode through the same cross-map.

Reads — User Library

EndpointAnime-specific behavior
GET /sync/all-items/animeType-scoped library read — returns only the user’s anime entries.
GET /sync/all-items?extended=full_anime_seasonsAdds mapped_tvdb_seasons: [N, ...] to anime show entries and adds a tvdb: { season, episode } cross-map block to every anime episode in the response.
GET /sync/all-items?anime_type=tvFilter anime entries by anime_type (tv, movie, ova, ona, special, music video).
GET /sync/activitiesReturns an anime block separate from tv_shows and movies, each with its own per-status timestamps.

Reads — Catalog

EndpointAnime-specific behavior
GET /anime/{id}Anime detail. Returns: anime_type, mapped_tvdb_seasons[], relations[], en_title, alt_titles[], season_name_year, and studios. (Does not include the episode list).
GET /anime/episodes/{id}Returns flat episode array (no season fields; episode number is 1-N). Includes tvdb: { season, episode } blocks on each episode.
GET /search/animeText search scoped to anime catalog. Returns anime_type, title_romaji, and title_en.

Integration Edge Cases

Because TMDB and TVDB are community-maintained, they occasionally disagree on season numbering for newer or split-cour anime (e.g., Solo Leveling).Since Simkl’s cross-mapping is based on TVDB season coordinates, sending TMDB-only IDs with TMDB-style season numbers can sometimes route to the wrong cour.Solutions:
  1. Send the TVDB ID (ids.tvdb) alongside the TMDB ID, using the TVDB season numbering in your payload.
  2. Provide anime-native IDs (mal, anilist, anidb) if your app has access to them, which maps 1:1 and avoids the translation step.
  3. Send Title + Year (title and year). Simkl’s server-side title resolver is robust and resolves directly to the right cour.
OVAs, specials, and recap films often inherit the parent TV show’s TMDB or TVDB ID on Simkl because a dedicated film entry does not exist or wasn’t linked.
  • Implied Action: Do not assume the Simkl tmdb / tvdb ID maps 1:1 to a unique external entry. To deep-link to external catalogs, treat these IDs as references rather than canonical links.
Some multi-part film series are grouped as a single Simkl entry with multiple episodes (each representing a film part).Check the total_episodes field to determine if a movie entry contains multiple parts.

Next Steps

Mark as watched

POST /sync/history — payload shape, batching, mixing movies / shows / anime in one call.

Sync watch state

Initial sync + continuous deltas, /sync/activities gating, extended=full_anime_seasons, supported IDs, write operations, edge cases.

Scrobbling playback

Real-time start / pause / stop / checkin. Includes anime-episode-numbering examples for both anime-native and TMDB / TVDB-shaped scrobbles.

Standard media objects

The ids table, anime[] vs shows[] envelope rule, and how episode objects work across every endpoint.