Files
MiruroAPI/README.md
T

28 KiB

Stars Forks Issues Pull Requests Last Commit License

Node.js Express AniList GraphQL Vercel License Version Endpoints Providers

Free RESTful API for anime streaming data powered by AniList GraphQL and Miruro providers.
Search, browse, filter, watch — every endpoint returns fresh data with smart caching.
18 endpoints, 12 streaming providers, M3U8 URLs with subtitles and skip timestamps.

Table of Contents • Features • API Docs • Quick Start • Deployment • Contributing


Disclaimer

  1. This API does not store any files — it only links to media hosted on 3rd party services.
  2. This API is explicitly made for educational purposes only and not for commercial usage. This repo will not be responsible for any misuse of it.
  3. All anime data, images, and content belong to their respective owners (AniList, Miruro). This project is not affiliated with miruro.tv.

Table of Contents


Overview

MiruroAPI is a serverless anime data API that fetches real-time information from AniList GraphQL and streaming data from Miruro providers — including anime details, episode lists, M3U8 streaming URLs with subtitles and skip timestamps, search, filtering, characters, and more — all through a clean REST API with zero database.

No database, no auth, no complex setup. Just deploy to Vercel and you have a production API.

Why MiruroAPI?

  • 18 Endpoints — Complete anime data coverage
  • AniList GraphQL — Rich metadata: scores, characters, relations, recommendations
  • 12 Streaming Providers — kiwi, pewe, bee, bonk, bun, ally, nun, twin, cog, moo, hop, telli
  • M3U8 URLs — Direct streaming links with resolution, codec, fansub info
  • Skip Timestamps — OP/ED skip data for supported anime
  • Smart Caching — In-memory Map with TTL reduces API load
  • CORS Enabled — Works from any frontend, no proxy needed
  • Swagger UI — Interactive API documentation at /docs
  • Docker Ready — One-command containerized deployment

How It Works

flowchart TD
    A["Client Request<br/>(Browser / App / curl)"] --> B["Express Server<br/>CORS - Security Headers"]
    B --> C{"Cache Check<br/>(In-Memory Map)"}
    C -- HIT --> D["Return Cached<br/>~50ms"]
    C -- MISS --> E{"Which Source?"}
    
    E -- Metadata --> F["AniList GraphQL<br/>graphql.anilist.co"]
    E -- Streaming --> G["Miruro Pipe<br/>miruro.tv/api/secure/pipe"]
    
    F --> H["AniList Response<br/>JSON"]
    G --> I["Pipe Response<br/>base64url + gzip"]
    
    H --> J["Cache + Respond"]
    I --> J
    
    style A fill:#0f172a,stroke:#38bdf8,color:#e2e8f0
    style B fill:#0f172a,stroke:#818cf8,color:#e2e8f0
    style C fill:#0f172a,stroke:#f43f5e,color:#e2e8f0
    style D fill:#0f172a,stroke:#22c55e,color:#e2e8f0
    style E fill:#0f172a,stroke:#a855f7,color:#e2e8f0
    style F fill:#0f172a,stroke:#02a6e4,color:#e2e8f0
    style G fill:#0f172a,stroke:#eab308,color:#e2e8f0
    style H fill:#0f172a,stroke:#06b6d4,color:#e2e8f0
    style I fill:#0f172a,stroke:#eab308,color:#e2e8f0
    style J fill:#0f172a,stroke:#22c55e,color:#e2e8f0

Features

Core

  • AniList GraphQL for rich metadata

  • Miruro pipe for streaming sources

  • Smart caching with configurable TTL

  • 18 RESTful endpoints

  • Graceful error handling per endpoint

  • Rate limiting (100 req/min per IP)

Data

  • Full-text search with pagination

  • Autocomplete suggestions for search

  • Advanced filtering — genre, year, season, format, sort

  • Characters with voice actors

  • Relations and Recommendations

  • Airing schedule by date

Streaming

  • Episode lists from 12 providers

  • M3U8 streaming URLs with resolution info

  • Skip timestamps (OP/ED)

  • Download links when available

  • Sub/Dub support per provider

  • Codec and fansub metadata

Reliability

  • CORS enabled — works from any frontend

  • Error responses with descriptive messages

  • Input validation — required params checked

  • Timeout protection — per request

  • In-memory caching — survives warm starts

  • Zero database — pure API + cache

Feature Highlights

Feature Description Status
18 API Endpoints Complete anime data coverage Done
AniList GraphQL Rich metadata from AniList Done
12 Streaming Providers M3U8 streaming sources Done
Full-Text Search Keyword search with pagination Done
Autocomplete Suggestions Fast search suggestions Done
Advanced Filtering Genre, year, season, format, sort Done
Characters + Voice Actors Full character data from AniList Done
Relations & Recommendations Related anime discovery Done
Skip Timestamps OP/ED skip data Done
Smart Caching In-memory Map with TTL Done
Swagger UI Docs Interactive API documentation Done
Docker Support Containerized deployment Done

Data Sources

Metadata Source

Source API Data
AniList graphql.anilist.co Search, info, characters, relations, recommendations, filter, schedule

Streaming Source

Source Domain Data
Miruro miruro.tv Episodes, streaming sources (M3U8 URLs)
Miruro miruro.to Mirror domain
Miruro miruro.bz Mirror domain
Miruro miruro.ru Mirror domain

Streaming Providers

Provider Provider Provider Provider
kiwi pewe bee bonk
bun ally nun twin
cog moo hop telli

Tech Stack

Technology Purpose Version
Node.js JavaScript runtime >= 20
Express HTTP server framework 4.21
AniList GraphQL Anime metadata API —
Axios HTTP client 1.8
Vercel Functions Serverless deployment —
cors CORS middleware 2.8
dotenv Environment variables 16.4

Dependencies

{
  "express": "^4.21.0",
  "axios": "^1.8.0",
  "cors": "^2.8.5",
  "dotenv": "^16.4.0"
}

Architecture

Request Flow

Stage Component Description
1 Client Browser, app, or curl sends request
2 Express Server Routes request, applies CORS + security headers + rate limiting
3 Cache Check In-memory Map with TTL — hit = instant response
4 Fetch Data AniList GraphQL or Miruro pipe endpoint
5 Decode Pipe responses decoded: base64url -> gunzip -> JSON
6 Cache + Respond Store in cache, return JSON response

Caching Architecture

Cache Type TTL Max Size Eviction
Search results 1 min 100 entries FIFO
Collection lists 2-5 min 100 entries FIFO
Episode lists 2 min 100 entries FIFO
Streaming sources 1 min 100 entries FIFO

Serverless functions have read-only filesystems except /tmp. The cache uses in-memory Map which survives across warm invocations.


Project Structure

MiruroAPI/
├── public/                              # Static files
│   ├── index.html                       #   Premium landing page
│   ├── docs.html                        #   Swagger UI documentation
│   ├── openapi.json                     #   OpenAPI 3.0 spec
│   ├── icon-dark.svg                    #   Miruro dark mode favicon
│   ├── icon-light.svg                   #   Miruro light mode favicon
│   ├── icon-512x512.png                 #   Miruro app icon
│   ├── favicon.ico                      #   Classic favicon
│   ├── apple-touch-icon-180x180.png     #   iOS home screen icon
│   └── og-image.png                     #   OG/Twitter share image
│
├── assets/                              # Scraped Miruro assets
│   ├── favicons/                        #   All favicon variants
│   ├── logos/                           #   Status page logo
│   ├── fonts/                           #   Inter + FontAwesome
│   └── media/                           #   Testimonial avatars
│
├── src/
│   ├── helpers/
│   │   ├── anilist.js                   # AniList GraphQL integration
│   │   ├── pipe.js                      # Miruro pipe integration
│   │   └── cache.js                     # In-memory cache with TTL
│   └── routes/
│       └── apiRoutes.js                 # All 18 route definitions
│
├── server.js                            # Express server entry point
├── package.json                         # Dependencies & scripts
├── vercel.json                          # Vercel routing config
├── Dockerfile                           # Docker support
├── CHANGELOG.md                         # Version history
└── README.md                            # This file

Quick Start

Prerequisites

Requirement Minimum Recommended
Node.js 20.x 20.x LTS
npm 9.0+ 10.x

Installation

# 1. Clone the repository
git clone https://github.com/Shineii86/MiruroAPI.git
cd MiruroAPI

# 2. Install dependencies
npm install

# 3. Start development server
npm run dev

Open http://localhost:3000 in your browser.

Production

npm start

Alternative Package Managers

# yarn
yarn install && yarn dev

# pnpm
pnpm install && pnpm dev

# bun
bun install && bun dev

Configuration

Environment Variables

Variable Default Description
PORT 3000 Server port
ALLOWED_ORIGINS * Comma-separated allowed origins

Vercel Configuration

The vercel.json handles:

  • Builds — Maps server.js to @vercel/node
  • Routes — All requests forwarded to Express

API Endpoints

Base URL

https://mirurotvapi.vercel.app/api

Response Format

All endpoints return:

{
  "success": true,
  "results": { ... }
}

Health Check

GET /api/health
curl "https://mirurotvapi.vercel.app/api/health"
Response
{
  "success": true,
  "results": {
    "status": "healthy",
    "version": "1.2.0",
    "uptime": "0h 0m 34s",
    "uptimeSeconds": 34,
    "timestamp": "2026-06-09T09:55:00.884Z",
    "node": "v24.14.1",
    "memory": { "used": "13MB", "total": "15MB" },
    "endpoints": 16,
    "providers": ["kiwi","pewe","bee","bonk","bun","ally","nun","twin","cog","moo","hop","telli"]
  }
}

GET /api/search?query=naruto&per_page=2
Param Type Default Description
query string required Search keyword
page number 1 Page number
per_page number 20 Results per page
curl "https://mirurotvapi.vercel.app/api/search?query=naruto&per_page=2"
const res = await fetch("https://mirurotvapi.vercel.app/api/search?query=naruto&per_page=2");
const data = await res.json();
console.log(data.results); // { page, perPage, total, hasNextPage, results: [...] }
Response
{
  "success": true,
  "results": {
    "page": 1,
    "perPage": 2,
    "total": 5000,
    "hasNextPage": true,
    "results": [
      {
        "id": 20,
        "title": { "romaji": "NARUTO", "english": "Naruto", "native": "NARUTO -ナルト-" },
        "coverImage": { "large": "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx20-dE6UHbFFg1A5.jpg" },
        "format": "TV",
        "season": "FALL",
        "seasonYear": 2002,
        "episodes": 220,
        "status": "FINISHED",
        "averageScore": 80,
        "genres": ["Action","Adventure","Comedy","Drama","Fantasy","Supernatural"]
      }
    ]
  }
}

Suggestions

GET /api/suggestions?query=naruto
Param Type Default Description
query string required Search keyword
curl "https://mirurotvapi.vercel.app/api/suggestions?query=naruto"
Response
{
  "success": true,
  "results": [
    { "id": 20, "title": "Naruto", "title_romaji": "NARUTO", "poster": "...", "format": "TV", "status": "FINISHED", "year": 2002, "episodes": 220 },
    { "id": 1735, "title": "Naruto: Shippuden", "title_romaji": "NARUTO: Shippuuden", "poster": "...", "format": "TV", "status": "FINISHED", "year": 2007, "episodes": 500 }
  ]
}

Filter

GET /api/filter?genre=Action&sort=POPULARITY_DESC&per_page=1
Param Type Default Description
genre string — Genre name (e.g. "Action")
tag string — Tag name
year number — Release year
season string — FALL, WINTER, SPRING, SUMMER
format string — TV, MOVIE, OVA, ONA, SPECIAL, MUSIC
status string — RELEASING, FINISHED, NOT_YET_RELEASED, CANCELLED
sort string POPULARITY_DESC Sort order
page number 1 Page number
per_page number 20 Results per page
curl "https://mirurotvapi.vercel.app/api/filter?genre=Action&year=2024&season=WINTER&per_page=3"
Response
{
  "success": true,
  "results": {
    "page": 1,
    "perPage": 3,
    "total": 5000,
    "hasNextPage": true,
    "results": [ ... ]
  }
}

GET /api/trending?per_page=10
Param Type Default Description
per_page number 20 Results per page
curl "https://mirurotvapi.vercel.app/api/trending?per_page=3"

GET /api/popular?per_page=10

Upcoming

GET /api/upcoming?per_page=10

Recent

GET /api/recent?per_page=10

Spotlight

GET /api/spotlight

Returns featured/spotlight anime for the hero carousel.

Response
{
  "success": true,
  "results": [
    {
      "id": 21,
      "title": { "romaji": "ONE PIECE", "english": "One Piece" },
      "coverImage": { "large": "..." },
      "bannerImage": "https://...",
      "format": "TV",
      "episodes": null,
      "status": "RELEASING",
      "averageScore": 85,
      "genres": ["Action","Adventure","Comedy","Fantasy"],
      "description": "Gol D. Roger was known as the Pirate King..."
    }
  ]
}

Schedule

GET /api/schedule?date=2026-06-09
Param Type Default Description
date string today Date in YYYY-MM-DD format

Anime Info

GET /api/info/:id
Param Type Default Description
id number required AniList anime ID
curl "https://mirurotvapi.vercel.app/api/info/20"
const res = await fetch("https://mirurotvapi.vercel.app/api/info/20");
const data = await res.json();
console.log(data.results.title); // { romaji: "NARUTO", english: "Naruto" }
Response
{
  "success": true,
  "results": {
    "id": 20,
    "idMal": 20,
    "title": { "romaji": "NARUTO", "english": "Naruto", "native": "NARUTO -ナルト-" },
    "description": "Naruto Uzumaki, a hyperactive and knuckle-headed ninja...",
    "coverImage": { "large": "https://s4.anilist.co/file/..." },
    "bannerImage": "https://s4.anilist.co/file/...",
    "format": "TV",
    "season": "FALL",
    "seasonYear": 2002,
    "episodes": 220,
    "duration": 23,
    "status": "FINISHED",
    "averageScore": 80,
    "popularity": 694959,
    "genres": ["Action","Adventure","Comedy","Drama","Fantasy","Supernatural"],
    "studios": [{ "name": "Studio Pierrot", "isAnimationStudio": true }],
    "startDate": { "year": 2002, "month": 10, "day": 3 },
    "endDate": { "year": 2007, "month": 2, "day": 8 }
  }
}

Characters

GET /api/anime/:id/characters
Param Type Default Description
id number required AniList anime ID
curl "https://mirurotvapi.vercel.app/api/anime/20/characters"
Response
{
  "success": true,
  "results": {
    "edges": [
      {
        "role": "MAIN",
        "node": {
          "id": 17,
          "name": { "full": "Naruto Uzumaki", "native": "うずまきナルト" },
          "image": { "large": "https://s4.anilist.co/file/..." }
        },
        "voiceActors": [
          {
            "id": 95015,
            "name": { "full": "Junko Takeuchi", "native": "竹内順子" },
            "languageV2": "Japanese"
          }
        ]
      }
    ]
  }
}

Relations

GET /api/anime/:id/relations

Returns related anime (sequels, prequels, side stories, etc.).


Recommendations

GET /api/anime/:id/recommendations

Returns recommended anime based on the given ID.


Episodes

GET /api/episodes/:id
Param Type Default Description
id number required AniList anime ID
curl "https://mirurotvapi.vercel.app/api/episodes/20"
Response
{
  "success": true,
  "results": {
    "providers": {
      "kiwi": {
        "meta": { "id": "1571", "title": "Naruto", "type": "TV" },
        "episodes": {
          "sub": [
            {
              "id": "watch/kiwi/20/sub/anikoto-1",
              "number": 1,
              "title": "Enter: Naruto Uzumaki!",
              "image": "https://image.tmdb.org/t/p/original/...",
              "airDate": "2002-10-03",
              "audio": "sub",
              "filler": false,
              "fillerType": "manga_canon"
            }
          ]
        }
      }
    }
  }
}

Watch (Streaming Sources)

GET /api/watch/:provider/:anilistId/:category/:slug
Param Type Default Description
provider string required Provider name (kiwi, pewe, etc.)
anilistId number required AniList anime ID
category string required sub or dub
slug string required Episode slug from episodes response
curl "https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1"
const res = await fetch("https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1");
const data = await res.json();
const streams = data.results.streams;
// streams[0].url = "https://vault-01.uwucdn.top/stream/.../uwu.m3u8"
// streams[0].quality = "360p"
// streams[0].type = "hls"
Response
{
  "success": true,
  "results": {
    "streams": [
      {
        "url": "https://vault-01.uwucdn.top/stream/.../uwu.m3u8",
        "type": "hls",
        "quality": "360p",
        "resolution": { "width": 640, "height": 360 },
        "codec": "h264",
        "audio": "sub",
        "fansub": "df68",
        "isActive": false,
        "referer": "https://kwik.cx/e/..."
      },
      {
        "url": "https://kwik.cx/e/...",
        "type": "embed",
        "quality": "360p",
        "codec": "h264",
        "audio": "sub",
        "fansub": "df68",
        "isActive": false
      }
    ],
    "download": "https://pahe.win/LJmbA"
  }
}

Streaming Flow

To get a stream URL, follow these 3 steps:

# Step 1: Get episodes (returns provider slugs)
curl "https://mirurotvapi.vercel.app/api/episodes/20"
# => providers.kiwi.episodes.sub[0].id = "watch/kiwi/20/sub/anikoto-1"

# Step 2: Get streaming sources
curl "https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1"
# => streams[0].url = "https://...m3u8"

# Step 3: Play M3U8 in any HLS player
# Use hls.js, video.js, or native <video> with hls support

Sub & Dub

Providers return both sub and dub episode lists:

const eps = await fetch("/api/episodes/20").then(r => r.json());
const providers = eps.results.providers;

// Pick provider
const kiwi = providers.kiwi.episodes;

// Get sub episodes
const subEps = kiwi.sub; // [{ id: "watch/kiwi/20/sub/anikoto-1", ... }]

// Get dub episodes (if available)
const dubEps = kiwi.dub || []; // [{ id: "watch/kiwi/20/dub/...", ... }]

HLS Player Example

<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<video id="player" controls></video>
<script>
  const video = document.getElementById('player');
  const streamUrl = 'https://...m3u8'; // From /api/watch response
  
  if (Hls.isSupported()) {
    const hls = new Hls();
    hls.loadSource(streamUrl);
    hls.attachMedia(video);
  } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = streamUrl; // Native HLS (Safari)
  }
</script>

Response Schema

Standard Response

interface ApiResponse<T> {
  success: boolean;
  results: T;
}

Search Response

interface SearchResults {
  page: number;
  perPage: number;
  total: number;
  hasNextPage: boolean;
  results: Anime[];  // AniList anime objects
}

Episodes Response

interface EpisodesResults {
  providers: {
    [provider: string]: {
      meta: { id: string; title: string; type: string };
      episodes: {
        sub: Episode[];
        dub?: Episode[];
      };
    };
  };
}

interface Episode {
  id: string;       // e.g. "watch/kiwi/20/sub/anikoto-1"
  number: number;
  title: string;
  image: string;
  airDate: string;
  audio: "sub" | "dub";
  filler: boolean;
  fillerType: string;
}

Watch Response

interface WatchResults {
  streams: Stream[];
  download?: string;
}

interface Stream {
  url: string;          // M3U8 URL or embed URL
  type: "hls" | "embed";
  quality: string;      // e.g. "360p", "720p", "1080p"
  resolution?: { width: number; height: number };
  codec: string;        // e.g. "h264"
  audio: "sub" | "dub";
  fansub: string;
  isActive: boolean;
  referer?: string;
}

Deployment

Deploy with Vercel

# Or manually
npm i -g vercel
vercel

Docker

# Build
docker build -t miruroapi .

# Run
docker run -p 3000:3000 miruroapi

Standalone

git clone https://github.com/Shineii86/MiruroAPI.git
cd MiruroAPI
npm install
npm start

Performance

Metric Value
Cold start ~500ms
Warm response ~50-200ms
Cache hit ~10ms
Memory usage ~15MB
Cache TTL 1-5 min
Max cache size 100 entries
Rate limit 100 req/min/IP

FAQ

What data does MiruroAPI provide?

Anime metadata from AniList (titles, descriptions, scores, characters, relations) and streaming sources from Miruro providers (M3U8 URLs, quality, codec, fansub info).

Does this API store any files?

No. MiruroAPI is a proxy/aggregator that fetches data from AniList GraphQL and Miruro pipe endpoints. No files are stored on the server.

Is there rate limiting?

Yes, 100 requests per minute per IP address. Exceeding this returns a 429 status.

Which streaming providers are supported?

12 providers: kiwi, pewe, bee, bonk, bun, ally, nun, twin, cog, moo, hop, telli.

Can I use this in production?

This API is for educational purposes. Use at your own discretion.


Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License.

MIT License

Copyright (c) 2026 Shinei Nouzen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Author

Shinei Nouzen