anidump API
A small, read-only HTTP mirror of AniDB, MyAnimeList, AniList, Anime News Network and Kitsu anime metadata — including Kitsu's per-episode records.
anidump collects public anime metadata from AniDB, MyAnimeList, AniList, Anime News Network and Kitsu and serves it back as plain JSON (and, for AniDB, the original XML). It is a personal hobby project, not an official AniDB, MyAnimeList, AniList, Anime News Network or Kitsu service. Everything here is read-only and unauthenticated — there is no API key, no login, and no write endpoint.
Best-effort dataset: no uptime, latency, or rate-limit guarantees, and the shape below can change. If you need reliability or bulk access, mirror the data rather than hammering this endpoint.
Base URL: https://anidump.id
Data model, in one breath
There are five independent datasets, each keyed by its own upstream id: AniDB records under
/api/anidb/…, keyed by an AniDB aid (anidb_id); MyAnimeList
records under /api/mal/…, keyed by a mal_id; AniList records under
/api/anilist/…, keyed by an anilist_id; Anime News Network
encyclopedia records under /api/ann/…, keyed by an ann_id; and Kitsu
records under /api/kitsu/…, keyed by a kitsu_id. The datasets are not
cross-linked here, with three convenience exceptions: an AniList record carries
id_mal, AniList's own pointer to the matching mal_id; an AniDB record
carries mal_id and ann_id; and a Kitsu record carries
mal_id, anilist_id and anidb_id. (If you want the links
themselves rather than one record's view of them, use /api/map.) anidump fetches
records one at a time, so only a subset of each upstream's id space is present at any moment, and
that subset grows over time. Each dataset has two levels of detail:
- Parsed — a flat, curated projection (
/api/anidb/{id},/api/mal/{id},/api/anilist/{id},/api/ann/{id},/api/kitsu/{id}). - Raw — exactly what the upstream returned, byte-for-byte
(
/raw). AniDB additionally serves its original XML at/raw/xml; MyAnimeList, AniList and Kitsu serve JSON only, and ANN's XML is converted to JSON when we fetch it, so there is no/api/mal/{id}/raw/xml,/api/anilist/{id}/raw/xml,/api/ann/{id}/raw/xmlor/api/kitsu/{id}/raw/xml.
Kitsu has one thing the other four do not: episodes. They live
nested under the anime (/api/kitsu/{id}/episodes), because that is what they
are — an episode belongs to a series, and we fetch a whole anime's episodes as a single unit. There
is no flat /api/kitsu/episodes/{id} and no all-episodes listing; walk
/api/kitsu/ids and ask each anime for its own. Everywhere else, an "episode" is just
a count on the anime record.
Routes
GET/api/anidb/ids
Every aid anidump has actually fetched, with its main title, ordered by anidb_id.
This is a subset of AniDB's full aid space and grows over time. Every id it returns
resolves on /api/anidb/{id}. An empty dataset returns [], never
null. title may be null.
curl https://anidump.id/api/anidb/ids
[
{"anidb_id": 1, "title": "Seikai no Monshou"},
{"anidb_id": 2, "title": "Seikai no Senki"},
{"anidb_id": 5, "title": "Cowboy Bebop: Tengoku no Tobira"}
]
GET/api/anidb/{id}
The parsed record for one aid. 404 if that aid has not been fetched. See the
field reference below.
curl https://anidump.id/api/anidb/1
{
"anidb_id": 1,
"title": "Seikai no Monshou",
"title_english": "Crest of the Stars",
"title_native": "星界の紋章",
"synonyms": ["CotS", "Hvězdný erb"],
"type": "TV Series",
"restricted": false,
"picture": "224210.jpg",
"url": "http://www.sunrise-inc.co.jp/seikai/",
"startdate": "1999-01-03",
"startyear": 1999,
"enddate": "1999-03-28",
"episodecount": 13,
"description": "In the future, mankind ...",
"mal_id": 290,
"ann_id": 14,
"tags": [{"anidb_tag_id": 2626, "name": "future", "weight": 600}],
"relatedanime": [{"anidb_id": 2, "type": "Sequel"}]
}
GET/api/anidb/{id}/raw
The AniDB HTTP-API response for this aid converted to JSON, served
verbatim as stored. Richer and more deeply nested than the parsed record
(attributes become @-prefixed keys). 404 if the aid is unknown or its
payload has not been fetched yet.
curl https://anidump.id/api/anidb/1/raw
{"anime": {
"@id": "1",
"@restricted": "false",
"type": "TV Series",
"episodecount": "13",
"startdate": "1999-01-03",
"enddate": "1999-03-28",
"titles": {"title": [
{"@xml:lang": "x-jat", "@type": "main", "#text": "Seikai no Monshou"}
]},
"picture": "224210.jpg"
}}
GET/api/anidb/{id}/raw/xml
The original AniDB XML, served verbatim as
application/xml. 404 if the aid is unknown or the XML has not been
fetched yet.
curl https://anidump.id/api/anidb/1/raw/xml
<?xml version="1.0" encoding="UTF-8"?>
<anime id="1" restricted="false">
<type>TV Series</type>
<episodecount>13</episodecount>
<startdate>1999-01-03</startdate>
<enddate>1999-03-28</enddate>
<titles>
<title xml:lang="x-jat" type="main">Seikai no Monshou</title>
</titles>
<picture>224210.jpg</picture>
</anime>
GET/api/mal/ids
Every mal_id anidump has actually fetched, with its main title, ordered by
mal_id. Every id it returns resolves on /api/mal/{id}. An empty
dataset returns [], never null. title may be
null.
curl https://anidump.id/api/mal/ids
[
{"mal_id": 1, "title": "Cowboy Bebop"},
{"mal_id": 5, "title": "Cowboy Bebop: Tengoku no Tobira"},
{"mal_id": 6, "title": "Trigun"}
]
GET/api/mal/{id}
The parsed record for one mal_id. 404 if that id has not been
fetched. Scores, ranks and member counts are not in this projection — they
change constantly, so they are served only by /api/mal/{id}/raw. See the field
reference below.
curl https://anidump.id/api/mal/1
{
"mal_id": 1,
"title": "Cowboy Bebop",
"title_english": "Cowboy Bebop",
"title_japanese": "カウボーイビバップ",
"title_synonyms": [],
"type": "TV",
"source": "Original",
"status": "Finished Airing",
"rating": "R - 17+ (violence & profanity)",
"approved": true,
"airing": false,
"episodes": 26,
"duration": "24 min per ep",
"aired_from": "1998-04-03",
"aired_to": "1999-04-24",
"season": "spring",
"year": 1998,
"genres": ["Action", "Award Winning", "Sci-Fi"],
"explicit_genres": [],
"themes": ["Adult Cast", "Space"],
"demographics": [],
"studios": ["Sunrise"],
"producers": ["Bandai Visual"],
"licensors": ["Funimation", "Bandai Entertainment"],
"synopsis": "Crime is timeless…",
"url": "https://myanimelist.net/anime/1/Cowboy_Bebop",
"image_url": "https://cdn.myanimelist.net/images/anime/4/19644l.jpg",
"absent": false,
"absent_at": null
}
GET/api/mal/{id}/raw
The full upstream MyAnimeList record for this id, served verbatim as stored.
Much richer than the parsed record: this is where score, scored_by,
rank, popularity, members and favorites
live, along with relations, streaming, external,
theme and the full images / trailer objects.
404 if the id is unknown or its payload has not been fetched yet.
These counters are a snapshot taken when we last fetched the record, not a live value. Treat them as stale by up to a couple of days.
curl https://anidump.id/api/mal/1/raw
{
"mal_id": 1,
"url": "https://myanimelist.net/anime/1/Cowboy_Bebop",
"title": "Cowboy Bebop",
"type": "TV",
"episodes": 26,
"status": "Finished Airing",
"aired": {"from": "1998-04-03T00:00:00+00:00", "to": "1999-04-24T00:00:00+00:00"},
"score": 8.75,
"scored_by": 1054321,
"rank": 46,
"popularity": 43,
"members": 1980000,
"favorites": 82000,
"genres": [{"mal_id": 1, "type": "anime", "name": "Action"}],
"studios": [{"mal_id": 14, "type": "anime", "name": "Sunrise"}],
"relations": [{"relation": "Adaptation", "entry": [{"mal_id": 173, "type": "manga"}]}]
}
GET/api/anilist/ids
Every anilist_id anidump has actually fetched, with its romaji title, ordered by
anilist_id. Every id it returns resolves on /api/anilist/{id}. An
empty dataset returns [], never null. title may be
null.
curl https://anidump.id/api/anilist/ids
[
{"anilist_id": 1, "title": "Cowboy Bebop"},
{"anilist_id": 5, "title": "Cowboy Bebop: Tengoku no Tobira"},
{"anilist_id": 6, "title": "Trigun"}
]
GET/api/anilist/{id}
The parsed record for one anilist_id. 404 if that id has not been
fetched. Scores, popularity and favourites are not in this projection — they
change constantly, so they are served only by /api/anilist/{id}/raw. Air dates are
split into _year / _month / _day parts, any of which can
be null on its own. See the field reference below.
curl https://anidump.id/api/anilist/1
{
"anilist_id": 1,
"id_mal": 1,
"title_romaji": "Cowboy Bebop",
"title_english": "Cowboy Bebop",
"title_native": "カウボーイビバップ",
"synonyms": ["Kaubōi Bibappu"],
"format": "TV",
"status": "FINISHED",
"source": "ORIGINAL",
"country_of_origin": "JP",
"is_licensed": true,
"episodes": 26,
"duration": 24,
"start_year": 1998, "start_month": 4, "start_day": 3,
"end_year": 1999, "end_month": 4, "end_day": 24,
"season": "SPRING",
"season_year": 1998,
"description": "In the year 2071, humanity has colonized…",
"cover_image": "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx1.png",
"banner_image": "https://s4.anilist.co/file/anilistcdn/media/anime/banner/1.jpg",
"genres": ["Action", "Adventure", "Drama", "Sci-Fi"],
"tags": ["Space", "Crime", "Episodic"],
"studios": ["Sunrise"],
"producers": ["Bandai Visual", "Bandai Entertainment"],
"absent": false,
"absent_at": null
}
GET/api/anilist/{id}/raw
The full upstream AniList GraphQL Media object for this id, served
verbatim as stored. Much richer than the parsed record: this is where
averageScore, meanScore, popularity and
favourites live, along with the full tags (with per-tag
rank), relations, trailer, coverImage
variants and nextAiringEpisode. 404 if the id is unknown or its
payload has not been fetched yet.
These counters are a snapshot taken when we last fetched the record, not a live value. Treat them as stale by up to a day.
curl https://anidump.id/api/anilist/1/raw
{
"id": 1,
"idMal": 1,
"title": {"romaji": "Cowboy Bebop", "english": "Cowboy Bebop", "native": "カウボーイビバップ"},
"format": "TV",
"status": "FINISHED",
"averageScore": 86,
"meanScore": 86,
"popularity": 456596,
"favourites": 32527,
"tags": [{"id": 63, "name": "Space", "rank": 94}],
"studios": {"nodes": [{"id": 14, "name": "Sunrise", "isAnimationStudio": true}]},
"relations": {"edges": [{"relationType": "SIDE_STORY", "node": {"id": 5, "type": "ANIME"}}]},
"nextAiringEpisode": null
}
GET/api/ann/ids
Every ann_id anidump has actually fetched, with its main title, ordered by
ann_id. Every id it returns resolves on /api/ann/{id}. An empty
dataset returns [], never null. title may be
null.
curl https://anidump.id/api/ann/ids
[
{"ann_id": 1, "title": "Angel Links"},
{"ann_id": 2, "title": "Apocalypse Zero"},
{"ann_id": 4658, "title": "Jinki:Extend"}
]
GET/api/ann/{id}
The parsed record for one ann_id. 404 if that id has not been
fetched. ANN's vote-based ratings are not in this projection — they change
constantly, so they are served only by /api/ann/{id}/raw. url is the
Anime News Network encyclopedia entry for this id; please keep it visible if you display the
record (see Attribution at the foot of this page). See the field reference below.
curl https://anidump.id/api/ann/1
{
"ann_id": 1,
"type": "TV",
"precision": "TV",
"title": "Angel Links",
"alternative_titles": ["Seihō Tenshi Angel Links", "星方天使エンジェルリンクス"],
"genres": ["action", "drama", "science fiction"],
"themes": ["pirates", "space"],
"plot_summary": "Li Meifon is the head of a free protection/security agency…",
"episodes": 13,
"running_time": "half hour",
"vintage": ["1999-04-07 to 1999-06-30"],
"start_year": 1999,
"objectionable_content": "TA",
"official_websites": ["http://www.sunrise-inc.co.jp/seihou/ANGEL-LINKS/story.html"],
"picture": "https://cdn.animenewsnetwork.com/thumbnails/max500x600/encyc/A1-51.jpg",
"url": "https://www.animenewsnetwork.com/encyclopedia/anime.php?id=1",
"absent": false,
"absent_at": null
}
GET/api/ann/{id}/raw
The full Anime News Network encyclopedia record for this id, served verbatim
as stored — ANN's api.xml converted to JSON (attributes become
@-prefixed keys, text is #text, repeated siblings become arrays).
Much richer than the parsed record: this is where ratings, cast,
staff, credit, episode, release and the
related-prev / related-next links live. 404 if the id is
unknown or its payload has not been fetched yet.
curl https://anidump.id/api/ann/1/raw
{"anime": {
"@id": "1",
"@type": "TV",
"@precision": "TV",
"@name": "Angel Links",
"info": [
{"@type": "Main title", "#text": "Angel Links"},
{"@type": "Genres", "#text": "action"},
{"@type": "Picture", "@src": "https://cdn.animenewsnetwork.com/…/A1-51.jpg"}
],
"ratings": {"@nb_votes": "352", "@bayesian_score": "5.85776", "@weighted_score": "5.8028"},
"cast": [{"@lang": "JA", "role": "Li Meifon", "person": {"#text": "Yuko Miyamura"}}]
}}
GET/api/kitsu/ids
Every kitsu_id anidump has actually fetched, with its canonical title, ordered by
kitsu_id. Every id it returns resolves on /api/kitsu/{id}. An empty
dataset returns [], never null. title may be
null.
curl https://anidump.id/api/kitsu/ids
[
{"kitsu_id": 1, "title": "Cowboy Bebop"},
{"kitsu_id": 2, "title": "Cowboy Bebop: Tengoku no Tobira"},
{"kitsu_id": 3, "title": "Trigun"}
]
GET/api/kitsu/{id}
The parsed record for one kitsu_id. 404 if that id has not been
fetched. Ratings, user counts and the global ranks are not in this projection
— they change constantly, so they are served only by /api/kitsu/{id}/raw.
url is the Kitsu entry for this id; please keep it visible if you display the
record (see Attribution at the foot of this page).
This is the record to reach for if you want cross-service ids: Kitsu keeps its
own mapping table, so mal_id, anilist_id and anidb_id
come straight from it. See the field reference below.
curl https://anidump.id/api/kitsu/1
{
"kitsu_id": 1,
"slug": "cowboy-bebop",
"canonical_title": "Cowboy Bebop",
"title_en": "Cowboy Bebop",
"title_en_jp": "Cowboy Bebop",
"title_ja_jp": "カウボーイビバップ",
"other_titles": ["Cowboy Bebop"],
"abbreviated_titles": ["COWBOY BEBOP"],
"description": "In the year 2071, humanity has colonized…",
"subtype": "TV",
"status": "finished",
"tba": null,
"age_rating": "R",
"age_rating_guide": "17+ (Violence & Profanity)",
"nsfw": false,
"episode_count": 26,
"episode_length": 24,
"total_length": 624,
"start_date": "1998-04-03",
"end_date": "1999-04-24",
"poster_image": "https://media.kitsu.io/anime/poster_images/1/original.png",
"cover_image": "https://media.kitsu.io/anime/cover_images/1/original.png",
"youtube_video_id": "qig4KOK2R2g",
"url": "https://kitsu.io/anime/cowboy-bebop",
"mal_id": 1,
"anilist_id": 1,
"anidb_id": 23,
"absent": false,
"absent_at": null
}
GET/api/kitsu/{id}/raw
The full upstream Kitsu record for this id, served verbatim as stored: the
JSON:API resource object (id, type, attributes) plus a
resolved mappings array. Much richer than the parsed record: this is where
averageRating, ratingFrequencies, userCount,
favoritesCount, popularityRank and ratingRank live,
along with every posterImage / coverImage size variant, the whole
titles locale map, and nextRelease. 404 if the id is
unknown or its payload has not been fetched yet.
Kitsu's JSON:API links and relationships are not kept: they
are boilerplate derivable from the id, and relationships in particular is only a
pointer into a batch-scoped included block that does not survive one record. The
information in it — the cross-service mappings — is resolved at fetch time and stored as the
flat mappings array you see here. These counters are a snapshot taken
when we last fetched the record, not a live value.
curl https://anidump.id/api/kitsu/1/raw
{
"id": "1",
"type": "anime",
"attributes": {
"slug": "cowboy-bebop",
"canonicalTitle": "Cowboy Bebop",
"titles": {"en": "Cowboy Bebop", "en_jp": "Cowboy Bebop", "ja_jp": "カウボーイビバップ"},
"subtype": "TV",
"status": "finished",
"averageRating": "82.29",
"ratingFrequencies": {"2": "13", "3": "1", "4": "6"},
"userCount": 138416,
"favoritesCount": 3958,
"popularityRank": 28,
"ratingRank": 27,
"posterImage": {"tiny": "…", "small": "…", "original": "…"}
},
"mappings": [
{"id": "1", "externalSite": "myanimelist/anime", "externalId": "1"},
{"id": "9578", "externalSite": "anilist/anime", "externalId": "1"},
{"id": "43151", "externalSite": "anidb", "externalId": "23"}
]
}
GET/api/kitsu/{id}/episodes
Every episode of one anime, in broadcast order (season_number, then
number). Kitsu is the only upstream here with a real per-episode dataset, so this
is the only place episode titles, air dates and synopses exist — the other four give you an
episode count and nothing more.
[] and 404 mean different things, and the difference matters
if you are mirroring. An empty episodes array with 200 is a
real answer: this anime has no episodes on Kitsu (a movie, an unaired entry, a listing
Kitsu has not broken out). A 404 means we have never fetched this anime's
episode list — the id may be perfectly valid on /api/kitsu/{id}. Do not record
a 404 as "0 episodes".
Episodes are nested under the anime — there is no
/api/kitsu/episodes/{id}, and no /api/kitsu/episodes/ids listing. An
episode is only meaningful as part of a series, we fetch a whole anime's episodes as one unit,
and a flat listing of all ~292,000 of them would be a ~10 MB response nobody wants. Start
from /api/kitsu/ids and walk it.
curl https://anidump.id/api/kitsu/1/episodes
{
"kitsu_id": 1,
"url": "https://kitsu.io/anime/cowboy-bebop",
"episodes": [
{
"kitsu_episode_id": 1,
"kitsu_id": 1,
"canonical_title": "Asteroid Blues",
"title_en_us": "Asteroid Blues",
"title_en_jp": "Asteroid Blues",
"title_ja_jp": "アステロイドブルース",
"other_titles": [],
"description": "Spike and Jet pursue a bounty on Tijuana…",
"season_number": 1,
"number": 1,
"relative_number": 1,
"airdate": "1998-04-03",
"length_minutes": 25,
"thumbnail": "https://media.kitsu.io/episodes/thumbnails/1/original.jpg"
}
]
}
GET/api/kitsu/{id}/episodes/{episode_id}
One episode, exactly as it appears in the list above, plus the anime's url. It is
scoped to its anime: an episode_id that belongs to a different
anime is a 404 under this path, even though it exists. Both ids must be positive
integers, or it is a 400.
curl https://anidump.id/api/kitsu/1/episodes/1
{
"kitsu_episode_id": 1,
"kitsu_id": 1,
"canonical_title": "Asteroid Blues",
"title_en_us": "Asteroid Blues",
"title_en_jp": "Asteroid Blues",
"title_ja_jp": "アステロイドブルース",
"other_titles": [],
"description": "Spike and Jet pursue a bounty on Tijuana…",
"season_number": 1,
"number": 1,
"relative_number": 1,
"airdate": "1998-04-03",
"length_minutes": 25,
"thumbnail": "https://media.kitsu.io/episodes/thumbnails/1/original.jpg",
"url": "https://kitsu.io/anime/cowboy-bebop"
}
GET/api/kitsu/{id}/episodes/raw
The whole episode list for this anime as we stored it from Kitsu, verbatim:
each entry is the upstream episode object flattened to {id, …attributes}, ordered
by episode id. This is where the fields the parsed projection leaves out live —
synopsis (a duplicate of description in every episode we measured),
createdAt, updatedAt, and the thumbnail object rather
than just its original URL. Same 404 rule as above.
curl https://anidump.id/api/kitsu/1/episodes/raw
{
"kitsu_id": 1,
"episodes": [
{
"id": "1",
"canonicalTitle": "Asteroid Blues",
"titles": {"en_us": "Asteroid Blues", "en_jp": "Asteroid Blues", "ja_jp": "アステロイドブルース"},
"seasonNumber": 1,
"number": 1,
"relativeNumber": 1,
"airdate": "1998-04-03",
"length": 25,
"synopsis": "Spike and Jet pursue a bounty on Tijuana…",
"description": "Spike and Jet pursue a bounty on Tijuana…",
"createdAt": "2013-02-20T16:00:14.183Z",
"updatedAt": "2023-11-01T09:12:22.918Z",
"thumbnail": {"original": "https://media.kitsu.io/episodes/thumbnails/1/original.jpg"}
}
]
}
GET/api/map/{id}
The cross-service id map for one MyAnimeList id: the sets of AniDB, AniList and ANN ids
that refer to the same title. Each is an array because the services split and merge
titles differently, so a MAL entry can correspond to several ids on another service (and
a side with none known is []). It is derived first-party — from AniList's
idMal, AniDB's <resources> ids, and exact-title matching —
so it can contain a link the source itself got wrong, and can miss one the sources never
recorded. 404 if the MAL id has no known cross-reference.
curl https://anidump.id/api/map/1535
{"mal_id": 1535, "anidb_id": [4563], "anilist_id": [1535], "ann_id": [6592]}
GET/api/map
The entire map, one object per MAL id (same shape as /api/map/{id}), ordered
by mal_id. Like the /ids listings this is a single large response;
mirror it rather than polling.
curl https://anidump.id/api/map
[{"mal_id": 1, "anidb_id": [], "anilist_id": [1], "ann_id": []}, …]
Field reference — /api/anidb/{id}
| Field | Type | Notes |
|---|---|---|
| anidb_id | integer | The AniDB aid. Stable primary key. |
| title | string · null | The AniDB main title (usually romaji / x-jat). |
| title_english | string · null | The official English title, when AniDB has one (null for most entries). |
| title_native | string · null | The official native (Japanese) title. Distinct from title, which is the romaji. |
| synonyms | array of string | Alternative/synonym titles across languages. Empty [] when none, never null. |
| type | string · null | e.g. TV Series, Movie, OVA, Web. |
| restricted | boolean | AniDB's adult / 18+ flag. true for restricted entries, else false. |
| picture | string · null |
A bare cover-art filename, not a URL. Build the image URL yourself:
https://cdn.anidb.net/images/main/<picture>
(e.g. https://cdn.anidb.net/images/main/224210.jpg). null when the
anime has no picture.
|
| url | string · null | The anime's official website, when AniDB records one. null otherwise. |
| startdate | string · null | Full air-start date as YYYY-MM-DD. See the note on partial dates below. |
| startyear | integer · null | The air-start year on its own. Populated even when startdate is
null.
|
| enddate | string · null | Full air-end date as YYYY-MM-DD; same partial-date caveat as
startdate.
|
| episodecount | integer · null | Planned/known episode count. null when unknown. |
| description | string · null | The AniDB synopsis, kept verbatim including AniDB's own markup. null when absent. |
| mal_id | integer · null |
The matching MyAnimeList id, taken from AniDB's cross-reference block —
join it to /api/mal/{mal_id}. null when AniDB has no MAL link
(~14% of entries).
|
| ann_id | integer · null |
The matching Anime News Network encyclopedia id — join it to
/api/ann/{ann_id}. null when AniDB has no ANN link
(~32% of entries).
|
| tags | array |
AniDB tags, each {"anidb_tag_id": <int>, "name": "<tag>", "weight": <int|null>},
ordered by descending weight (relevance). Empty [] or null when there are none.
|
| relatedanime | array |
Related entries, each {"anidb_id": <int>, "type": "<relation>"} where
the relation is AniDB's own (Sequel, Prequel,
Side story, Parent story, …). Empty [] or
null when there are no relations.
|
startdate vs. startyear.
AniDB sometimes knows only a partial date — a bare year, or a year and month — for
when a show aired. A partial date cannot be expressed as a real YYYY-MM-DD, so
startdate (and enddate) collapse to null in those cases,
while startyear keeps the year. So: prefer startdate for a precise
date, but fall back to startyear when it is null. The same holds for
enddate.
Field reference — /api/mal/{id}
| Field | Type | Notes |
|---|---|---|
| mal_id | integer | The MyAnimeList id. Stable primary key. Unrelated to anidb_id. |
| title | string · null | The default title, usually romaji. |
| title_english title_japanese |
string · null | null for a large fraction of entries — most have no English title. |
| title_synonyms | array of string | Alternative titles. Empty [] when there are none, never null. |
| type | string · null |
TV, Movie, OVA, ONA,
Special, TV Special, Music, CM,
PV, or the literal Unknown.
|
| source | string · null | What it was adapted from: Original, Manga,
Light novel, Game, … |
| status | string · null | Finished Airing, Currently Airing, or
Not yet aired. |
| rating | string · null | Content rating, e.g. PG-13 - Teens 13 or older. The literal string
None means MyAnimeList records no rating. |
| approved | boolean | Whether MyAnimeList has approved the entry. |
| airing | boolean | Whether it was airing when we last fetched the record. |
| episodes | integer · null | null when unknown (often for currently-airing or unaired entries). |
| duration | string · null |
Free-form upstream text, not a number:
24 min per ep, 1 hr 35 min, Unknown. Parse it
yourself if you need minutes.
|
| aired_from aired_to |
string · null |
Air-start / air-end date as YYYY-MM-DD. aired_to is
null for well over half of entries (single-episode works, and anything
still airing).
|
| season | string · null | winter, spring, summer or fall.
null together with year for entries with no seasonal slot.
|
| year | integer · null | The season's year. null exactly when season is. |
| genres explicit_genres themes demographics |
array of string |
Names only (the upstream ids and URLs are dropped; they are in /raw).
Empty [] rather than null.
|
| studios producers licensors |
array of string | Company names only. Empty [] rather than null. |
| synopsis | string · null | Plot summary, as written on MyAnimeList. |
| url | string · null | Canonical MyAnimeList permalink. It carries a title slug, so it is not derivable from
mal_id alone. |
| image_url | string · null |
A full cover-art URL on cdn.myanimelist.net (unlike AniDB's
picture, which is a bare filename). Fetch it from there, not through
this API.
|
| absent | boolean |
true when the entry has disappeared from MyAnimeList's catalogue since we
archived it. The record is kept and still served — that is when this mirror is most
useful. The flag clears if the entry reappears.
|
| absent_at | string · null | RFC 3339 timestamp of when the entry was first observed missing.
null whenever absent is false. |
No scores, ranks or member counts here.
score, scored_by, rank, popularity,
members and favorites move for nearly every title every time we
refresh it, so keeping them in the parsed projection would mean rewriting the whole table
continuously for numbers that are stale the moment they are served. They are still archived,
and /api/mal/{id}/raw returns them verbatim — just read them as a snapshot, not a
live figure.
Field reference — /api/anilist/{id}
| Field | Type | Notes |
|---|---|---|
| anilist_id | integer | The AniList id. Stable primary key. Unrelated to anidb_id and
mal_id. |
| id_mal | integer · null | AniList's own pointer to the matching MyAnimeList id — the one cross-link between
datasets, usable against /api/mal/{id}. null when AniList
records no mapping; not guaranteed unique (AniList and MAL split/merge differently). |
| title_romaji | string · null | AniList's canonical romaji title. Effectively always present. |
| title_english title_native |
string · null | title_english is null for about half of entries. |
| synonyms | array of string | Alternative titles. Empty [] when there are none, never null. |
| format | string · null | AniList's uppercase enum, verbatim: TV, TV_SHORT,
MOVIE, OVA, ONA, SPECIAL,
MUSIC. |
| status | string · null | FINISHED, RELEASING, NOT_YET_RELEASED,
CANCELLED, HIATUS. |
| source | string · null | What it was adapted from: ORIGINAL, MANGA,
LIGHT_NOVEL, VISUAL_NOVEL, VIDEO_GAME,
OTHER, … |
| country_of_origin | string · null | ISO 3166 country code: JP, CN, KR,
TW. |
| is_licensed | boolean | Whether AniList marks the title as officially licensed. |
| episodes | integer · null | null when unknown (often for currently-airing or unaired entries). |
| duration | integer · null | Runtime in minutes per episode, as a number (unlike MAL's free-form
duration string). null when unknown. |
| start_year start_month start_day end_year end_month end_day |
integer · null | Air-start / air-end date, as separate parts. AniList often knows only part of a date,
so each part is independently null — a year with a
null month and day is common. See the note below. |
| season | string · null | WINTER, SPRING, SUMMER or FALL.
null together with season_year for entries with no seasonal
slot. |
| season_year | integer · null | The premiere season's year. null exactly when season is. |
| description | string · null | Synopsis, as written on AniList. Contains HTML markup
(<br>, <i>, …) — render or strip it
yourself. |
| cover_image | string · null | Full cover-art URL on s4.anilist.co (the largest variant). Fetch it from there, not through this API. |
| banner_image | string · null | Full banner-image URL, or null (most entries have none). |
| genres tags |
array of string | Names only. tags drops each tag's id and relevance
rank (those are in /raw). Empty [] rather than
null. |
| studios producers |
array of string | Company names only. AniList keeps one studio list and flags each with
isAnimationStudio; studios is the animation studios,
producers the rest. Empty [] rather than null. |
| absent | boolean | true when the id has disappeared from AniList since we archived it
(usually a duplicate AniList merged away). The record is kept and still served — that
is when this mirror is most useful. The flag clears if the entry reappears. |
| absent_at | string · null | RFC 3339 timestamp of when the entry was first observed missing.
null whenever absent is false. |
AniList dates come in parts.
Unlike AniDB and MyAnimeList, which we fold into a single YYYY-MM-DD string,
AniList models a date as a year / month / day triple
where any part can be missing on its own — a show may have a known year but no month or day.
We keep those parts as-is (start_year, start_month,
start_day, and the end_* trio) so nothing is lost. Build a full date
only when all three parts are present; otherwise use whatever parts you have.
No scores, popularity or favourites here.
averageScore, meanScore, popularity and
favourites move for nearly every title every time we refresh it, so they are left
out of the parsed projection for the same reason as MAL's counters. They are still archived,
and /api/anilist/{id}/raw returns them verbatim — read them as a snapshot, not a
live figure.
Field reference — /api/ann/{id}
| Field | Type | Notes |
|---|---|---|
| ann_id | integer | The Anime News Network encyclopedia id. Stable primary key. Unrelated to
anidb_id, mal_id and anilist_id. |
| type | string · null | TV, OAV, movie, ONA,
special or omnibus. |
| precision | string · null | ANN's disambiguation label — TV, TV 2,
movie series, meta, … — which separates entries that
share a title. Distinct from type. |
| title | string · null | The ANN main title. |
| alternative_titles | array of string | Other titles ANN lists (across languages). Empty [] rather than
null. |
| genres themes |
array of string | ANN's genre and theme tags (lowercase). Empty [] rather than
null. |
| plot_summary | string · null | Plot summary, as written on ANN. null when ANN records none. |
| episodes | integer · null | null when unknown, or when ANN writes a non-numeric count (a few entries
say e.g. 12 (+ 2 specials)). The raw text is in /raw. |
| running_time | string · null | Free-form upstream text, not a number: half hour,
30 minutes. Parse it yourself if you need minutes. |
| vintage | array of string | Release dates/periods, free-form and multi-valued: a full date, a range
A to B, a bare year, or any of those with a parenthetical region. Empty
[] rather than null. See start_year for a
filterable year. |
| start_year | integer · null | Convenience: the leading 4-digit year of the first vintage.
null when it does not begin with a year. Not a substitute for
vintage. |
| objectionable_content | string · null | ANN's content code — TA, OC, AO,
AA, MA (upstream casing varies). null when ANN
records none. |
| official_websites | array of string | Official site URLs ANN lists. Empty [] rather than null. |
| picture | string · null | A full cover-art URL on cdn.animenewsnetwork.com. Fetch it
from there, not through this API. null when ANN has no picture. |
| url | string | The Anime News Network encyclopedia entry for this id (animenewsnetwork.com/encyclopedia/anime.php?id=<ann_id>). Always present. Keep it visible when you display the record — see Attribution below. |
| absent | boolean | true when ANN no longer serves this id. The record is kept and still
served — that is when this mirror is most useful. The flag clears if the entry
reappears. |
| absent_at | string · null | RFC 3339 timestamp of when the entry was first observed missing.
null whenever absent is false. |
Anime News Network requires attribution.
ANN's terms of
use ask that any page showing their encyclopedia details credit Anime News Network as the
source and link the relevant entry. Every /api/ann/{id} response carries that link
as url; if you display ANN data, surface it. The vote-based ratings
(in /raw) are a snapshot from our last fetch, not a live figure.
Field reference — /api/kitsu/{id}
| Field | Type | Notes |
|---|---|---|
| kitsu_id | integer | The Kitsu id. Stable primary key. Unrelated to anidb_id,
mal_id, anilist_id and ann_id. |
| slug | string · null | Kitsu's URL slug (cowboy-bebop). Not derivable from the id — it is what
builds url. |
| canonical_title | string · null | The title Kitsu itself displays. This is what /api/kitsu/ids returns as
title. |
| title_en title_en_jp title_ja_jp |
string · null |
The English, romaji and native titles. Kitsu stores titles as an open-ended
locale map, not a fixed set of fields, so these three are the common locales
pulled out by name; title_en is null for about half of
entries.
|
| other_titles | array of string | Every other locale's title (en_us, zh_cn,
ko_kr, …), so nothing in the locale map is lost. Empty
[] rather than null. |
| abbreviated_titles | array of string | Short forms and alternative spellings Kitsu lists. Empty [] rather than
null. |
| description | string · null | Synopsis, as written on Kitsu. Plain text (unlike AniList's, which carries HTML). |
| subtype | string · null | TV, movie, ONA, OVA,
special or music. Note the mixed casing — it is Kitsu's,
verbatim. |
| status | string · null | finished, current, upcoming,
unreleased or tba. |
| tba | string · null |
Kitsu's free-text note about an unannounced date — "2027",
"tba", a whole sentence. A string, not a boolean, despite
the name. null for most entries.
|
| age_rating | string · null | G, PG, R or R18. |
| age_rating_guide | string · null | Free-form gloss on the rating, e.g. 17+ (Violence & Profanity). |
| nsfw | boolean | Kitsu's adult flag — the anidb.restricted analogue. |
| episode_count | integer · null | null when unknown (often for currently-airing or unaired entries). |
| episode_length total_length |
integer · null |
Minutes per episode, and minutes for the whole run — real numbers, unlike MAL's
free-form duration string and ANN's running_time.
|
| start_date end_date |
string · null |
Air-start / air-end date as YYYY-MM-DD. Kitsu emits a full date or
nothing, so there is no partial-date caveat here (contrast AniDB's
startyear and AniList's split date parts).
|
| poster_image cover_image |
string · null |
Full image URLs on media.kitsu.io, the original size
only. The tiny/small/medium/large variants are in /raw. Fetch them from
there, not through this API.
|
| youtube_video_id | string · null | Bare YouTube id of the trailer, not a URL — build youtube.com/watch?v=<id> yourself. |
| url | string | The Kitsu entry for this id (kitsu.io/anime/<slug>,
falling back to kitsu.io/anime/<kitsu_id> when the slug
is null). Always present. Keep it visible when you display the record —
see Attribution below. |
| mal_id anilist_id anidb_id |
integer · null |
Kitsu's own cross-references, taken from its mappings — join them to
/api/mal/{id}, /api/anilist/{id} and
/api/anidb/{id}. Each is null when Kitsu records
no mapping to that service or more than one: an unambiguous
id, or nothing. There is no ann_id — Kitsu maps no Anime News Network ids
at all. Kitsu's mappings are community-editable, so treat them as a strong hint, not a
guarantee.
|
| absent | boolean | true when Kitsu no longer serves this id. The record is kept and still
served — that is when this mirror is most useful. The flag clears if the entry
reappears. |
| absent_at | string · null | RFC 3339 timestamp of when the entry was first observed missing.
null whenever absent is false. |
No ratings, user counts or ranks here.
averageRating, ratingFrequencies, userCount,
favoritesCount, popularityRank and ratingRank are left
out of the parsed projection for the same reason as MAL's and AniList's counters — and the two
ranks are worse than the rest, being global positions that shift for thousands of
titles whenever one of them gains a vote. They are still archived, and
/api/kitsu/{id}/raw returns them verbatim — read them as a snapshot, not a live
figure.
Field reference — /api/kitsu/{id}/episodes
The fields of one episode. The same object appears as an element of
/api/kitsu/{id}/episodes and as the whole body of
/api/kitsu/{id}/episodes/{episode_id} (which adds url, the anime's Kitsu
entry — the list carries it once, at the top level, rather than on every episode).
| Field | Type | Notes |
|---|---|---|
| kitsu_episode_id | integer | The episode's own Kitsu id — a different id space from
kitsu_id. Globally unique across all anime, so it is the key, but it only
resolves under its own anime's path. |
| kitsu_id | integer | The anime this episode belongs to — the id in the URL, repeated on every element so a
single episode lifted out of the array is still self-describing. Join it to
/api/kitsu/{id}. |
| canonical_title | string · null | The title Kitsu itself displays for the episode. Often null for
never-localised entries, and frequently just "Episode 12". |
| title_en_us title_en_jp title_ja_jp |
string · null |
Note the en_us. Episodes key their locale map differently
from the anime resource: an anime has en / en_jp /
ja_jp (hence title_en on /api/kitsu/{id}), an
episode has en_us / en_jp / ja_jp. That is
Kitsu's, not ours — an episode has no en title at all, so do not expect a
title_en here.
|
| other_titles | array of string | Every other locale's title, so nothing in the locale map is lost. Empty
[] rather than null. |
| description | string · null | The episode synopsis. Kitsu also carries a synopsis field, but it was
identical to this one in every episode we compared, so only this one is projected —
both are in /api/kitsu/{id}/episodes/raw if you want to check. |
| season_number | integer · null | Kitsu's own seasoning of the series, not a broadcast season. Most series are all season 1; a few use it to split long runs. |
| number relative_number |
integer · null |
The absolute episode number within the series, and the number within its season. Both
are nullable and neither is unique — they are community-entered, and
duplicates and gaps exist. Sort on them for display (that is the order this route
returns), but key on kitsu_episode_id.
|
| airdate | string · null | First broadcast, YYYY-MM-DD. null for unaired episodes and
for a great many older ones nobody has filled in. |
| length_minutes | integer · null | Runtime in minutes (Kitsu's length). null when unknown. |
| thumbnail | string · null | Full image URL on media.kitsu.io, the original size only. Fetch it from there, not through this API. |
| url | string | Only on /api/kitsu/{id}/episodes/{episode_id}. The Kitsu
entry for the anime (Kitsu has no public per-episode page). On the list route
the same link sits once at the top level. Keep it visible when you display the record
— see Attribution below. |
Errors
Errors are JSON with the matching HTTP status:
{"error": "not found"}
400— the{id}is not a positive integer.404— no such id, its payload has not been fetched, or an unknown path (including/api/mal/{id}/raw/xml,/api/anilist/{id}/raw/xml,/api/ann/{id}/raw/xmland/api/kitsu/{id}/raw/xml, which do not exist).405— wrong HTTP method (onlyGET/HEADare served).500— something broke on our side; the detail is logged, not returned.