Using the API
The dataset is served read-only by a Connect RPC
service. You can call it with an ordinary HTTP POST and a JSON body — no client
library or codegen required.
Your first call
curl -X POST https://anime-metadata-db.vercel.app/anime.v1.AnimeService/GetHealth \
-H 'Content-Type: application/json' -d '{}'{"status":"ok","version":"<commit>","stats":{"franchises":1,"series":3,"seasons":9,"episodes":124}}That’s the whole contract: POST a JSON body to
/{package}.{Service}/{Method}, get JSON back.
Endpoint
POST https://anime-metadata-db.vercel.app/anime.v1.AnimeService/{Method}
Content-Type: application/jsonhttps://anime-metadata-db.vercel.app is the hosted public instance. To run your
own, start the server locally (go run ./cmd/api, see
Building the dataset) and use
http://localhost:8080 instead — the paths are identical.
Methods
| Method | Body | Returns |
|---|---|---|
GetHealth | {} | liveness, build version, dataset stats |
ListFranchises | {} | every multi-series franchise, fully nested |
GetFranchise | {"id": "..."} | one franchise with its nested series |
GetSeries | {"id": "..."} | one series (standalone or under a franchise) |
Search | {"query": "...", "limit": 10} | matching franchises and series |
GetCharacter | {"id": "..."} | one character with every appearance and its cast |
ListCharacters | {"seriesId": "...", "limit": 10} | the whole cast, or one series’ cast |
GetStaff | {"id": "..."} | one staff member with the characters they voice |
ListStaff | {"language": "ja", "limit": 10} | staff, optionally by credited language |
ListFranchises returns only multi-series franchises; a standalone series is
reachable through Search and GetSeries. For Search, limit is optional
(defaults to 50) and a blank query matches nothing. For the two list methods
limit defaults to 100; an unknown seriesId is a not_found error rather than
an empty list, so a typo is not mistaken for a series with no cast.
Examples
Search — case-insensitive substring over titles:
curl -X POST https://anime-metadata-db.vercel.app/anime.v1.AnimeService/Search \
-H 'Content-Type: application/json' -d '{"query": "demon", "limit": 5}'{"results":[{"kind":"ENTRY_KIND_SERIES","id":"demon-slayer","title":"Demon Slayer"}]}Fetch one series with its full structure — the id comes from a search result:
curl -X POST https://anime-metadata-db.vercel.app/anime.v1.AnimeService/GetSeries \
-H 'Content-Type: application/json' -d '{"id": "demon-slayer"}'{
"series": {
"id": "demon-slayer",
"title": "Demon Slayer",
"seasons": [
{
"id": "demon-slayer-s1",
"number": 1,
"releaseYear": 2019,
"releaseSeason": "RELEASE_SEASON_SPRING",
"externalIds": {"anilistId": 101922, "anidbId": 14107, "tvdbId": 348545},
"episodes": [
{"absoluteNumber": 1, "airedNumber": 1},
{"absoluteNumber": 2, "airedNumber": 2}
]
}
],
"movies": [
{"id": "demon-slayer-mugen-train-film", "title": "Mugen Train", "releaseYear": 2020}
]
}
}A Franchise nests series, which nests seasons, movies and specials,
each carrying episodes. Dates are YYYY-MM-DD strings; externalIds
cross-maps each node to AniList, AniDB, TMDB, TVDB and Wikidata. Field names in
the JSON are camelCase (releaseYear, externalIds, absoluteNumber). See
Using the dataset for the full model.
Characters and staff
Characters and staff are global nodes, not children of a series. A character
attaches onto the structure through its appearances, so the same node is
reachable three ways — nested in a series’ characters, by id from
GetCharacter, and as a credit from GetStaff — and it always carries every
series it appears in:
curl -X POST https://anime-metadata-db.vercel.app/anime.v1.AnimeService/GetCharacter \
-H 'Content-Type: application/json' -d '{"id": "artoria-pendragon"}'{
"character": {
"id": "artoria-pendragon",
"externalIds": {"wikidataId": "Q4918886"},
"voiceActors": [
{"staffId": "ayako-kawasumi", "language": "ja"}
],
"appearances": [
{"seriesId": "fate-stay-night"},
{"seriesId": "fate-zero"}
]
}
}That response has no name or staffName, and it is not a bug: names are
filled from Wikidata at build time, and the committed dataset was built
without the Wikidata fetch. Run builder init before builder build and the
same call returns "name": "Artoria Pendragon" on the character and
"staffName": "Ayako Kawasumi" on each voice-actor link. Every other field is
independent of it, so the graph is fully usable by id either way.
voiceActors on the character is the default cast; an appearance may carry
its own voiceActors to override it for that series, and a scope to narrow it
to specific seasons, movies or specials. Each link repeats the staff member’s
resolved staffName, so rendering a cast list needs no second call.
GetStaff is the inverse — the characters a person is cast as, with the
language and the series each casting covers:
curl -X POST https://anime-metadata-db.vercel.app/anime.v1.AnimeService/GetStaff \
-H 'Content-Type: application/json' -d '{"id": "ayako-kawasumi"}'{
"staff": {"id": "ayako-kawasumi", "externalIds": {"wikidataId": "Q49566"}},
"credits": [
{
"characterId": "artoria-pendragon",
"language": "ja",
"seriesIds": ["fate-stay-night", "fate-zero"]
}
]
}One credit is emitted per character and language, listing every series the casting covers — so a voice actor who plays the same character across a whole franchise appears once, not once per series.
Names follow the same Accept-Language rules as titles, via name and (with
Accept-Language: *) localizedName.
Only facts are served: ids, names, and the appearance and voice-actor graph. Roles, biographies and images are deliberately absent; fetch those live from the external ids.
Localized titles
Every title-bearing node returns a single title string, resolved from the
request’s Accept-Language header (default en). For each title, resolution
tries, in order:
- the requested language,
- for a non-English request, the native
original, - English,
- the native
original, - any available translation.
# Japanese titles where available, else the native original → "鬼滅の刃":
curl -X POST https://anime-metadata-db.vercel.app/anime.v1.AnimeService/GetSeries \
-H 'Content-Type: application/json' -H 'Accept-Language: ja' \
-d '{"id": "demon-slayer"}'Send Accept-Language: * to additionally receive the full localizedTitle (the
native original plus every translation) on every node.
Scope. The API serves the structural catalog — franchises, series, seasons, movies, specials and episodes. Characters and staff are present in the committed dataset but not yet exposed over the API.
Next: Using the dataset — the same data as committed YAML, and the full model.