AniPub API
Anime metadata, streaming links, MAL integration, characters & voice actors — all from one clean, free API.
/api/info/:idinteger or slug like one-piece/api/find/:namecheck existence + episode count/api/findbyGenre/:genre?Page=2paginated genre results/api/findbyrating?page=1top-rated, paginated/api/search/:namequick search · flat array/api/searchall/:name?page=1paginated full search/api/checkname + genre match checkIntroduction
All responses are JSON. CORS is enabled so you can call directly from the browser. Standard HTTP status codes. No API key needed.
ImagePath or Cover don't begin with https://, prepend https://anipub.xyz/ to build the full URL./api/info/:id accepts an integer or a slug. Slugs use lowercase, spaces become -, no special characters. Examples: one-piece, black-clover, high-school-dxd, date-a-live-iv.Error Codes
| Status | Name | Description |
|---|---|---|
| 200 | OK | Request succeeded — JSON returned |
| 400 | Bad Request | Missing or invalid parameters |
| 404 | Not Found | No anime with that ID or name |
| 500 | Server Error | Internal error — retry |
/api/info/:id
Get Anime Info
Full metadata for one anime. :id is an integer or a kebab-case slug (spaces → hyphens, no special chars, lowercase).
/api/info/61 · /api/info/black-clover · /api/info/one-piece · /api/info/high-school-dxd61 or slug like black-clover
async function getAnimeInfo(idOrSlug) {
// idOrSlug can be: 61 OR "black-clover" OR "one-piece"
const res = await fetch(`https://anipub.xyz/api/info/${idOrSlug}`);
if (!res.ok) throw new Error(res.status);
const d = await res.json();
// Resolve relative image paths
const fix = p => p?.startsWith('https://') ? p : `https://anipub.xyz/${p}`;
d.ImagePath = fix(d.ImagePath);
d.Cover = fix(d.Cover);
return d;
}
// By ID
await getAnimeInfo(61);
// By slug (spaces → hyphens, lowercase, no special chars)
await getAnimeInfo('black-clover');
await getAnimeInfo('one-piece');
await getAnimeInfo('high-school-dxd');
import requests
def get_anime_info(id_or_slug):
# Works with int ID or slug string
r = requests.get(f"https://anipub.xyz/api/info/{id_or_slug}")
r.raise_for_status()
d = r.json()
for k in ("ImagePath", "Cover"):
if d.get(k) and not d[k].startswith("https://"):
d[k] = f"https://anipub.xyz/{d[k]}"
return d
print(get_anime_info(61)["Name"]) # integer ID
print(get_anime_info("one-piece")["Name"]) # slug
function getAnimeInfo($idOrSlug) {
$url = "https://anipub.xyz/api/info/" . $idOrSlug;
$data = json_decode(file_get_contents($url), true);
foreach (['ImagePath', 'Cover'] as $k)
if (!str_starts_with($data[$k] ?? '', 'https://'))
$data[$k] = 'https://anipub.xyz/' . $data[$k];
return $data;
}
print_r(getAnimeInfo(61)); // integer
print_r(getAnimeInfo('one-piece')); // slug
# Integer ID
curl "https://anipub.xyz/api/info/61"
# Slug — lowercase, hyphens for spaces, no special chars
curl "https://anipub.xyz/api/info/black-clover"
curl "https://anipub.xyz/api/info/one-piece"
curl "https://anipub.xyz/api/info/high-school-dxd"
curl "https://anipub.xyz/api/info/one-piece" | jq '.'
type AnimeInfo struct {
ID int `json:"_id"`
Name string `json:"Name"`
ImagePath string `json:"ImagePath"`
MALScore string `json:"MALScore"`
Genres []string `json:"Genres"`
Status string `json:"Status"`
EpCount int `json:"epCount"`
}
// idOrSlug: "61" or "black-clover"
resp, _ := http.Get("https://anipub.xyz/api/info/black-clover")
defer resp.Body.Close()
var a AnimeInfo
json.NewDecoder(resp.Body).Decode(&a)
if !strings.HasPrefix(a.ImagePath, "https://") {
a.ImagePath = "https://anipub.xyz/" + a.ImagePath
}
require 'net/http'; require 'json'
def get_info(id_or_slug)
d = JSON.parse(Net::HTTP.get(URI(
"https://anipub.xyz/api/info/#{id_or_slug}"
)))
['ImagePath', 'Cover'].each { |k|
d[k] = "https://anipub.xyz/#{d[k]}" unless d[k].to_s.start_with?('https://') }
d
end
p get_info(61)['Name']
p get_info('one-piece')['Name']
{
"_id": 61,
"Name": "Black Clover",
"ImagePath": "https://...", // prepend https://anipub.xyz/ if relative
"Cover": "https://...",
"Synonyms": "...",
"Aired": "Oct 3, 2017 to Mar 30, 2021",
"Premiered": "Fall 2017",
"RatingsNum": 45,
"Genres": ["action", "fantasy", "magic"],
"Studios": "Pierrot",
"DescripTion": "...",
"Duration": "25m",
"MALScore": "8.88",
"Status": "Finished Airing",
"epCount": 170
}
/api/getAllGet Total Count
Returns a plain integer — total anime in the database. Use to determine valid ID range for /api/info/:id.
const total = await (await fetch('https://anipub.xyz/api/getAll')).json();
console.log(`${total} anime — IDs 1 to ${total}`);
total = requests.get("https://anipub.xyz/api/getAll").json()
print(f"Total: {total}")
curl "https://anipub.xyz/api/getAll"
# → 153
$n = json_decode(file_get_contents('https://anipub.xyz/api/getAll'));
echo "Total: $n";
/api/find/:nameFind Anime by Name
Check if an anime exists. Returns {"exist":true,"id":10,"ep":1155} or {"exist":false}.
%20const findAnime = async name => (await fetch(
`https://anipub.xyz/api/find/${encodeURIComponent(name)}`
)).json();
const r = await findAnime('One Piece');
// → { exist: true, id: 10, ep: 1155 }
if (r.exist) {
const info = await fetch(`https://anipub.xyz/api/info/${r.id}`).then(x => x.json());
}
from urllib.parse import quote
r = requests.get(f"https://anipub.xyz/api/find/{quote('One Piece')}").json()
if r["exist"]:
print(f"ID={r['id']} ep={r['ep']}")
curl "https://anipub.xyz/api/find/One%20Piece"
# → {"exist":true,"id":10,"ep":1155}
curl "https://anipub.xyz/api/find/Does%20Not%20Exist"
# → {"exist":false}
type FindResult struct { Exist bool `json:"exist"`; ID int `json:"id"`; Ep int `json:"ep"` }
resp, _ := http.Get("https://anipub.xyz/api/find/" + url.PathEscape("One Piece"))
var r FindResult
json.NewDecoder(resp.Body).Decode(&r)
/v1/api/details/:idStreaming Links
Returns iframe streaming links per episode. Strip the src= prefix from each link value to get the raw iframe URL.
local.link (top-level) = Episode 1. The local.ep[] array starts from Episode 2 onwards — so ep array index 0 = EP 2, index 1 = EP 3, etc._id may be a MongoDB ObjectId string — deprecated. Use the URL :id parameter as the canonical identifier.const { local } = await (await fetch(
'https://anipub.xyz/v1/api/details/119'
)).json();
const src = link => link.replace('src=', '');
// EP 1 — top-level link (NOT in the ep array)
iframeEl.src = src(local.link);
// EP 2, 3, 4... — ep[] array starts at episode 2
const allEps = [
{ ep: 1, src: src(local.link) }, // EP 1
...local.ep.map((e, i) => ({ ep: i+2, src: src(e.link) })) // EP 2+
];
local = requests.get("https://anipub.xyz/v1/api/details/119").json()["local"]
# EP 1 is the top-level link, NOT inside ep[]
ep1 = local["link"].replace("src=", "")
print(f"EP1: {ep1}")
# EP 2, 3, 4... — ep[] array begins at episode 2
for i, ep in enumerate(local["ep"], 2):
print(f"EP{i}: {ep['link'].replace('src=','')}")
curl "https://anipub.xyz/v1/api/details/119" | \
jq '.local.ep[].link | ltrimstr("src=")'
$local = json_decode(file_get_contents(
'https://anipub.xyz/v1/api/details/119'
), true)['local'];
foreach ($local['ep'] as $i => $ep)
echo "EP".($i+1).": ".str_replace('src=','',$ep['link'])."\n";
{
"local": {
"name": "Black Clover",
"link": "src=https://...", // ← strip "src=" → EP 1 iframe src
"ep": [
{ "link": "src=https://..." }, // ep[0] = EP 2
{ "link": "src=https://..." }, // ep[1] = EP 3
"..."
]
}
}
/anime/api/details/:idFull Details + MAL + Characters
Returns local (metadata), jikan (MAL data), and characters (cast + voice actors). The most complete endpoint.
const { local, jikan, characters } = await (await fetch(
'https://anipub.xyz/anime/api/details/119'
)).json();
const fix = p => p?.startsWith('https://') ? p : `https://anipub.xyz/${p}`;
console.log(local.Name, local.MALScore);
console.log(jikan?.synopsis);
characters.forEach(c => {
console.log(c.character.name, c.role);
c.voice_actors.forEach(va => console.log(' VA:', va.person.name, va.language));
});
data = requests.get("https://anipub.xyz/anime/api/details/119").json()
local, chars = data["local"], data["characters"]
print(local["Name"], local["MALScore"])
for c in chars:
print(f" {c['character']['name']} — {c['role']}")
curl "https://anipub.xyz/anime/api/details/119" | jq '.'
curl "https://anipub.xyz/anime/api/details/119" | \
jq '.characters[] | {name:.character.name, role}'
var res struct {
Local struct{ Name string `json:"Name"` } `json:"local"`
Characters []struct{
Character struct{ Name string `json:"name"` } `json:"character"`
Role string `json:"role"`
} `json:"characters"`
}
json.NewDecoder(resp.Body).Decode(&res)
/api/findbyGenre/:genreBrowse by Genre
Paginated anime list by genre. Add ?Page=2 for next pages. Response: {"currentPage":1,"wholePage":[...]}.
harem, action, romance1. Append ?Page=2.const findByGenre = async (genre, page = 1) => {
const data = await (await fetch(
`https://anipub.xyz/api/findbyGenre/${genre}?Page=${page}`
)).json();
console.log(`Page ${data.currentPage} — ${data.wholePage.length} results`);
return data.wholePage;
};
findByGenre('harem'); // page 1
findByGenre('harem', 2); // page 2
findByGenre('action', 3); // page 3
def find_by_genre(genre, page=1):
d = requests.get(
f"https://anipub.xyz/api/findbyGenre/{genre}?Page={page}"
).json()
return d["wholePage"]
for a in find_by_genre("harem"):
print(f"[{a['_id']}] {a['Name']} — {a['MALScore']}")
curl "https://anipub.xyz/api/findbyGenre/harem"
curl "https://anipub.xyz/api/findbyGenre/harem?Page=2"
curl "https://anipub.xyz/api/findbyGenre/action" | jq '.wholePage[].Name'
$data = json_decode(file_get_contents(
"https://anipub.xyz/api/findbyGenre/harem?Page=1"
), true);
foreach ($data['wholePage'] as $a)
echo $a['Name'] . " — " . $a['MALScore'] . "\n";
/api/checkCheck Name & Genre
Verifies an anime exists by name and genre. Genre accepts a string or an array of strings.
"Action" or ["Action","Drama"]const checkAnime = async (name, genre) => (await fetch('https://anipub.xyz/api/check', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ Name: name, Genre: genre })
})).json();
checkAnime('Black Clover', 'Action');
checkAnime('Jujutsu Kaisen', ['Action', 'Drama']);
res = requests.post("https://anipub.xyz/api/check", json={
"Name": "Jujutsu Kaisen", "Genre": ["Action", "Drama"]
}).json()
curl -X POST "https://anipub.xyz/api/check" \
-H "Content-Type: application/json" \
-d '{"Name":"Black Clover","Genre":["Action","Fantasy"]}'
$ch = curl_init('https://anipub.xyz/api/check');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(['Name'=>'Black Clover','Genre'=>['Action']]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
]);
const { data } = await axios.post('https://anipub.xyz/api/check', {
Name: 'Jujutsu Kaisen', Genre: ['Action', 'Drama']
});
/api/findbyratingBrowse by Rating
Returns a paginated list of top-rated anime, sorted by MAL score descending. Use ?page=2 to navigate pages.
1. Append ?page=2, ?page=3…const getTopRated = async (page = 1) => {
const data = await (await fetch(
`https://anipub.xyz/api/findbyrating?page=${page}`
)).json();
// data.AniData — array of anime
// data.currentPage — current page number
return data;
};
const p1 = await getTopRated(); // page 1
const p2 = await getTopRated(2); // page 2
p1.AniData.forEach(a => console.log(a.Name, a.MALScore));
def get_top_rated(page=1):
d = requests.get(f"https://anipub.xyz/api/findbyrating?page={page}").json()
return d.get("AniData", [])
for a in get_top_rated():
print(f"{a['Name']} — {a['MALScore']}")
curl "https://anipub.xyz/api/findbyrating"
curl "https://anipub.xyz/api/findbyrating?page=2"
curl "https://anipub.xyz/api/findbyrating?page=1" | jq '.AniData[].Name'
{
"currentPage": 1,
"AniData": [
{
"_id": 2454,
"Name": "Frieren: Beyond Journey's End",
"ImagePath": "https://...",
"MALScore": "9.36",
"RatingsNum": 50,
"DescripTion": "...",
"finder": "frieren-beyond-journeys-end"
}
]
}
/api/search/:nameQuick Search
Fast search by anime name. Returns a flat array of matching results — ideal for autocomplete, search boxes, and quick lookups. No pagination.
%20const quickSearch = async (query) => (await fetch(
`https://anipub.xyz/api/search/${encodeURIComponent(query)}`
)).json();
const results = await quickSearch('One Piece');
// → [ { Name, Id, Image, finder }, ... ]
// Great for a live search input
searchInput.addEventListener('input', async (e) => {
if (e.target.value.length < 2) return;
const hits = await quickSearch(e.target.value);
renderDropdown(hits);
});
from urllib.parse import quote
results = requests.get(
f"https://anipub.xyz/api/search/{quote('One Piece')}"
).json()
for r in results:
print(f"[{r['Id']}] {r['Name']}")
curl "https://anipub.xyz/api/search/One%20Piece"
curl "https://anipub.xyz/api/search/Attack%20on%20Titan" | jq '.[].Name'
$results = json_decode(file_get_contents(
"https://anipub.xyz/api/search/" . rawurlencode("One Piece")
), true);
foreach ($results as $r)
echo $r['Name'] . " (ID: " . $r['Id'] . ")\n";
[
{
"Name": "One Piece",
"Id": 10,
"Image": "One-Piece.jpg", // prepend https://anipub.xyz/ if relative
"finder": "one-piece"
},
{ "Name": "One Piece Film Red", "Id": 15, ... }
]
/api/searchall/:nameSearch All (Paginated)
Full paginated search across all anime. Returns AniData array and currentPage. Use ?page=2 to navigate. More results than /api/search.
%201. Append ?page=2.const searchAll = async (query, page = 1) => (await fetch(
`https://anipub.xyz/api/searchall/${encodeURIComponent(query)}?page=${page}`
)).json();
const r = await searchAll('One Piece');
// r.AniData — array of full anime objects
// r.currentPage — current page
r.AniData.forEach(a =>
console.log(`[${a._id}] ${a.Name} — ${a.MALScore}`)
);
def search_all(query, page=1):
return requests.get(
f"https://anipub.xyz/api/searchall/{quote(query)}?page={page}"
).json()
r = search_all("One Piece")
for a in r.get("AniData", []):
print(f"[{a['_id']}] {a['Name']} — {a['MALScore']}")
curl "https://anipub.xyz/api/searchall/One%20Piece"
curl "https://anipub.xyz/api/searchall/One%20Piece?page=2"
curl "https://anipub.xyz/api/searchall/naruto" | jq '.AniData[].Name'
$d = json_decode(file_get_contents(
"https://anipub.xyz/api/searchall/" . rawurlencode("One Piece") . "?page=1"
), true);
foreach ($d['AniData'] as $a)
echo $a['Name'] . " — " . $a['MALScore'] . "\n";
{
"currentPage": 1,
"AniData": [
{
"_id": 10,
"Name": "One Piece",
"ImagePath": "One-Piece.jpg",
"MALScore": "8.72",
"RatingsNum": 50,
"DescripTion": "...",
"finder": "one-piece"
}
]
}
⚡ Playground
Fire any request directly. Supports GET and POST.
🎌 Genre Browser
Click any tag to instantly fetch and display live API results.