Want to build a manga reader, a tracking app, or a Discord bot that posts new chapters? This free manga API gives you search, chapter lists, and page images over plain REST — no signup, no API key. Every example below was tested live against the real API.
Base: https://ahm7xmakki.com/api/manga
Auth: none. Reader UI: ahm7xmakki.com/manga
Flow: search → chapters → pages (three calls, that's the whole API).
| Action | Request | Returns |
|---|---|---|
search | ?action=search&q=naruto | Titles with covers, genres, status, sourceId |
chapters | ?action=chapters&id=SOURCE_ID | Chapter list with chapterId per chapter |
pages | ?action=pages&id=CHAPTER_ID | Ordered page-image URLs |
latest | ?action=latest | Recently updated titles |
curl "https://ahm7xmakki.com/api/manga?action=search&q=berserk"
Response (trimmed):
{
"success": true,
"query": "berserk",
"count": 3,
"results": [
{
"name": "Berserk",
"cover": "/api/manga?action=img&p=imgs%2Fcover%2F...",
"sourceId": "berserk.43",
"status": "Ongoing",
"genres": ["Action", "Adventure", "Drama", "Fantasy", "Horror"]
}
]
}
Two fields matter for the next steps: sourceId (feed it to chapters) and cover (a relative path — prefix it with https://ahm7xmakki.com).
curl "https://ahm7xmakki.com/api/manga?action=chapters&id=berserk.43"
{
"success": true,
"chapters": [
{ "chapterId": "berserk.43/chapter-364", "name": "Chapter 364", "date": "..." },
{ "chapterId": "berserk.43/chapter-363", "name": "Chapter 363", "date": "..." }
]
}
Chapters come newest-first. Grab the chapterId of the one you want to read.
curl "https://ahm7xmakki.com/api/manga?action=pages&id=berserk.43/chapter-364"
{
"success": true,
"pages": [
"https://.../page-001.jpg",
"https://.../page-002.jpg"
]
}
Render the pages array in order and you have a working reader. That's the entire API — three endpoints.
const API = "https://ahm7xmakki.com/api/manga";
async function searchManga(q) {
const r = await fetch(`${API}?action=search&q=${encodeURIComponent(q)}`);
return (await r.json()).results;
}
async function getChapters(sourceId) {
const r = await fetch(`${API}?action=chapters&id=${encodeURIComponent(sourceId)}`);
return (await r.json()).chapters;
}
async function getPages(chapterId) {
const r = await fetch(`${API}?action=pages&id=${encodeURIComponent(chapterId)}`);
return (await r.json()).pages;
}
// Read the latest chapter of a search result:
const [title] = await searchManga("one piece");
const [latest] = await getChapters(title.sourceId);
const pages = await getPages(latest.chapterId);
pages.forEach(src => {
const img = document.createElement("img");
img.src = src; img.loading = "lazy"; img.style.maxWidth = "100%";
document.getElementById("reader").appendChild(img);
});
Building a "new chapters" notifier? Poll ?action=latest on a schedule and diff against the last chapter IDs you saw:
import requests, time
seen = set()
while True:
data = requests.get("https://ahm7xmakki.com/api/manga?action=latest",
timeout=30).json()
for item in data.get("results", []):
key = (item["sourceId"], item.get("latestChapter"))
if key not in seen:
seen.add(key)
print("NEW:", item["name"], "-", item.get("latestChapter"))
time.sleep(600) # check every 10 minutes
loading="lazy" so readers don't download 40 images at once.429 means slow down — add backoff, don't retry in a tight loop.Search results include a cover path like /api/manga?action=img&p=imgs%2Fcover%2F.... It's relative — prefix it with the origin to get a full URL:
const coverUrl = "https://ahm7xmakki.com" + result.cover;
Results also include a path such as /manga/naruto.1205 — that's the hosted reader URL for the title, handy if you want a "read on AHM7" fallback link next to your own reader. The reader even supports query shortcuts: /manga?naruto jumps straight to search.
A good reader needs prev/next chapter buttons and keyboard shortcuts. Since chapters returns newest-first, index math is simple:
let chapters = await getChapters(sourceId); // newest first
let idx = 0; // start at latest
async function showChapter(i) {
idx = Math.max(0, Math.min(chapters.length - 1, i));
const pages = await getPages(chapters[idx].chapterId);
const reader = document.getElementById("reader");
reader.innerHTML = "";
pages.forEach(src => {
const img = document.createElement("img");
img.src = src; img.loading = "lazy";
img.style.cssText = "max-width:100%;display:block;margin:0 auto";
reader.appendChild(img);
});
document.getElementById("chName").textContent = chapters[idx].name;
window.scrollTo(0, 0);
}
document.getElementById("prev").onclick = () => showChapter(idx - 1); // newer
document.getElementById("next").onclick = () => showChapter(idx + 1); // older
document.addEventListener("keydown", e => {
if (e.key === "ArrowLeft") showChapter(idx - 1);
if (e.key === "ArrowRight") showChapter(idx + 1);
});
The ?action=latest feed is global, but users usually follow specific series. Store the first chapterId per sourceId and re-check on an interval:
async function hasNewChapter(sourceId, knownFirstId) {
const chapters = await getChapters(sourceId);
return chapters.length && chapters[0].chapterId !== knownFirstId
? chapters[0]
: null;
}
// usage
const fresh = await hasNewChapter("berserk.43", savedId);
if (fresh) notifyUser("Berserk", fresh.name);
How many titles are in the catalog? Thousands, across genres from shounen to slice-of-life. Search is the fastest way to check coverage for the series you care about.
Why do some chapters return no pages? Source gaps happen — a chapter may be listed but its images unavailable. Show a friendly "pages unavailable" state and let the user pick another chapter.
Can I hotlink the page images? They work as <img> sources. For heavy traffic, proxy or cache them on your own CDN to be a good citizen.
Is there a rate limit? Yes, per IP like the other AHM7 APIs. A 429 means back off and retry with delays.
The hosted reader uses this exact API — search anything to see it in action:
For the rest of the free toolkit, see the 10 best free APIs roundup and the full API docs.