The Black Hole Bay

API Reference

Full endpoint documentation with parameters, responses, and code examples

Getting Started

Everything you need to start using the API.

Base URL

All API requests should be made to:

text
https://theblackholebay.lol
Note: All endpoints are prefixed with /api. Example: https://theblackholebay.lol/api/search?q=dune

Authentication

No authentication is required for any public endpoint.

HeaderRequiredDescription
AuthorizationNoNot required
API-KeyNoNot required
Note: All third-party API keys (TMDB, RAWG) are kept server-side and are never exposed in client responses.

Rate Limiting

The API uses IP-based rate limiting.

SettingValue
Requests120 / minute / IP
EnforcementAutomatic
Exceeded429 Too Many Requests
IP cleanupEvery 60 seconds

Applications should use exponential backoff when receiving 429 responses:

javascript
async function fetchWithRetry(url, retries = 3) { for (let attempt = 0; attempt <= retries; attempt++) { const response = await fetch(url); if (response.status !== 429) return response; const delay = 1000 * 2 ** attempt; await new Promise(r => setTimeout(r, delay)); } throw new Error("Rate limit exceeded"); }

Response Format

All responses are JSON with the following headers:

HeaderValue
Content-Typeapplication/json; charset=utf-8
Cache-Controlno-store

Clients should implement their own short-lived caching for repeated requests.

Torrent API

Search torrents, get metadata, list files, and track downloads.

GET/api/torrent/{id}

Returns full metadata for a single torrent.

bash
curl "https://theblackholebay.lol/api/torrent/4034523"
json
{ "torrent": { "id":"4034523", "name":"...", "magnet":"magnet:?...", "seeders":245, "sizeLabel":"1.00 GiB" } }
GET/api/files/{id}

Returns the list of files inside a torrent.

json
{ "files": [ { "name": "video.mkv", "size": 1073741824, "sizeLabel": "1.00 GiB" }, { "name": "subs.srt", "size": 45200, "sizeLabel": "44.14 KiB" } ] }
GET/api/track/download

Increments the download counter. Call this when a user clicks a magnet link.

json
{ "ok": true }
Movies & TV

Movie and TV metadata powered by TMDB.

GET/api/upcoming?page=1

Movies currently in theaters. Posters cached locally.

ParameterDefaultDescription
page1Page number (20 per page)
Note: poster_path returns a local path: /upcoming/images/{id}.jpg � use directly as https://theblackholebay.lol/upcoming/images/{id}.jpg. Movies older than 90 days are filtered out.
GET/api/movie/{id}

Full movie details including cast, runtime, genres, and IMDb link.

json
{ "id": 872585, "title": "Oppenheimer", "runtime": 180, "imdb_id": "tt15398776", "genres": [{ "name": "Drama" }], "credits": { "cast": [{ "name": "Cillian Murphy", "character": "Oppenheimer" }] } }
GET/api/tv/{id}

Full TV show details including cast, seasons, and episodes.

json
{ "name": "Show Name", "number_of_seasons": 3, "number_of_episodes": 24, "episode_run_time": [55], "status": "Returning Series" }
Games

Game metadata powered by RAWG.

Image URLs
SourceFormat
TMDBhttps://image.tmdb.org/t/p/{size}{path} � sizes: w342, w500, w780, original
Local cachehttps://theblackholebay.lol/upcoming/images/{id}.jpg
RAWGUse background_image URL directly
Errors
StatusMeaningResponse
403IP blockedForbidden: IP banned.
404Not found{ "error": "Failed." }
429Rate limit exceededToo Many Requests.
500Server error{ "error": "Internal Server Error" }
Code Examples

JavaScript

javascript
const API = "https://theblackholebay.lol"; // Search torrents const res = await fetch(`${API}/api/search?q=oppenheimer&category=200`); const data = await res.json(); data.results.forEach(t => { console.log(`${t.name} | ${t.sizeLabel} | S:${t.seeders} L:${t.leechers}`); }); // Trending movies const movies = await fetch(`${API}/api/trending`).then(r => r.json()); movies.results.forEach(m => { console.log(`${m.title} (${m.vote_average}/10)`); });

Python

python
import requests API = "https://theblackholebay.lol" response = requests.get(f"{API}/api/search", params={ "q": "breaking bad", "category": 200, "page": 0 }, timeout=10) for torrent in response.json()["results"]: print(f"{torrent['name']} | {torrent['sizeLabel']}")

cURL

bash
# Search curl "https://theblackholebay.lol/api/search?q=dune&category=200" # Trending movies curl "https://theblackholebay.lol/api/trending" # Trending games curl "https://theblackholebay.lol/api/trending_games" # Movie details curl "https://theblackholebay.lol/api/movie/872585"

Minimal API Client

javascript
const API = "https://theblackholebay.lol"; const client = { search: (q, cat = 0) => fetch(`${API}/api/search?q=${q}&category=${cat}`).then(r => r.json()), torrent: (id) => fetch(`${API}/api/torrent/${id}`).then(r => r.json()), files: (id) => fetch(`${API}/api/files/${id}`).then(r => r.json()), trendingMovies: () => fetch(`${API}/api/trending`).then(r => r.json()), trendingTV: () => fetch(`${API}/api/trending_tv`).then(r => r.json()), trendingGames: () => fetch(`${API}/api/trending_games`).then(r => r.json()), movie: (id) => fetch(`${API}/api/movie/${id}`).then(r => r.json()), tv: (id) => fetch(`${API}/api/tv/${id}`).then(r => r.json()) };
Best Practices

Caching

API responses use Cache-Control: no-store. For frequently-requested data (like trending movies), implement your own short-lived cache (30-60 seconds) to avoid hitting rate limits.

Error Handling

javascript
switch (response.status) { case 200: break; // Success case 403: break; // IP blocked case 404: break; // Not found case 429: break; // Back off and retry case 500: break; // Temporary failure }

Security

Do not expose provider API keys in frontend applications. All keys are kept server-side. The recommended architecture is:

text
Frontend ? HTTPS ? Your App ? Server-side request ? The Black Hole Bay API