{
  "openapi": "3.1.0",
  "info": {
    "title": "AnimeDoc API",
    "version": "2.0.0",
    "description": "AnimeDoc is an anime and movie streaming API with search, details and playback endpoints, plus a free site to watch anime online. Plans and limits: https://animedoc.cloud/pricing",
    "contact": {
      "email": "support@animedoc.cloud",
      "url": "https://animedoc.cloud/about"
    }
  },
  "externalDocs": {
    "url": "https://animedoc.cloud/docs"
  },
  "servers": [
    {
      "url": "https://api.animedoc.cloud"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/api/v2/anime/home/": {
      "get": {
        "operationId": "home",
        "summary": "Home Feed",
        "description": "Everything a streaming front page needs in one call: banners and ready-made catalog rows. Returns banners (featured titles with a wide backdrop image) and rows: Most watched today, Latest anime, Latest movies, Popular anime, New anime movies, Popular movies, Popular series, Top rated anime, Latest animation, then curated collections. Rows built from Browse include a browse object with the exact channelId/sort/genre to page through the full list. Items share one compact shape; pass detailPath to Details and subjectId + detailPath to Media Sources. Cached for 10 minutes.",
        "externalDocs": {
          "url": "https://animedoc.cloud/docs/endpoints/home"
        },
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests per day on your plan"
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests left today"
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix time of the next daily reset (00:00 UTC)"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over the plan's per-minute or per-day limit",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "502": {
            "description": "Content provider unavailable; retry with backoff",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/anime/section/": {
      "get": {
        "operationId": "section",
        "summary": "Section",
        "description": "A ready-made page for one section (anime, movies, series, asian, bollywood, nollywood), or that section's filtered list. With just id: featured (titles with trailers, for a header; anime uses what's popular this season), filters (the sort, kind, genre and year options that section supports), rows (each with the query behind it) and, for anime, upcoming (upcoming anime with a youtubeId trailer). Add any of sort, kind, genre, year or page to get that section's filtered list instead, as items + pager. Every result really belongs to the section: no non-anime in anime, no anime in movies, only Nigerian titles in nollywood, only Korean/Japanese/Chinese/Thai live-action in asian. Items include trailer (a short MP4, or empty) and backdrop (a landscape still) for hover previews.",
        "externalDocs": {
          "url": "https://animedoc.cloud/docs/endpoints/section"
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "anime, movies, series, asian, bollywood or nollywood.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Latest, Hottest or Rating (filtered list).",
            "schema": {
              "type": "string",
              "default": "Hottest"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "series or movies, where the section has both (filtered list).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "genre",
            "in": "query",
            "required": false,
            "description": "One of the section's filters.genre values, e.g. Action (filtered list).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "Release year, e.g. 2026 (filtered list).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "asian only: Korea, Japan, China or Thailand (filtered list).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page of the filtered list.",
            "schema": {
              "type": "integer",
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests per day on your plan"
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests left today"
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix time of the next daily reset (00:00 UTC)"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over the plan's per-minute or per-day limit",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "502": {
            "description": "Content provider unavailable; retry with backoff",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/anime/trending/": {
      "get": {
        "operationId": "trending",
        "summary": "Trending",
        "description": "What most people are watching right now, across anime, movies and series. Pages start at 0. Use it for a \"Most watched\" or \"Trending now\" row. Same item shape as Search and Browse.",
        "externalDocs": {
          "url": "https://animedoc.cloud/docs/endpoints/trending"
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page number, starting at 0.",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "Items per page (max 48).",
            "schema": {
              "type": "integer",
              "default": 24
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests per day on your plan"
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests left today"
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix time of the next daily reset (00:00 UTC)"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over the plan's per-minute or per-day limit",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "502": {
            "description": "Content provider unavailable; retry with backoff",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/anime/browse/": {
      "get": {
        "operationId": "browse",
        "summary": "Browse",
        "description": "List a channel (movies, series or animation) sorted by latest, most popular or top rated, optionally by genre and country. The building block for catalog pages and \"latest\" rows. channelId: 1 = movies, 2 = series, 1006 = animation. sort: Latest, Hottest or Rating. genre narrows it, e.g. Anime. Examples: newest anime channelId=2&genre=Anime&sort=Latest; anime movies channelId=1&genre=Anime; most popular movies channelId=1&sort=Hottest; top rated anime channelId=2&genre=Anime&sort=Rating; Bollywood channelId=1&country=India; Nollywood channelId=1&country=Nigeria; K-drama channelId=2&country=Korea.",
        "externalDocs": {
          "url": "https://animedoc.cloud/docs/endpoints/browse"
        },
        "parameters": [
          {
            "name": "channelId",
            "in": "query",
            "required": false,
            "description": "1 = movies, 2 = series, 1006 = animation.",
            "schema": {
              "type": "integer",
              "default": 2
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Latest, Hottest or Rating.",
            "schema": {
              "type": "string",
              "default": "Latest"
            }
          },
          {
            "name": "genre",
            "in": "query",
            "required": false,
            "description": "Optional genre filter, e.g. Anime, Action, Comedy, Horror.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Optional country filter: India (Bollywood), Nigeria (Nollywood), United States (Hollywood), Korea (K-drama)...",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page number, starting at 1.",
            "schema": {
              "type": "integer",
              "default": 1
            }
          },
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "description": "Items per page (max 48).",
            "schema": {
              "type": "integer",
              "default": 24
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests per day on your plan"
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests left today"
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix time of the next daily reset (00:00 UTC)"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over the plan's per-minute or per-day limit",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "502": {
            "description": "Content provider unavailable; retry with backoff",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/anime/suggest/": {
      "post": {
        "operationId": "searchSuggestions",
        "summary": "Search Suggestions",
        "description": "Autocomplete: turn a partial keyword into likely search terms. Use it behind a search box: send what the user has typed so far and show the returned words as suggestions. It's cheap and fast, but each call still counts as one request, so debounce keystrokes (300 ms works well).",
        "externalDocs": {
          "url": "https://animedoc.cloud/docs/endpoints/search-suggestions"
        },
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests per day on your plan"
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests left today"
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix time of the next daily reset (00:00 UTC)"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "word": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over the plan's per-minute or per-day limit",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "502": {
            "description": "Content provider unavailable; retry with backoff",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "keyword"
                ],
                "properties": {
                  "keyword": {
                    "type": "string",
                    "description": "The partial text the user typed."
                  },
                  "perPage": {
                    "type": "integer",
                    "description": "Maximum number of suggestions.",
                    "default": 30
                  }
                }
              },
              "example": {
                "keyword": "naru",
                "perPage": 5
              }
            }
          }
        }
      }
    },
    "/api/v2/anime/search/": {
      "post": {
        "operationId": "search",
        "summary": "Search",
        "description": "Full-text catalog search across anime, animation, movies and series, with pagination. Returns matching titles with cover art, genre, release date and rating. Each item has a subjectId and a detailPath: pass detailPath to Details, and both to Media Sources. One catalog covers anime and general movies; use subjectType to bias results and the genre field to split anime from everything else.",
        "externalDocs": {
          "url": "https://animedoc.cloud/docs/endpoints/search"
        },
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests per day on your plan"
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests left today"
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix time of the next daily reset (00:00 UTC)"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "pager": {
                          "type": "object",
                          "properties": {
                            "hasMore": {
                              "type": "boolean"
                            },
                            "totalCount": {
                              "type": "integer"
                            }
                          }
                        },
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Subject"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over the plan's per-minute or per-day limit",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "502": {
            "description": "Content provider unavailable; retry with backoff",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "keyword"
                ],
                "properties": {
                  "keyword": {
                    "type": "string",
                    "description": "What to search for."
                  },
                  "page": {
                    "type": "integer",
                    "description": "Page number, starting at 1.",
                    "default": 1
                  },
                  "perPage": {
                    "type": "integer",
                    "description": "Results per page.",
                    "default": 15
                  },
                  "subjectType": {
                    "type": "integer",
                    "description": "0 = everything, 1 = movies, 2 = series.",
                    "default": 0
                  }
                }
              },
              "example": {
                "keyword": "naruto",
                "page": 1,
                "perPage": 15,
                "subjectType": 0
              }
            }
          }
        }
      }
    },
    "/api/v2/anime/detail/": {
      "get": {
        "operationId": "details",
        "summary": "Details",
        "description": "Full metadata for one title, plus its seasons and episode counts. Look up a title by the detailPath from a search result. resource.seasons lists each season (se) and how many episodes it has (maxEp). A movie shows up as a single season with se: 0 and maxEp: 0.",
        "externalDocs": {
          "url": "https://animedoc.cloud/docs/endpoints/details"
        },
        "parameters": [
          {
            "name": "detailPath",
            "in": "query",
            "required": true,
            "description": "The detailPath from a search result.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests per day on your plan"
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests left today"
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix time of the next daily reset (00:00 UTC)"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "subject": {
                          "$ref": "#/components/schemas/Subject"
                        },
                        "stars": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string"
                              },
                              "character": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "resource": {
                          "type": "object",
                          "properties": {
                            "seasons": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "se": {
                                    "type": "integer"
                                  },
                                  "maxEp": {
                                    "type": "integer"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Title or episode not found"
          },
          "429": {
            "description": "Over the plan's per-minute or per-day limit",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "502": {
            "description": "Content provider unavailable; retry with backoff",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/anime/media-sources/": {
      "get": {
        "operationId": "mediaSources",
        "summary": "Media Sources",
        "description": "Playable video URLs (several resolutions) and subtitle tracks for one episode or movie. Resolves an episode to direct video files and captions. URLs are signed and expire, so request them right before playback and don't cache them. Skip entries with vipLocked: true or an empty url. For a movie, pass se=0&ep=0. CDN URLs usually refuse hotlinking from browsers, so play them through the Stream Proxy.",
        "externalDocs": {
          "url": "https://animedoc.cloud/docs/endpoints/media-sources"
        },
        "parameters": [
          {
            "name": "subjectId",
            "in": "query",
            "required": true,
            "description": "subjectId from Search or Details.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "detailPath",
            "in": "query",
            "required": true,
            "description": "detailPath from Search or Details.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "se",
            "in": "query",
            "required": false,
            "description": "Season number (0 for movies).",
            "schema": {
              "type": "integer",
              "default": 1
            }
          },
          {
            "name": "ep",
            "in": "query",
            "required": false,
            "description": "Episode number (0 for movies).",
            "schema": {
              "type": "integer",
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests per day on your plan"
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests left today"
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix time of the next daily reset (00:00 UTC)"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "downloads": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "url": {
                                "type": "string",
                                "format": "uri"
                              },
                              "resolution": {
                                "type": "integer"
                              },
                              "size": {
                                "type": "integer"
                              },
                              "duration": {
                                "type": "integer"
                              },
                              "codecName": {
                                "type": "string"
                              },
                              "vipLocked": {
                                "type": "boolean"
                              }
                            }
                          }
                        },
                        "captions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "lan": {
                                "type": "string"
                              },
                              "lanName": {
                                "type": "string"
                              },
                              "url": {
                                "type": "string",
                                "format": "uri"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Title or episode not found"
          },
          "429": {
            "description": "Over the plan's per-minute or per-day limit",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "502": {
            "description": "Content provider unavailable; retry with backoff",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/anime/stream-file/": {
      "get": {
        "operationId": "streamProxy",
        "summary": "Stream Proxy",
        "description": "Streams a Media Sources URL back through AnimeDoc, with byte-range support, so players can seek. Pass a url from Media Sources as video_url. The response is the video itself (video/mp4) with Accept-Ranges: bytes, so <video> elements and mobile players can seek. Forward the player's Range header if you proxy it. Needs an API key on a paid plan (Starter, Pro, Business or the 3-Day Pass). Each HTTP request counts, and players fetch in chunks, so one playback is usually several requests.",
        "externalDocs": {
          "url": "https://animedoc.cloud/docs/endpoints/stream-proxy"
        },
        "parameters": [
          {
            "name": "video_url",
            "in": "query",
            "required": true,
            "description": "A downloads[].url from Media Sources.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "required": false,
            "description": "Byte range, e.g. bytes=0-. Players send this automatically.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Video bytes (full file)",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "206": {
            "description": "Partial content for a Range request",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Plan doesn't include the stream proxy (needs a paid plan)"
          },
          "429": {
            "description": "Over the plan's per-minute or per-day limit",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "502": {
            "description": "Content provider unavailable; retry with backoff",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      }
    },
    "schemas": {
      "Subject": {
        "type": "object",
        "properties": {
          "subjectId": {
            "type": "string"
          },
          "subjectType": {
            "type": "integer",
            "description": "1 = movie, 2 = series"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "releaseDate": {
            "type": "string",
            "example": "2002-10-03"
          },
          "genre": {
            "type": "string",
            "description": "Comma-separated"
          },
          "cover": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri"
              }
            }
          },
          "countryName": {
            "type": "string"
          },
          "imdbRatingValue": {
            "type": "string"
          },
          "subtitles": {
            "type": "string"
          },
          "hasResource": {
            "type": "boolean"
          },
          "detailPath": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          }
        }
      },
      "RateLimitError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "enum": [
              "rate_limit_exceeded",
              "daily_quota_exceeded"
            ]
          },
          "detail": {
            "type": "string"
          },
          "limit": {
            "type": "integer"
          },
          "window": {
            "type": "string",
            "enum": [
              "minute",
              "day"
            ]
          },
          "retry_after_seconds": {
            "type": "integer"
          },
          "resets_at": {
            "type": "string",
            "format": "date-time"
          },
          "upgrade_url": {
            "type": "string",
            "format": "uri"
          }
        }
      }
    }
  }
}