tolong buatkan website Dracin full api: tolong buatkan website dracin sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc Account Created Referral code ABC123 applied successfully! Copy your API key now — it will not be shown again. Your API Key sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc Use it in your requests: Authorization: Bearer sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc lalu Short Drama API Short Drama Overview 30+ providers, 25,000+ dramas, multi-quality video (up to 1080p), multi-language subtitles, pre-signed CDN URLs, MeiliSearch full-text search, and per-plan rate limiting. The flagship API product. Providers 28 Dramas 28,223 Episodes 1,990,231 Published 1,914,922 Base URL Base URL https://api.splay.id GET /api/dramas Key Features Multi-Provider 30+ content providers aggregated into a single API. Filter, include, or exclude by provider slug. Multi-Quality Video in 360p, 480p, 720p, and 1080p. Primary video_url plus qualities JSON object. Signed CDN URLs HMAC-SHA256 signed video URLs with 1-hour TTL. Covers and subtitles are public. Full-Text Search MeiliSearch-powered search with provider, tag, and language filters. Authentication API Key Required All data endpoints require Authorization: Bearer . Get your key atapi-dashboard. Quick Example GET /api/dramas Copy curl"https://api.splay.id/api/dramas?page=1&per_page=10"\ -H"Authorization: Bearer " # Response { "data": [ { "id": 1, "title":"Hidden Wolf King", "cover_url":"https://cdn.splay.id/...", "chapter_count": 80, "provider_slug":"dramabox", ... } ], "meta": {"page": 1,"per_page": 10,"total": 25000,"total_pages": 2500 } } Short Drama API API Endpoints Complete reference for all available Short Drama endpoints. All endpoints require an API key via Authorization: Bearer header. Drama & Search Method Endpoint Description GET /api/dramas List dramas (paginated, filter by provider/tag/language, sorting) GET /api/dramas/popular Popular dramas ranked by published episode count GET /api/dramas/trending Trending dramas (recently updated, sorted by play count) GET /api/dramas/alphabet A-Z letter counts, or dramas by letter (?letter=A) GET /api/dramas/:id Drama detail with tags and all episodes (includes subtitles + multi-quality) GET /api/dramas/:id/episodes Paginated episodes with subtitles, qualities, and optional status filter GET /api/search Full-text + trigram fuzzy search with relevance scoring Provider, Tag & Status Method Endpoint Description GET /api/providers List all providers (id, slug, name) GET /api/tags List all tags with drama counts GET /api/status API status with provider stats and totals Query Parameters Parameter Type Default Description page integer 1 Page number (min: 1) per_page integer 20 Items per page (1-100) provider string -- Filter by a single provider slug (backward compat alias for providers=) providers string -- Comma-separated provider slugs to include (e.g. dramabite,reelshort). Up to 10. exclude string -- Comma-separated provider slugs to exclude (e.g. moviebox-movies,moviebox-series). Up to 10. tag string -- Filter by tag name or en_name (e.g. Romance) language string -- Filter by audio language: en, id, zh, ko q string -- Search query (required) status string -- Filter: published, coming_soon, removed sort_by string updated_at Sort field: title, created_at, updated_at sort_order string desc Sort direction: asc, desc Response Shapes GET /api/dramas -- Paginated List Copy { "data": [ { "id": 1, "provider_id": 1, "external_id":"abc123", "title":"Hidden Wolf King", "cover_url":"https://cdn.splay.id/dramabox/abc123/cover.jpg", "introduction":"A young woman discovers...", "chapter_count": 80, "play_count": 1542, "shelf_time":"2025-01-15T00:00:00Z", "is_dubbed": false, "language":"en", "raw_data": { ... }, "created_at":"2025-01-15T10:00:00Z", "updated_at":"2025-03-01T12:00:00Z", "provider_slug":"dramabox", "provider_name":"DramaBox" } ], "meta": { "page": 1, "per_page": 20, "total": 5450, "total_pages": 273 } } GET /api/dramas/:id -- Detail (drama + tags + episodes) Copy { "data": { "drama": { "id": 1, "title":"Hidden Wolf King", "cover_url":"https://cdn.splay.id/dramabox/abc123/cover.jpg", "introduction":"...", "chapter_count": 80, "provider_slug":"dramabox", "provider_name":"DramaBox", ... }, "tags": [ {"id": 1,"name":"Romance","en_name":"Romance"}, {"id": 5,"name":"Werewolf","en_name":"Werewolf"} ], "episodes": [ { "id": 101, "drama_id": 1, "episode_index": 1, "episode_name":"Episode 1", "video_url":"https://cdn.splay.id/dramabox/abc123/1/video.mp4?sig=a3f9...&expires=1741600000", "subtitle_url":"https://cdn.splay.id/.../subtitle_id.vtt", "subtitles": [ {"lang":"id","url":"https://cdn.splay.id/.../subtitle_id.vtt"}, {"lang":"en","url":"https://cdn.splay.id/.../subtitle_en.vtt"} ], "qualities": { "1080p":"https://cdn.splay.id/.../video_1080p.mp4?sig=b7c2...&expires=1741600000", "720p":"https://cdn.splay.id/.../video_720p.mp4?sig=d1e4...&expires=1741600000" }, "status":"published", "released_at":"2025-01-15T00:00:00Z", "created_at":"2025-01-15T10:00:00Z" } ] } } GET /api/dramas/:id/episodes -- Paginated Episodes Copy { "data": [ { "id": 101, "drama_id": 1, "external_id":"ep_001", "episode_index": 1, "episode_name":"Episode 1", "video_url":"https://cdn.splay.id/dramabox/abc123/1/video.mp4?sig=a3f9...&expires=1741600000", "subtitle_url":"https://cdn.splay.id/.../subtitle_id.vtt", "subtitles": [ {"lang":"id","url":"..."}, {"lang":"en","url":"..."} ], "qualities": {"1080p":"...?sig=...&expires=...","720p":"...","480p":"..."}, "status":"published", "released_at":"2025-01-15T00:00:00Z", "created_at":"2025-01-15T10:00:00Z" } ], "meta": {"page": 1,"per_page": 20,"total": 80,"total_pages": 4 } } Signed Video URLs All video_url and qualities fields in episode responses are pre-signed by the API server using HMAC-SHA256. The signature is valid for 30 minutes by default (max 4 hours via expires_in param). Cover images (cover_url) and subtitles are not signed -- they are public. Signed by API server You never touch the signing secret TTL 30 min Default 1800s, max 14400s (4h) via expires_in param Algorithm HMAC-SHA256 sig = HMAC(secret, path:expires) Signed URL format Copy # video_url returned by the API already contains sig + expires: https://cdn.splay.id/{provider}/{drama_id}/{ep_index}/video.mp4 ?sig=a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1 &expires=1741600000 # expires -- Unix timestamp (seconds). URL is invalid after this time. # sig -- HMAC-SHA256 hex of"{path}:{expires}"signed with server secret. # Use video_url directly in your player -- no extra signing needed: Short Drama API Full-Text Search Search dramas by title using MeiliSearch with ILIKE fallback. Supports provider and tag filters. Basic Search Request Copy GET /api/search?q=love&page=1&per_page=10 Response Copy { "data": [ { "id": 42, "title":"Love in the City", "cover_url":"https://cdn.splay.id/.../cover.jpg", "introduction":"...", "chapter_count": 24, "play_count": 0, "shelf_time":"2025-01-15T00:00:00Z", "is_dubbed": false, "language":"en", "provider_slug":"dramabox", "provider_name":"DramaBox", "created_at":"...", "updated_at":"..." } ], "meta": { "page": 1, "per_page": 10, "total": 156, "total_pages": 16 } } With Filters cURL $curl "https://api.splay.id/api/search?q=love&provider=freereels&tag=romance&sort_by=title&sort_order=asc" Parameters q Required Search query (required, max 200 characters). Uses MeiliSearch with ILIKE fallback. provider Filter by provider slug (e.g. dramabox, freereels, dramabite) tag Filter by tag name or English name language Filter by audio language: en (English), id (Indonesian), zh (Chinese), ko (Korean) sort_by Sort field: title, created_at, updated_at (default) sort_order Sort direction: asc, desc (default) page Page number (default: 1) per_page Results per page (default: 20, max: 100) Search results are cached. The cache key includes query, page, per_page, provider, tag, language, and sort order. Cached responses include thex-cache: hit header. Short Drama API Code Examples Ready-to-use examples for integrating with the Short Drama API. Paste your API key below to try live requests. Your API Key Active Paste your API key to authenticate the "Try" buttons and inject it into code examples.Get your key → sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc Save Clear Try It Live Browse Dramas GET /api/dramas?page=1&per_page=3 Send 403 342ms 0.1 KB Copy Collapse { "error": { "code": "FORBIDDEN", "message": "IP 2a09:bac1:6500:8::3c3:40 is not in the whitelist for this API key." } } GET /api/dramas?provider=dramabox&per_page=3 Send GET /api/dramas?providers=dramabite,reelshort&per_page=3 Send GET /api/dramas?exclude=moviebox-movies,moviebox-series&per_page=3 Send GET /api/dramas?tag=Romance&per_page=3 Send GET /api/dramas?language=id&per_page=3 Send GET /api/dramas?sort_by=title&sort_order=asc&per_page=3 Send GET /api/dramas/popular?per_page=5 Send GET /api/dramas/trending?per_page=5 Send GET /api/dramas/alphabet Send GET /api/dramas/alphabet?letter=M&per_page=5 Send Drama Detail GET /api/dramas/1 Send GET /api/dramas/1/episodes?page=1&per_page=5 Send GET /api/dramas/1/episodes?status=published&per_page=5 Send Search GET /api/search?q=love&per_page=3 Send GET /api/search?q=love&provider=freereels&per_page=3 Send GET /api/search?q=ceo&language=id&per_page=3 Send Meta GET /api/providers Send GET /api/tags?per_page=20 Send GET /api/status Send cURL cURL Examples Copy # Set your API key API_KEY="YOUR_API_KEY" BASE="https://api.splay.id" # -- List dramas (paginated) -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas?page=1&per_page=10" # -- Filters -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas?provider=dramabox&per_page=10" curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas?providers=dramabite,reelshort&per_page=10" curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas?exclude=moviebox-movies,moviebox-series&per_page=10" curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas?tag=Romance&per_page=10" curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas?language=id&per_page=10" curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas?sort_by=title&sort_order=asc&per_page=10" # -- Popular & Trending -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas/popular?per_page=10" curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas/trending?per_page=10" # -- Browse A-Z -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas/alphabet" curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas/alphabet?letter=M&per_page=20" # -- Drama detail (includes tags + episodes) -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas/1" # -- Episodes paginated -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/dramas/1/episodes?page=1&per_page=20" # -- Search -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/search?q=love&per_page=10" # -- Meta -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/providers" curl -H"Authorization: Bearer $API_KEY""$BASE/api/tags" curl"$BASE/api/status" JavaScript / TypeScript Full Example Copy const BASE ="https://api.splay.id"; const API_KEY ="YOUR_API_KEY"; const headers = { Authorization: `Bearer ${API_KEY}` }; // -- List dramas with pagination -- const res = await fetch(`${BASE}/api/dramas?page=1&per_page=10`, { headers }); const { data, meta } = await res.json(); console.log(`Found ${meta.total} dramas (page ${meta.page}/${meta.total_pages})`); data.forEach(d => console.log(`[${d.provider_name}] ${d.title}`)); // -- Filters: provider, tag, language, sort -- const filtered = await fetch( `${BASE}/api/dramas?provider=dramabox&tag=Romance&language=en&sort_by=title&sort_order=asc&per_page=10`, { headers } ); // -- Popular & Trending -- const { data: popularDramas } = await ( await fetch(`${BASE}/api/dramas/popular?per_page=10`, { headers }) ).json(); // -- Drama detail (returns drama + tags + episodes) -- const detail = await fetch(`${BASE}/api/dramas/1`, { headers }); const { data: { drama, tags, episodes } } = await detail.json(); console.log(`${drama.title} -- ${episodes.length} episodes`); // -- Episodes with signed video URLs (valid 1 hour) -- const ep = episodes[0]; console.log("Video URL:", ep.video_url); // signed, ready to play if (ep.qualities) { console.log("1080p:", ep.qualities["1080p"]); } // -- Search with filters -- const search = await fetch( `${BASE}/api/search?q=romance&provider=freereels&language=id`, { headers } ); const results = await search.json(); console.log(`Found ${results.meta.total} results`); Python Full Example Copy import requests BASE ="https://api.splay.id" API_KEY ="YOUR_API_KEY" headers = {"Authorization": f"Bearer {API_KEY}"} # -- List dramas (paginated) -- res = requests.get(f"{BASE}/api/dramas", params={"page": 1,"per_page": 10}, headers=headers) data = res.json() for drama in data["data"]: print(f"[{drama['provider_name']}] {drama['title']} ({drama['chapter_count']} eps)") print(f"Total: {data['meta']['total']} dramas") # -- Filters: provider, tag, language, sort -- filtered = requests.get(f"{BASE}/api/dramas", params={ "provider":"dramabox","tag":"Romance","language":"en", "sort_by":"title","sort_order":"asc","per_page": 10 }, headers=headers) # -- Popular & Trending -- popular = requests.get(f"{BASE}/api/dramas/popular", params={"per_page": 10}, headers=headers) trending = requests.get(f"{BASE}/api/dramas/trending", params={"per_page": 10}, headers=headers) # -- Drama detail (returns drama + tags + episodes) -- detail = requests.get(f"{BASE}/api/dramas/1", headers=headers) info = detail.json()["data"] drama, tags, episodes = info["drama"], info["tags"], info["episodes"] print(f"{drama['title']} -- {len(episodes)} episodes") # -- Episodes with signed video URLs (valid 1 hour) -- ep = episodes[0] print("Video URL:", ep.get("video_url")) if ep.get("qualities"): print(f"Qualities: {', '.join(ep['qualities'].keys())}") # -- Search with filters -- search = requests.get(f"{BASE}/api/search", params={ "q":"love","provider":"dramabox","language":"id","per_page": 10 }, headers=headers) print(f"Search found {search.json()['meta']['total']} results") PHP Full Example Copy true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer $apiKey", "Accept: application/json", ], CURLOPT_TIMEOUT => 10, ]); $body = curl_exec($ch); curl_close($ch); return json_decode($body, true) ?? []; } // -- List dramas (paginated) -- $res = sdrama("/api/dramas", $API_KEY, ["page"=> 1,"per_page"=> 10]); foreach ($res["data"] as $drama) { echo"[{$drama['provider_name']}] {$drama['title']}\n"; } echo"Total: {$res['meta']['total']} dramas\n"; // -- Drama detail (tags + episodes) -- $detail = sdrama("/api/dramas/1", $API_KEY); $drama = $detail["data"]["drama"]; $tags = $detail["data"]["tags"]; $episodes = $detail["data"]["episodes"]; echo"{$drama['title']} --". count($episodes) ."episodes\n"; // -- Search -- $search = sdrama("/api/search", $API_KEY, ["q"=>"love","provider"=>"melolo","per_page"=> 10]); echo"Search found {$search['meta']['total']} results\n"; DrakorIndo API DrakorIndo Overview Full-length Korean dramas and movies with Indonesian hardsub. Multi-quality video (480p/720p/1080p), rich metadata including Korean titles, cast, directors, ratings, and genres. Same familiar Drama/Episode data model used across the platform. Titles Growing Episodes Growing Quality 480p-1080p Subtitles Hardsub Indo Base URL Base URL https://api.splay.id GET /api/drakor?per_page=20&type=series Content Types DrakorIndo hosts both Korean drama series and movies. Use the type query parameter to filter by content type. Type Filter Description Series ?type=series Full-length Korean drama series (10-20+ episodes typical) Movie ?type=movie Korean movies (single video, 1h20m-2h30m typical) All (no filter) Both series and movies combined Data Model DrakorIndo uses the same Drama and Episode types as the Short Drama API. Each drama includes standard fields plus rich metadata in the raw_data JSON field -- Korean title, cast, director, rating, and genre details. Field Type Description id number Unique drama ID title string Drama title (English) cover_url string Signed cover image URL (TMDB source) provider_slug string Provider identifier (drakorindo) chapter_count number Total episode count introduction string Drama synopsis tags Tag[] Genre/category tags episodes Episode[] Episode list with video URLs raw_data object Rich metadata: korean_title, cast, director, rating, genres Video Quality Each episode has a primary video_url and a qualities JSON object with all available resolutions. All videos have Indonesian hardcoded subtitles. Quality JSON key in qualities{} Notes 480p qualities["480p"] Standard definition -- available on most content 720p video_url · qualities["720p"] Primary -- HD 1080p qualities["1080p"] Full HD -- newer content (2025+) All video URLs are HMAC-SHA256 signed with 30-min TTL. Use video_url as your primary source; fall back through qualities for other resolutions. Videos are hardsub Indonesian -- no separate subtitle tracks. Authentication Same API Key DrakorIndo endpoints use the same Authorization: Bearer authentication as all other APIs. Get your key atapi-dashboard. Quick Example GET /api/drakor Copy curl"https://api.splay.id/api/drakor?per_page=20&type=series"\ -H"Authorization: Bearer "DrakorIndo API Endpoints Dedicated /api/drakor/* endpoints for DrakorIndo content. All endpoints follow the same patterns as the Short Drama API -- pagination, sorting, filtering, and signed video URLs. Use ?type=series or ?type=movie to filter by content type. Authentication Required All data endpoints require Authorization: Bearer . Get your key atapi-dashboard. GET /api/drakor List DrakorIndo dramas -- paginated, with filtering and sorting. Use ?type=series or ?type=movie to filter by content type. Parameter Type Required Description page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) type string optional Content type filter: series | movie provider string optional Filter by provider slug tag string optional Filter by tag name (genre) language string optional ISO 639-1 language code (ko, en, ...) sort_by string optional updated_at | created_at | title | play_count | chapter_count sort_order string optional desc | asc Example /api/drakor?per_page=20&type=series&sort_by=updated_at GET /api/drakor/popular Popular DrakorIndo dramas ranked by play count Parameter Type Required Description page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) type string optional Content type filter: series | movie language string optional ISO 639-1 language code Example /api/drakor/popular?per_page=10&type=series GET /api/drakor/trending Trending DrakorIndo dramas (recently updated, sorted by play count) Parameter Type Required Description page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) type string optional Content type filter: series | movie language string optional ISO 639-1 language code Example /api/drakor/trending?type=series GET /api/drakor/search Full-text search across DrakorIndo dramas Parameter Type Required Description q string required Search query page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) type string optional Content type filter: series | movie Example /api/drakor/search?q=vincenzo&type=series GET /api/drakor/alphabet Browse A-Z -- returns letter counts, or dramas starting with a specific letter Parameter Type Required Description letter string optional Single letter (A-Z) to filter dramas. Omit for letter counts. page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) type string optional Content type filter: series | movie Example /api/drakor/alphabet?letter=V&type=series GET /api/drakor/{id} Get DrakorIndo drama detail with all episodes, signed video URLs, and rich metadata (Korean title, cast, director, rating) Parameter Type Required Description id number required Drama ID (integer) expires_in number optional Signed URL TTL in seconds (max 14400, default 1800) Example /api/drakor/42 GET /api/drakor/{id}/episodes Paginated episodes for a DrakorIndo drama Parameter Type Required Description id number required Drama ID (integer) page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) expires_in number optional Signed URL TTL in seconds (max 14400, default 1800) Example /api/drakor/42/episodes?page=1&per_page=50 Episode Response Shape Each episode object contains video_url (primary, signed) and a qualities JSON object with all available resolutions. All videos are hardsub Indonesian -- no separate subtitle tracks. Episode object Copy { "id": 456, "drama_id": 78, "episode_index": 1, "episode_name":"Episode 1", "status":"published", // Primary video -- HMAC-SHA256 signed, 30min TTL "video_url":"https://cdn.splay.id/drakorindo/.../video.mp4?sig=...&expires=...", // All available resolutions -- same signed CDN URLs "qualities": { "480p":"https://cdn.splay.id/.../video_480p.mp4?sig=...&expires=...", "720p":"https://cdn.splay.id/.../video.mp4?sig=...&expires=...", "1080p":"https://cdn.splay.id/.../video_1080p.mp4?sig=...&expires=..." }, // No subtitles array -- videos are hardsub Indonesian "subtitles": null, "released_at":"2026-03-16T00:00:00Z", "created_at":"2026-03-18T08:00:00Z" } Rich Metadata (raw_data) Drama detail responses include a raw_data field with DrakorIndo-specific metadata not available in the standard Drama model. raw_data in drama detail Copy { "korean_title":"클라이맥스", "year": 2026, "status":"ongoing", "director":"Lee Ji-won", "rating": 8.4, "rating_count": 39633, "genres": ["Mystery", "Drama"], "country":"South Korea", "cast": [ {"actor":"Ju Ji-hoon","character":"Bang Tae-seop"}, {"actor":"Ha Ji-won","character":"Choo Sang-ah"} ], "duration":"59:36", "media_type":"series" } Pagination All list endpoints return paginated responses with a meta object containing pagination info. Response meta Copy { "data": [...], "meta": { "page": 1, "per_page": 20, "total": 1200, "total_pages": 60 } } DrakorIndo API Code Examples Ready-to-run examples for all DrakorIndo endpoints. Paste your API key to try live requests directly in the browser. Your API Key Active Paste your API key to authenticate the "Try" buttons and inject it into code examples. Get your key → sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc Save Clear Try It Live Browse GET /api/drakor?per_page=5 Send 403 190ms 0.1 KB Copy Collapse { "error": { "code": "FORBIDDEN", "message": "IP 2a09:bac1:6500:8::3c3:40 is not in the whitelist for this API key." } } GET /api/drakor?type=series&per_page=5 Send GET /api/drakor?type=movie&per_page=5 Send GET /api/drakor/popular?type=series&per_page=5 Send GET /api/drakor/popular?type=movie&per_page=5 Send GET /api/drakor/trending?per_page=5 Send GET /api/drakor/alphabet Send GET /api/drakor/alphabet?letter=V&per_page=5 Send Detail & Episodes GET /api/drakor/42 Send GET /api/drakor/42/episodes?per_page=5 Send GET /api/drakor/42/episodes?per_page=5&expires_in=7200 Send Search GET /api/drakor/search?q=love&per_page=5 Send GET /api/drakor/search?q=my+name&type=series&per_page=5 Send GET /api/drakor/search?q=squid&type=movie&per_page=5 Send cURL cURL Examples Copy API_KEY="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" BASE="https://api.splay.id" # -- Browse -- curl -H "Authorization: Bearer $API_KEY" "$BASE/api/drakor?per_page=20&type=series" curl -H "Authorization: Bearer $API_KEY" "$BASE/api/drakor?per_page=20&type=movie" curl -H "Authorization: Bearer $API_KEY" "$BASE/api/drakor/popular?type=series&per_page=10" curl -H "Authorization: Bearer $API_KEY" "$BASE/api/drakor/trending?per_page=10" curl -H "Authorization: Bearer $API_KEY" "$BASE/api/drakor/alphabet" curl -H "Authorization: Bearer $API_KEY" "$BASE/api/drakor/alphabet?letter=V&type=series" # -- Detail & episodes -- curl -H "Authorization: Bearer $API_KEY" "$BASE/api/drakor/42" curl -H "Authorization: Bearer $API_KEY" "$BASE/api/drakor/42/episodes?per_page=50&expires_in=7200" # -- Search -- curl -H "Authorization: Bearer $API_KEY" "$BASE/api/drakor/search?q=vincenzo&type=series" JavaScript / TypeScript Full Example Copy const BASE = "https://api.splay.id"; const API_KEY = "sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // -- List series -- const { data, meta } = await fetch( `${BASE}/api/drakor?type=series&per_page=20`, { headers } ).then(r => r.json()); console.log(`${meta.total} Korean drama series`); data.forEach(d => console.log(`[${d.id}] ${d.title} — ${d.chapter_count} eps`)); // -- Drama detail -- const { data: drama } = await fetch(`${BASE}/api/drakor/42`, { headers }).then(r => r.json()); console.log(drama.title, drama.raw_data?.korean_title); console.log("Director:", drama.raw_data?.director); console.log("Rating:", drama.raw_data?.rating); // -- Episodes with signed URLs (2h TTL) -- const { data: eps } = await fetch( `${BASE}/api/drakor/42/episodes?per_page=50&expires_in=7200`, { headers } ).then(r => r.json()); const ep1 = eps[0]; // Pick best available quality const url = ep1.qualities?.["1080p"] ?? ep1.qualities?.["720p"] ?? ep1.video_url; console.log(`Ep 1 → ${url}`); // -- Search -- const search = await fetch( `${BASE}/api/drakor/search?q=the+glory&type=series&per_page=5`, { headers } ).then(r => r.json()); console.log(`Found ${search.meta.total} results`); search.data.forEach(d => console.log(` ${d.title}`)); Python Full Example Copy import requests BASE = "https://api.splay.id" API_KEY = "sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" headers = {"Authorization": f"Bearer {API_KEY}"} # -- List Korean drama series -- res = requests.get(f"{BASE}/api/drakor", params={"type": "series", "per_page": 20}, headers=headers) body = res.json() print(f"{body['meta']['total']} series, {body['meta']['total_pages']} pages") for d in body["data"]: print(f" [{d['id']}] {d['title']} — {d['chapter_count']} eps") # -- Drama detail + raw_data -- detail = requests.get(f"{BASE}/api/drakor/42", headers=headers).json()["data"] raw = detail.get("raw_data", {}) print(f" {detail['title']}") print(f" Korean: {raw.get('korean_title')}") print(f" Director: {raw.get('director')}") print(f" Rating: {raw.get('rating')}/10") print(f" Cast: {', '.join(c['actor'] for c in raw.get('cast', [])[:3])}") # -- All episodes with 2h signed URLs -- page, all_eps = 1, [] while True: r = requests.get( f"{BASE}/api/drakor/42/episodes", params={"page": page, "per_page": 50, "expires_in": 7200}, headers=headers ).json() all_eps.extend(r["data"]) if page >= r["meta"]["total_pages"]: break page += 1 for ep in all_eps: url = (ep.get("qualities") or {}).get("1080p") or ep.get("video_url") print(f" Ep {ep['episode_index']}: {url[:60]}...") # -- Search -- results = requests.get( f"{BASE}/api/drakor/search", params={"q": "vincenzo", "type": "series", "per_page": 5}, headers=headers ).json() print(f" Search: {results['meta']['total']} results") for d in results["data"]: print(f" {d['title']}") PHP Full Example Copy true, CURLOPT_HTTPHEADER => ["Authorization: Bearer $apiKey", "Accept: application/json"], CURLOPT_TIMEOUT => 10, ]); $body = curl_exec($ch); curl_close($ch); return json_decode($body, true) ?? []; } // -- List series -- $list = drakor("/api/drakor", $API_KEY, ["type" => "series", "per_page" => 10]); foreach ($list["data"] as $d) { echo "[{$d['id']}] {$d['title']} — {$d['chapter_count']} eps "; } // -- Drama detail -- $detail = drakor("/api/drakor/42", $API_KEY); $drama = $detail["data"]; $raw = $drama["raw_data"] ?? []; echo "{$drama['title']} ({$raw['korean_title']}) "; echo "Director: {$raw['director']}, Rating: {$raw['rating']} "; // -- Episodes -- $eps = drakor("/api/drakor/42/episodes", $API_KEY, ["per_page" => 50, "expires_in" => 7200]); foreach ($eps["data"] as $ep) { $url = $ep["qualities"]["720p"] ?? $ep["video_url"]; echo "Ep {$ep['episode_index']}: $url "; } // -- Search -- $search = drakor("/api/drakor/search", $API_KEY, ["q" => "my name", "type" => "series"]); echo "Found {$search['meta']['total']} results "; WeTV API WeTV Overview Tencent Video International content — Asian dramas, variety shows, and anime. Multi-quality video (up to 1080p), multi-language subtitles, HMAC-signed CDN URLs. Same familiar Drama/Episode data model used across the platform. Titles Growing Episodes Growing Quality 240p-1080p Subtitles Multi-lang Base URL Base URL https://api.splay.id GET /api/wetv?per_page=20 Data Model WeTV uses the same Drama and Episode types as the Short Drama API. Each drama has a title, cover image, tags, introduction, and episode list. Each episode includes signed video URLs with multiple quality levels and subtitle tracks. Field Type Description id number Unique drama ID title string Drama title cover_url string Signed cover image URL provider_slug string Provider identifier (e.g. wetv) chapter_count number Total episode count introduction string Drama synopsis tags Tag[] Genre/category tags episodes Episode[] Episode list with video URLs Video Quality Each episode has a primary video_url and a qualities JSON object with all available resolutions. Quality JSON key in qualities{} Notes 240p qualities["240p"] Low bandwidth fallback 360p qualities["360p"] Available on most content 480p qualities["480p"] Standard definition 720p video_url · qualities["720p"] Primary -- HD 1080p qualities["1080p"] Full HD -- premium content All video URLs are HMAC-SHA256 signed with 1-hour TTL. Use video_url as your primary source; fall back through qualities for other resolutions. Authentication Same API Key WeTV endpoints use the same Authorization: Bearer authentication as all other APIs. Get your key atapi-dashboard. Quick Example GET /api/wetv Copy curl"https://api.splay.id/api/wetv?per_page=20"\ -H"Authorization: Bearer " WeTV API Endpoints Dedicated /api/wetv/* endpoints for WeTV content. All endpoints follow the same patterns as the Short Drama API -- pagination, sorting, filtering, and signed video URLs. Authentication Required All data endpoints require Authorization: Bearer . Get your key atapi-dashboard. GET /api/wetv List WeTV dramas -- paginated, with filtering and sorting Parameter Type Required Description page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) provider string optional Filter by provider slug tag string optional Filter by tag name language string optional ISO 639-1 language code (en, zh, ko, ...) sort_by string optional updated_at | created_at | title | play_count | chapter_count sort_order string optional desc | asc Example /api/wetv?per_page=20&sort_by=updated_at GET /api/wetv/popular Popular WeTV dramas ranked by play count Parameter Type Required Description page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) language string optional ISO 639-1 language code Example /api/wetv/popular?per_page=10 GET /api/wetv/trending Trending WeTV dramas (recently updated, sorted by play count) Parameter Type Required Description page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) language string optional ISO 639-1 language code Example /api/wetv/trending GET /api/wetv/search Full-text search across WeTV dramas Parameter Type Required Description q string required Search query page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) Example /api/wetv/search?q=love GET /api/wetv/alphabet Browse A-Z -- returns letter counts, or dramas starting with a specific letter Parameter Type Required Description letter string optional Single letter (A-Z) to filter dramas. Omit for letter counts. page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) Example /api/wetv/alphabet?letter=L GET /api/wetv/{id} Get WeTV drama detail with all episodes and signed video URLs Parameter Type Required Description id number required Drama ID (integer) expires_in number optional Signed URL TTL in seconds (max 14400, default 1800) Example /api/wetv/42 GET /api/wetv/{id}/episodes Paginated episodes for a WeTV drama Parameter Type Required Description id number required Drama ID (integer) page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) expires_in number optional Signed URL TTL in seconds (max 14400, default 1800) Example /api/wetv/42/episodes?page=1&per_page=50 Episode Response Shape Each episode object contains video_url (primary, signed) and a qualities JSON object with all available resolutions. Episode object Copy { "id": 456, "drama_id": 78, "episode_index": 1, "episode_name":"Episode 1", "status":"published", // Primary video -- HMAC-SHA256 signed, 1h TTL "video_url":"https://cdn.splay.id/wetv/.../video.mp4?sig=...&expires=...", // All available resolutions -- same signed CDN URLs "qualities": { "240p":"https://cdn.splay.id/.../video_240p.mp4?sig=...&expires=...", "360p":"https://cdn.splay.id/.../video_360p.mp4?sig=...&expires=...", "480p":"https://cdn.splay.id/.../video_480p.mp4?sig=...&expires=...", "720p":"https://cdn.splay.id/.../video.mp4?sig=...&expires=...", "1080p":"https://cdn.splay.id/.../video_1080p.mp4?sig=...&expires=..." }, // Subtitles -- signed SRT URLs "subtitles": [ {"lang":"en","label":"English","url":"https://cdn.splay.id/.../subtitle_en.srt?sig=..."}, {"lang":"zh","label":"Chinese","url":"https://cdn.splay.id/.../subtitle_zh.srt?sig=..."}, {"lang":"id","label":"Indonesian","url":"https://cdn.splay.id/.../subtitle_id.srt?sig=..."} ], "released_at":"2025-08-01T00:00:00Z", "created_at":"2026-02-20T08:00:00Z" } Pagination All list endpoints return paginated responses with a meta object containing pagination info. Response meta Copy { "data": [...], "meta": { "page": 1, "per_page": 20, "total": 800, "total_pages": 40 } } WeTV API Code Examples Ready-to-use examples for the WeTV API -- browse dramas, search, video playback, and subtitle handling. Your API Key Active Paste your API key to authenticate the "Try" buttons and inject it into code examples.Get your key → sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc Save Clear Try It Live Browse Content GET /api/wetv?per_page=5 Send 403 164ms 0.1 KB Copy Collapse { "error": { "code": "FORBIDDEN", "message": "IP 2a09:bac1:6500:8::3c3:40 is not in the whitelist for this API key." } } GET /api/wetv?sort_by=updated_at&sort_order=desc&per_page=5 Send GET /api/wetv/popular?per_page=5 Send GET /api/wetv/trending?per_page=5 Send GET /api/wetv/alphabet Send GET /api/wetv/alphabet?letter=L&per_page=5 Send Search GET /api/wetv/search?q=love&per_page=5 Send cURL cURL Examples Copy API_KEY="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" BASE="https://api.splay.id" # -- List dramas -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/wetv?per_page=20" # -- Sort by latest updated -- curl -H"Authorization: Bearer $API_KEY"\ "$BASE/api/wetv?sort_by=updated_at&sort_order=desc&per_page=20" # -- Popular dramas -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/wetv/popular" # -- Trending dramas -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/wetv/trending" # -- Browse A-Z (get letter counts) -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/wetv/alphabet" # -- Browse letter L -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/wetv/alphabet?letter=L" # -- Search -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/wetv/search?q=love" # -- Drama detail (all episodes + signed video URLs) -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/wetv/DRAMA_ID" # -- Paginated episodes -- curl -H"Authorization: Bearer $API_KEY"\ "$BASE/api/wetv/DRAMA_ID/episodes?page=1&per_page=50" JavaScript / TypeScript Browse & Search Copy const BASE ="https://api.splay.id"; const API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // -- List dramas (paginated) -- const res = await fetch(`${BASE}/api/wetv?per_page=20`, { headers }); const { data, meta } = await res.json(); console.log(`${meta.total} dramas (page ${meta.page}/${meta.total_pages})`); data.forEach(d => console.log(`[${d.id}] ${d.title}`)); // -- Popular -- const { data: popular } = await ( await fetch(`${BASE}/api/wetv/popular`, { headers }) ).json(); // -- Trending -- const { data: trending } = await ( await fetch(`${BASE}/api/wetv/trending`, { headers }) ).json(); // -- Search -- const { data: results, meta: searchMeta } = await ( await fetch(`${BASE}/api/wetv/search?q=love`, { headers }) ).json(); console.log(`Found ${searchMeta.total} results`); // -- A-Z Browse -- const { data: letters } = await ( await fetch(`${BASE}/api/wetv/alphabet`, { headers }) ).json(); // letters = [{"letter":"A","count": 42 }, ...] Get Detail + Play Video Copy const BASE ="https://api.splay.id"; const API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // -- Drama detail (drama + episodes with signed URLs) -- const res = await fetch(`${BASE}/api/wetv/DRAMA_ID`, { headers }); const { data: { drama, episodes } } = await res.json(); console.log(`${drama.title} -- ${episodes.length} episodes`); // -- Video URLs -- const ep = episodes[0]; // video_url = primary, signed HMAC-SHA256 console.log("Primary:", ep.video_url); // qualities = all resolutions as JSON object console.log("240p:", ep.qualities?.["240p"]); console.log("360p:", ep.qualities?.["360p"]); console.log("480p:", ep.qualities?.["480p"]); console.log("720p:", ep.qualities?.["720p"]); console.log("1080p:", ep.qualities?.["1080p"]); // -- Pick best available quality -- const videoUrl = ep.qualities?.["1080p"] ?? ep.qualities?.["720p"] ?? ep.video_url ?? ep.qualities?.["480p"] ?? ep.qualities?.["360p"] ?? ep.qualities?.["240p"]; const video = document.querySelector("video"); if (video && videoUrl) { video.src = videoUrl; // direct MP4 -- no HLS library needed video.play(); } // -- Subtitles (signed SRT URLs) -- for (const sub of ep.subtitles ?? []) { console.log(`[${sub.lang}] ${sub.label}: ${sub.url}`); } // -- Paginated episodes -- const { data: eps, meta } = await ( await fetch(`${BASE}/api/wetv/DRAMA_ID/episodes?page=1&per_page=50`, { headers }) ).json(); console.log(`${meta.total} total episodes, showing ${eps.length}`); Python Full Example Copy import requests BASE ="https://api.splay.id" API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" headers = {"Authorization": f"Bearer {API_KEY}"} # -- List dramas -- res = requests.get(f"{BASE}/api/wetv", params={ "per_page": 20,"sort_by":"updated_at","sort_order":"desc" }, headers=headers) for d in res.json()["data"]: print(f"[{d['id']}] {d['title']} ({d['chapter_count']} eps)") # -- Popular dramas -- popular = requests.get(f"{BASE}/api/wetv/popular", headers=headers) for d in popular.json()["data"][:5]: print(f"Popular: {d['title']}") # -- Search -- search = requests.get(f"{BASE}/api/wetv/search", params={ "q":"love","per_page": 10 }, headers=headers) results = search.json() print(f"Found {results['meta']['total']} results") # -- Drama detail with episodes -- detail = requests.get(f"{BASE}/api/wetv/DRAMA_ID", headers=headers) info = detail.json()["data"] drama, episodes = info["drama"], info["episodes"] print(f"\n=== {drama['title']} ===") print(f"Episodes: {len(episodes)}") # -- Video URLs (signed MP4, 1h TTL) -- ep = episodes[0] qualities = ep.get("qualities") or {} video_url = ( qualities.get("1080p") or qualities.get("720p") or ep.get("video_url") or qualities.get("480p") or qualities.get("360p") or qualities.get("240p") ) print(f"\nBest video URL: {video_url}") # -- Subtitles -- for sub in ep.get("subtitles", []): print(f"[{sub['lang']}] {sub['label']}: {sub['url']}") Rate Limits Rate Limiting Rate limits are enforced at two levels: per-IP infrastructure limits via Traefik, and per-plan API key limits per user. Plan-Based Limits (per API key) Every request must include Authorization: Bearer . Limits are tracked per user — all keys on the same account share one bucket. Plan Req / Min Req / Day Content Access Free 60 86,400 Drama Basic 120 172,800 Drama, Anime, MovieBox Advanced 240 345,600 Drama, Anime, MovieBox Pro 480 691,200 All (+ iQIYI, WeTV) Enterprise 960 1,382,400 All Elite 1,920 2,764,800 All Ultimate 5,760 8,294,400 All Exceeded limit returns 429 withX-RateLimit-Limit,X-RateLimit-Remaining, andX-RateLimit-Reset headers.Accessing restricted content returns 402 with upgrade instructions.Upgrade your plan → Content Gating Each plan tier unlocks access to additional content APIs. Accessing a restricted endpoint returns402 UPGRADE_REQUIRED. Free /api/dramas, /api/search, /api/providers, /api/tags Basic+ + /api/anime, /api/moviebox Pro+ + /api/iqiyi, /api/wetv (all content) Infrastructure Limits (per IP) IP Average 200 req/s Traefik token bucket per IP IP Burst 500 req Max burst before throttle Window 1 second Sliding window period How It Works 1 Token Bucket Each IP gets a bucket of 500 tokens. Tokens refill at 200 per second. 2 Request Cost Each API request consumes 1 token from the bucket. 3 Throttling When tokens run out, requests receive a 429 response until tokens refill. 429 Response When rate-limited, the API returns HTTP 429 with aRetry-Afterheader indicating how long to wait (in seconds). Rate Limit Response Copy HTTP/1.1 429 Too Many Requests X-RateLimit-Limit: 60 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1710000060 Content-Type: application/json { "error": { "code":"RATE_LIMITED", "message":"Rate limit exceeded: 60 req/min on free plan. Upgrade for higher limits." } } Best Practices Implement exponential backoff— On 429, wait 1s, then 2s, then 4s before retrying. Cache responses locally— Drama data doesn't change frequently — cache for at least 5 minutes. Use pagination efficiently— Fetch only the pages you need instead of crawling all pages at once. Batch your requests— Space out requests rather than sending bursts. Retry Example JavaScript — Exponential Backoff Copy const API_KEY ="sk_live_..."; const headers = { Authorization: `Bearer ${API_KEY}` }; async function fetchWithRetry(url, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { const res = await fetch(url, { headers }); if (res.status === 429) { const reset = res.headers.get("X-RateLimit-Reset"); const waitMs = reset ? Math.max(0, Number(reset) * 1000 - Date.now()) : Math.pow(2, i) * 1000; // fallback: 1s, 2s, 4s console.log(`Rate limited, retrying in ${waitMs}ms...`); await new Promise(r => setTimeout(r, waitMs)); continue; } return res.json(); } throw new Error("Max retries exceeded"); } Errors Error Handling All errors follow a consistent JSON format. Use the HTTP status code and error code to handle failures. Error Format Error Response Copy { "error": { "code":"VALIDATION_ERROR", "message":"query must be at most 200 characters" } } HTTP Status Codes 400 Bad Request Invalid or missing request parameters 401 Unauthorized Missing or invalid API key — add Authorization: Bearer header 403 Forbidden API key valid but IP not in whitelist 404 Not Found Resource not found (drama, provider, etc.) 422 Validation Error Body or query params failed validation (e.g. query too long) 429 Rate Limited Exceeded plan req/min or req/day limit — check X-RateLimit-* headers 500 Internal Error Server error — database or unexpected failure 503 Service Unavailable Database or Redis is unreachable Error Codes Code HTTP Description UNAUTHORIZED 401 Missing or invalid API key FORBIDDEN 403 IP not in API key whitelist NOT_FOUND 404 Resource not found BAD_REQUEST 400 Invalid request VALIDATION_ERROR 422 Validation failed RATE_LIMITED 429 Plan rate limit exceeded INTERNAL 500 Internal server error SERVICE_UNAVAILABLE 503 Dependency temporarily unavailable, retry later Responses Response Format All responses are JSON. Successful responses wrap data in a 'data' key. Paginated responses include a 'meta' key. Single Resource Success Response Copy { "data": { "drama": { "id": 42, "title":"Love in the City", "provider_name":"DramaBox", "cover_url":"https://cdn.splay.id/dramabox/42/cover.jpg", "introduction":"A romantic drama set in...", "chapter_count": 24, "play_count": 1542, "is_dubbed": false, "created_at":"2024-01-10T10:00:00Z", "updated_at":"2024-01-20T15:00:00Z" }, "tags": [ {"id": 1,"name":"romance","en_name":"Romance"} ], "episodes": [ { "id": 500, "episode_index": 1, "episode_name":"Episode 1", "video_url":"https://cdn.splay.id/.../video.mp4", "subtitle_url":"https://cdn.splay.id/.../subtitle_id.srt", "subtitles": [{"lang":"in","url":"https://cdn.splay.id/.../subtitle_in.srt"}], "qualities": {"1080p":"https://cdn.splay.id/.../video_1080p.mp4","720p":"https://cdn.splay.id/.../video_720p.mp4"}, "status":"published" } ] } } Paginated List Paginated Response Copy { "data": [ { "id": 1, "title":"Love in the City", "provider_name":"DramaBox", "chapter_count": 24, "cover_url":"https://..." }, ... ], "meta": { "page": 1, "per_page": 20, "total": 15000, "total_pages": 750 } } Data Models Drama Copy { "id": 42, // integer "provider_id": 1, // integer "external_id":"drama_123", // string — provider's ID "title":"Love in the City", // string "cover_url":"https://...", // string | null "introduction":"A story about..", // string | null "chapter_count": 24, // integer | null "play_count": 1542, // integer — view counter "shelf_time":"2024-01-10T...", // ISO 8601 | null "is_dubbed": false, // boolean "raw_data": { ... }, // object | null — original provider data "created_at":"2024-01-10T...", // ISO 8601 "updated_at":"2024-01-20T...", // ISO 8601 "provider_slug":"dramabox", // string — joined from providers "provider_name":"DramaBox"// string — joined from providers } Episode Copy { "id": 500, // integer "drama_id": 42, // integer "external_id":"ep_001", // string | null "episode_index": 1, // integer — sort order "episode_name":"Episode 1", // string | null "video_url":"https://...", // string | null — CDN URL (default quality) "subtitle_url":"https://...", // string | null — default subtitle "subtitles": [ // array | null — multi-language subtitles {"lang":"id","url":"https://cdn.splay.id/.../subtitle_id.vtt"}, {"lang":"en","url":"https://cdn.splay.id/.../subtitle_en.vtt"} ], "qualities": { // object | null — multi-quality video URLs "1080p":"https://cdn.splay.id/.../video_1080p.mp4", "720p":"https://cdn.splay.id/.../video_720p.mp4", "480p":"https://cdn.splay.id/.../video_480p.mp4" }, "status":"published", //"published"|"coming_soon"|"removed" "released_at":"2024-01-15T...", // ISO 8601 | null "created_at":"2024-01-10T..."// ISO 8601 } Provider Copy { "id": 1, // integer "slug":"dramabox", // string — URL-safe identifier "name":"DramaBox"// string } Tag Copy { "id": 1, // integer "name":"romance", // string — original name "en_name":"Romance", // string | null — English name "drama_count": 245 // integer — from /api/tags only } Caching Cached responses include an x-cache header with valuehit or miss. The API uses a 2-tier cache: per-instance in-memory (L1, 60s TTL) and shared Redis (L2, configurable TTL). Cache TTLs Copy Static data (providers, tags, status): ~6 hours Drama lists and detail: ~1 hour Search results: ~30 minutes GraphQL API GraphQL Overview Query dramas, anime, movies, and more with a single request. Request exactly the fields you need, combine multiple resources in one call, and explore the API interactively in the playground. Endpoint POST Universes 5+ Max Depth 5 Max Complexity 100 Endpoint GraphQL Endpoint https://api.splay.id/graphql POST Content-Type: application/json Authentication Same API Key as REST The GraphQL endpoint uses the same Authorization: Bearer authentication as all REST endpoints. Get your key at api-dashboard. Plan-based access restrictions apply: Free gets dramas only, Basic adds anime + moviebox, Pro adds iQIYI + WeTV. Why GraphQL? Single Request Fetch a drama and its episodes in one query instead of two REST calls. Request Only What You Need Specify exactly which fields to return -- no wasted bandwidth on unused data. Type Safety Strongly typed schema with introspection. Autocompletion in the playground and code generators. All Universes Short dramas, anime, MovieBox, iQIYI, WeTV, providers, and tags -- all from one endpoint. Quick Example Fetch a drama and its first 5 episodes in a single request -- this would require two separate REST calls. cURL $ curl -X POST https://api.splay.id/graphql \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{"query": "{ drama(id: 1) { title cover_url episodes(first: 5) { title video_url } } }"}' Response Copy { "data": { "drama": { "title": "Hidden Wolf King", "cover_url": "https://cdn.splay.id/...", "episodes": [ { "title": "Episode 1", "video_url": "https://cdn.splay.id/...?sig=..." }, ... ] } } } Rate Limiting 1 GraphQL request = 1 API request. Each POST to /graphql counts as a single request toward your plan rate limit, regardless of how many resources it resolves. The same per-plan limits apply: Free 30 rpm, Basic 120 rpm, Advanced 240 rpm, Pro 480 rpm. Query Limits Limit Value Description Max Depth 5 Nested selections cannot exceed 5 levels deep Max Complexity 100 Total resolved field complexity per query Max Aliases 10 Maximum number of aliased fields per query Introspection Allowed Schema introspection is enabled for development Interactive Playground Explore the full schema, write queries with autocompletion, and test responses in the embedded Apollo Sandbox. Open GraphQL Playground GraphQL API Schema Reference Complete GraphQL schema with all queries, arguments, return types, and field definitions. Use introspection in the playground for live schema discovery. Root Query All data is accessed through the root Query type. The GraphQL endpoint only supports queries (read operations) -- there are no mutations. Query Root Copy type Query { # --- Short Dramas --- drama(id: Int!): DramaDetail dramas(page: Int, perPage: Int, sort: String): DramaPaginated dramasPopular(page: Int, perPage: Int): DramaPaginated dramasTrending(page: Int, perPage: Int): DramaPaginated episodes(dramaId: Int!, page: Int, perPage: Int, expiresIn: Int): EpisodePaginated # --- Search --- search(query: String!, page: Int, perPage: Int): DramaPaginated # --- Anime --- anime(id: String!): AnimeDetail animePopular(page: Int, perPage: Int): AnimePaginated animeLatest(page: Int, perPage: Int): AnimePaginated animeEpisodes(animeId: String!, page: Int, perPage: Int): AnimeEpisodePaginated animeEpisode(animeId: String!, episode: Int!, expiresIn: Int): AnimeEpisodeDetail # --- MovieBox --- moviebox(id: Int!): MovieBoxDetail movieboxList(page: Int, perPage: Int): MovieBoxPaginated movieboxPopular(page: Int, perPage: Int): MovieBoxPaginated movieboxTrending(page: Int, perPage: Int): MovieBoxPaginated movieboxEpisodes(id: Int!, page: Int, perPage: Int): MovieBoxEpisodePaginated # --- DrakorIndo --- drakor(id: Int!): DramaGql drakorList(page: Int, perPage: Int, type: String): DrakorPaginated drakorPopular(page: Int, perPage: Int, type: String): DrakorPaginated drakorTrending(page: Int, perPage: Int, type: String): DrakorPaginated drakorSearch(query: String!, page: Int, perPage: Int, type: String): DrakorPaginated drakorEpisodes(id: Int!, page: Int, perPage: Int, expiresIn: Int): EpisodePaginated # --- iQIYI --- iqiyi(id: Int!): IqiyiDetail iqiyiList(page: Int, perPage: Int): IqiyiPaginated iqiyiPopular(page: Int, perPage: Int): IqiyiPaginated iqiyiTrending(page: Int, perPage: Int): IqiyiPaginated # --- WeTV --- wetv(id: Int!): WetvDetail wetvList(page: Int, perPage: Int): WetvPaginated wetvPopular(page: Int, perPage: Int): WetvPaginated wetvTrending(page: Int, perPage: Int): WetvPaginated # --- Baca (Manga / Manhwa / Manhua) --- baca(category: String!, id: Int!): BacaDetail bacaList(category: String!, page: Int, perPage: Int): BacaPaginated bacaChapters(category: String!, id: Int!, page: Int, perPage: Int, expiresIn: Int): BacaChapterPaginated # --- Static --- providers: [Provider!]! tags: [Tag!]! } Short Drama Types DramaGql Copy type DramaGql { id: Int! title: String! cover_url: String introduction: String chapter_count: Int! play_count: Int! shelf_time: String is_dubbed: Boolean! language: String provider_slug: String! provider_name: String! created_at: String! updated_at: String! tags: [Tag!] } DramaDetail Copy type DramaDetail { drama: DramaGql! episodes: [EpisodeGql!]! } EpisodeGql Copy type EpisodeGql { id: Int! drama_id: Int! title: String episode_index: Int! video_url: String # Signed URL (HMAC-SHA256) subtitle_url: String # Signed subtitle URL if available duration: Int # Duration in seconds qualities: Qualities # Multi-resolution URLs created_at: String! updated_at: String! } type Qualities { "480p": String "720p": String "1080p": String } Pagination Copy type DramaPaginated { data: [DramaGql!]! meta: PaginationMeta! } type EpisodePaginated { data: [EpisodeGql!]! meta: PaginationMeta! } type PaginationMeta { page: Int! per_page: Int! total: Int! total_pages: Int! } Signed URLs: The video_url, subtitle_url, and qualities fields contain HMAC-SHA256 signed URLs. Default TTL is 30 minutes. Use the expiresIn argument on episodes to request up to 14400 seconds (4 hours). Episode Query Arguments Argument Type Default Description dramaId Int! -- Required. The drama ID to fetch episodes for page Int 1 Page number for pagination perPage Int 20 Items per page (max 100) expiresIn Int 1800 Signed URL TTL in seconds (max 14400) Anime Types AnimeGql Copy type AnimeGql { id: String! title: String! japanese_title: String cover_url: String banner_url: String description: String type: String # "TV", "Movie", "OVA", etc. status: String # "Ongoing", "Completed" season: String year: Int rating: String quality: String sub_or_dub: String # "sub", "dub", "both" episode_count: Int genres: [String!] studios: [String!] } AnimeEpisodeGql Copy type AnimeEpisodeGql { episode: Int! title: String video_url: String # Signed HLS URL subtitles: [Subtitle!] intro: TimeRange outro: TimeRange } type Subtitle { url: String! # Signed VTT URL lang: String! label: String } type TimeRange { start: Int! end: Int! } AnimeDetail Copy type AnimeDetail { anime: AnimeGql! episodes: [AnimeEpisodeSummary!]! relations: [AnimeGql!] recommendations: [AnimeGql!] } type AnimeEpisodeSummary { episode: Int! title: String } type AnimeEpisodeDetail { episode: AnimeEpisodeGql! anime: AnimeGql! } MovieBox Types MovieBoxGql Copy type MovieBoxGql { id: Int! title: String! cover_url: String introduction: String chapter_count: Int! year: Int rating: Float language: String provider_slug: String! provider_name: String! tags: [Tag!] } MovieBoxEpisodeGql Copy type MovieBoxEpisodeGql { id: Int! title: String episode_index: Int! video_url: String # Signed MP4 URL subtitle_url: String duration: Int qualities: Qualities # 480p / 720p / 1080p } DrakorIndo Types DrakorIndo uses the standard DramaGql and EpisodeGql types. Use the optional type argument ("series" | "movie") to filter content. All videos are hardsub Indonesian — no separate subtitle tracks. DrakorIndo Queries Copy # --- DrakorIndo --- drakor(id: Int!): DramaGql drakorList(page: Int, perPage: Int, type: String): DrakorPaginated drakorPopular(page: Int, perPage: Int, type: String): DrakorPaginated drakorTrending(page: Int, perPage: Int, type: String): DrakorPaginated drakorSearch(query: String!, page: Int, perPage: Int, type: String): DrakorPaginated drakorEpisodes(id: Int!, page: Int, perPage: Int, expiresIn: Int): EpisodePaginated # Types reuse the standard drama model: type DrakorPaginated { data: [DramaGql!]! meta: PaginationMeta! } # type filter values: # "series" — full-length Korean drama series (10-20+ episodes) # "movie" — Korean movies (single video, 90m-150m) # omitted — both series and movies combined iQIYI and WeTV Types iQIYI and WeTV share the same base drama structure. They use the standard DramaGql and EpisodeGql types with provider-specific slugs. iQIYI / WeTV Copy # iQIYI and WeTV reuse the standard types: # - IqiyiDetail = DramaDetail (drama + episodes) # - IqiyiPaginated = DramaPaginated # - WetvDetail = DramaDetail # - WetvPaginated = DramaPaginated # # Access is plan-gated: # iQIYI — Pro plan and above # WeTV — Pro plan and above type IqiyiDetail { drama: DramaGql! episodes: [EpisodeGql!]! } type WetvDetail { drama: DramaGql! episodes: [EpisodeGql!]! } Baca Types (Manga / Manhwa / Manhua) Baca reuses the standard DramaGql and EpisodeGql types. The category argument must be "manga", "manhwa", or "manhua". Chapters use video_url as a signed directory path, and qualities contains page count and format. Baca Types Copy # Baca reuses standard types with image-specific fields: # - BacaDetail = DramaDetail (drama + chapters) # - BacaPaginated = DramaPaginated # - BacaChapterPaginated = EpisodePaginated # # Chapter (EpisodeGql) fields for Baca: # video_url: signed chapter directory URL # qualities: { "pages": N, "format": "webp" } # # Construct image URLs: # {video_url}/001.webp?sig=...&expires=... # {video_url}/002.webp?sig=...&expires=... # ... up to qualities.pages type BacaDetail { drama: DramaGql! episodes: [EpisodeGql!]! # chapters } type BacaChapterPaginated { data: [EpisodeGql!]! # chapters with signed image URLs meta: PaginationMeta! } Static Types Provider & Tag Copy type Provider { id: Int! name: String! slug: String! drama_count: Int! base_url: String } type Tag { id: Int! name: String! slug: String! drama_count: Int! } Sorting The sort argument on dramas accepts the following values: Value Description updated_at Most recently updated (default) created_at Most recently added title Alphabetical by title chapter_count Most episodes first play_count Most played first Schema introspection is enabled. You can send an introspection query or use the GraphQL Playground to explore the full schema interactively with autocompletion and inline documentation. GraphQL API Query Examples Practical GraphQL queries for all seven universes. Each example shows the query and explains what it does. Copy and paste into the playground or your application. 1. Drama with Episodes Fetch a drama and its first 5 episodes in a single request. This replaces two REST calls: GET /api/dramas/1 and GET /api/dramas/1/episodes. GraphQL Copy query DramaWithEpisodes { drama(id: 1) { drama { id title cover_url introduction chapter_count provider_name language tags { name } } episodes { episode_index title video_url subtitle_url duration qualities { _480p _720p _1080p } } } } The episodes field in DramaDetail returns all episodes by default. For large series, use the standalone episodes(dramaId, page, perPage) query with pagination instead. 2. Search with Pagination Full-text search across all dramas with pagination metadata. GraphQL Copy query SearchDramas { search(query: "wolf king", page: 1, perPage: 10) { data { id title cover_url provider_name chapter_count language } meta { page per_page total total_pages } } } 3. Anime Episode with Signed Video URL Fetch a specific anime episode with HLS video URL and subtitles. Use expiresIn to extend the signed URL TTL up to 4 hours. GraphQL Copy query AnimeEpisode { animeEpisode( animeId: "one-piece-100" episode: 1 expiresIn: 7200 ) { anime { title japanese_title cover_url status genres } episode { episode title video_url subtitles { url lang label } intro { start end } outro { start end } } } } Anime requires Basic plan or above. Free plan keys will receive an authorization error when querying anime endpoints. 4. MovieBox Movie with Subtitles Fetch a MovieBox movie detail with all available resolution qualities and subtitle URLs. GraphQL Copy query MovieBoxDetail { moviebox(id: 42) { drama { id title cover_url introduction chapter_count tags { name } } episodes { episode_index title video_url subtitle_url duration qualities { _480p _720p _1080p } } } } 5. Baca Manga Chapters Fetch a manga title and its chapters. Each chapter's video_url is a signed directory path. Append page filenames (001.webp, 002.webp, ...) to construct image URLs. The qualities field contains the page count and format. GraphQL Copy query BacaMangaChapters { # Get title detail baca(category: "manga", id: 42) { drama { id title cover_url introduction chapter_count tags { name } } episodes { episode_index title video_url # signed chapter directory URL qualities # { "pages": 24, "format": "webp" } } } # Or paginate chapters separately bacaChapters( category: "manga" id: 42 page: 1 perPage: 25 expiresIn: 7200 ) { data { episode_index title video_url qualities } meta { page per_page total total_pages } } } # To render chapter images: # 1. Parse video_url to extract sig and expires params # 2. For page 1..qualities.pages: # {video_url}/{page:03d}.webp?sig=...&expires=... 6. DrakorIndo — Series + Movie Episodes Fetch a Korean drama series with its episodes. The optional type argument filters by "series" or "movie". All videos are hardsub Indonesian — no separate subtitle tracks. GraphQL Copy # List Korean drama series query DrakorSeries { drakorList(page: 1, perPage: 10, type: "series") { data { id title cover_url introduction chapter_count provider_slug tags { name } } meta { page per_page total total_pages } } } # Get a single drama + first 10 episodes (all resolutions) query DrakorDetail { drakor(id: 42) { id title cover_url introduction chapter_count tags { name } } } # Paginated episodes with signed video URLs query DrakorEpisodes { drakorEpisodes(id: 42, page: 1, perPage: 20, expiresIn: 7200) { data { episode_index video_url # 720p primary (HMAC-SHA256 signed) qualities { _480p _720p _1080p } } meta { page per_page total } } } # Search for a Korean drama query DrakorSearch { drakorSearch(query: "vincenzo", type: "series", perPage: 5) { data { id title cover_url chapter_count } meta { total } } } # Movie list query DrakorMovies { drakorList(type: "movie", perPage: 10) { data { id title cover_url chapter_count } meta { total total_pages } } } # Popular dramas query DrakorPopular { drakorPopular(perPage: 5) { data { id title cover_url } } } 7. All Providers List all content providers with their drama counts. GraphQL Copy query AllProviders { providers { id name slug drama_count } tags { name slug drama_count } } 8. Multi-Universe Dashboard Fetch popular content from multiple universes in a single request -- ideal for building a homepage or dashboard. GraphQL Copy query Dashboard { popularDramas: dramasPopular(perPage: 5) { data { id title cover_url provider_name } } popularAnime: animePopular(perPage: 5) { data { id title cover_url genres } } popularMovies: movieboxPopular(perPage: 5) { data { id title cover_url rating } } } Using aliases (popularDramas, popularAnime, etc.) lets you query the same type multiple times with different arguments in a single request. 9. JavaScript / TypeScript Minimal fetch example -- no GraphQL client library needed. JavaScript Copy const API_KEY = "sk_live_..."; async function graphql(query, variables = {}) { const res = await fetch("https://api.splay.id/graphql", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${API_KEY}`, }, body: JSON.stringify({ query, variables }), }); const json = await res.json(); if (json.errors) throw new Error(json.errors[0].message); return json.data; } // --- Fetch drama + episodes --- const { drama } = await graphql(` query ($id: Int!) { drama(id: $id) { drama { title chapter_count provider_name } episodes { episode_index title video_url } } } `, { id: 1 }); console.log(drama.drama.title); drama.episodes.forEach(ep => console.log(` Ep ${ep.episode_index}: ${ep.title}`) ); // --- Search --- const { search } = await graphql(` query ($q: String!) { search(query: $q, perPage: 5) { data { id title provider_name } meta { total } } } `, { q: "hidden love" }); console.log(`Found ${search.meta.total} results`); // --- Multi-universe dashboard --- const data = await graphql(`{ dramasPopular(perPage: 3) { data { title } } animePopular(perPage: 3) { data { title } } providers { name drama_count } }`); 10. Python Using the standard requests library. Python Copy import requests API_KEY = "sk_live_..." ENDPOINT = "https://api.splay.id/graphql" HEADERS = { "Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}", } def graphql(query: str, variables: dict = None) -> dict: payload = {"query": query} if variables: payload["variables"] = variables res = requests.post(ENDPOINT, json=payload, headers=HEADERS) res.raise_for_status() body = res.json() if "errors" in body: raise Exception(body["errors"][0]["message"]) return body["data"] # --- Fetch drama --- data = graphql(""" query ($id: Int!) { drama(id: $id) { drama { title chapter_count } episodes { episode_index video_url } } } """, {"id": 1}) drama = data["drama"]["drama"] print(f"{drama['title']} -- {drama['chapter_count']} episodes") for ep in data["drama"]["episodes"][:5]: print(f" Ep {ep['episode_index']}: {ep['video_url'][:60]}...") # --- Search --- results = graphql(""" query ($q: String!) { search(query: $q, perPage: 5) { data { id title provider_name } meta { total total_pages } } } """, {"q": "revenge"}) print(f"\nFound {results['search']['meta']['total']} results") for d in results["search"]["data"]: print(f" [{d['id']}] {d['title']} ({d['provider_name']})") # --- Anime episode with subtitles --- anime = graphql(""" query ($aid: String!, $ep: Int!) { animeEpisode(animeId: $aid, episode: $ep) { anime { title } episode { video_url subtitles { lang url } } } } """, {"aid": "one-piece-100", "ep": 1}) ep = anime["animeEpisode"] print(f"\n{ep['anime']['title']} Ep 1") print(f" HLS: {ep['episode']['video_url'][:60]}...") for sub in ep["episode"]["subtitles"]: print(f" Sub [{sub['lang']}]: {sub['url'][:60]}...") Error Handling GraphQL errors are returned in the errors array alongside any partial data. The HTTP status is always 200 for valid GraphQL requests -- check the errors array. Error Response Copy { "data": null, "errors": [ { "message": "Drama not found", "locations": [{ "line": 2, "column": 3 }], "path": ["drama"], "extensions": { "code": "NOT_FOUND" } } ] } HTTP 401 / 403 / 429 are still returned as standard HTTP errors (not GraphQL errors) for authentication failures, plan restrictions, and rate limiting. Always check the HTTP status code first. Try all these queries interactively in the GraphQL Playground with autocompletion, schema explorer, and response formatting. { "info": { "name": "SPlay API", "description": "Complete API collection for SPlay — 7 content APIs (Short Drama, Anime, MovieBox, iQIYI, WeTV, DrakorIndo, Baca). Base URL: https://api.splay.id", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "auth": { "type": "bearer", "bearer": [{ "key": "token", "value": "{{API_KEY}}", "type": "string" }] }, "variable": [ { "key": "BASE_URL", "value": "https://api.splay.id" }, { "key": "API_KEY", "value": "YOUR_API_KEY" } ], "item": [ { "name": "Health & Status", "item": [ { "name": "Health Check", "request": { "method": "GET", "url": "{{BASE_URL}}/health" } }, { "name": "API Status", "request": { "method": "GET", "url": "{{BASE_URL}}/api/status" } }, { "name": "Content Types", "request": { "method": "GET", "url": "{{BASE_URL}}/api/content-types" } }, { "name": "RPS Metrics", "request": { "method": "GET", "url": "{{BASE_URL}}/api/metrics/rps?minutes=60" } } ] }, { "name": "Short Drama", "item": [ { "name": "List Dramas", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas?page=1&per_page=20" } }, { "name": "Popular Dramas", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/popular?per_page=20" } }, { "name": "Trending Dramas", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/trending?per_page=20" } }, { "name": "Search Dramas", "request": { "method": "GET", "url": "{{BASE_URL}}/api/search?q=love&per_page=10" } }, { "name": "Drama Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/1" } }, { "name": "Drama Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/1/episodes?page=1&per_page=100" } }, { "name": "Alphabet Counts", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/alphabet" } }, { "name": "Alphabet List", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/alphabet?letter=A&per_page=20" } }, { "name": "Providers", "request": { "method": "GET", "url": "{{BASE_URL}}/api/providers" } }, { "name": "Tags", "request": { "method": "GET", "url": "{{BASE_URL}}/api/tags" } } ] }, { "name": "Anime", "item": [ { "name": "List Anime", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime?page=1&per_page=20" } }, { "name": "Popular Anime", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/popular?per_page=20" } }, { "name": "Latest Update", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/latest-update?per_page=20" } }, { "name": "Search Anime", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/search?q=naruto&per_page=10" } }, { "name": "Anime Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/one-piece" } }, { "name": "Anime Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/one-piece/episodes?page=1&per_page=25" } }, { "name": "Single Episode", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/one-piece/episodes/1" } }, { "name": "Genres", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/genres" } }, { "name": "Alphabet", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/alphabet" } } ] }, { "name": "MovieBox", "item": [ { "name": "List Movies", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox?type=movies&page=1&per_page=20" } }, { "name": "List Series", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox?type=series&page=1&per_page=20" } }, { "name": "Popular", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox/popular?type=movies&per_page=20" } }, { "name": "Trending", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox/trending?per_page=20" } }, { "name": "Search", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox/search?q=batman&per_page=10" } }, { "name": "Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox/1" } }, { "name": "Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox/1/episodes?page=1&per_page=100" } } ] }, { "name": "iQIYI", "item": [ { "name": "List", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi?page=1&per_page=20" } }, { "name": "Popular", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi/popular?per_page=20" } }, { "name": "Trending", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi/trending?per_page=20" } }, { "name": "Search", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi/search?q=love&per_page=10" } }, { "name": "Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi/1" } }, { "name": "Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi/1/episodes?page=1&per_page=100" } } ] }, { "name": "WeTV", "item": [ { "name": "List", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv?page=1&per_page=20" } }, { "name": "Popular", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv/popular?per_page=20" } }, { "name": "Trending", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv/trending?per_page=20" } }, { "name": "Search", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv/search?q=drama&per_page=10" } }, { "name": "Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv/1" } }, { "name": "Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv/1/episodes?page=1&per_page=100" } } ] }, { "name": "DrakorIndo", "item": [ { "name": "List Series", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor?type=series&page=1&per_page=20" } }, { "name": "List Movies", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor?type=movie&page=1&per_page=20" } }, { "name": "Popular", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor/popular?type=series&per_page=20" } }, { "name": "Trending", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor/trending?per_page=20" } }, { "name": "Search", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor/search?q=love&per_page=10" } }, { "name": "Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor/1" } }, { "name": "Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor/1/episodes?page=1&per_page=100" } } ] }, { "name": "Baca (Manga)", "item": [ { "name": "List Manhwa", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhwa?page=1&per_page=20" } }, { "name": "List Manga", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manga?page=1&per_page=20" } }, { "name": "List Manhua", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhua?page=1&per_page=20" } }, { "name": "Popular Manhwa", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhwa/popular?per_page=20" } }, { "name": "Search Manhwa", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhwa/search?q=solo&per_page=10" } }, { "name": "Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhwa/1" } }, { "name": "Chapters", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhwa/1/chapters?page=1&per_page=100" } } ] } ] } { "info": { "name": "SPlay API", "description": "Complete API collection for SPlay — 7 content APIs (Short Drama, Anime, MovieBox, iQIYI, WeTV, DrakorIndo, Baca). Base URL: https://api.splay.id", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "auth": { "type": "bearer", "bearer": [ { "key": "token", "value": "{{API_KEY}}", "type": "string" } ] }, "variable": [ { "key": "BASE_URL", "value": "https://api.splay.id" }, { "key": "API_KEY", "value": "YOUR_API_KEY" } ], "item": [ { "name": "Health & Status", "item": [ { "name": "Health Check", "request": { "method": "GET", "url": "{{BASE_URL}}/health" } }, { "name": "API Status", "request": { "method": "GET", "url": "{{BASE_URL}}/api/status" } }, { "name": "Content Types", "request": { "method": "GET", "url": "{{BASE_URL}}/api/content-types" } }, { "name": "RPS Metrics", "request": { "method": "GET", "url": "{{BASE_URL}}/api/metrics/rps?minutes=60" } } ] }, { "name": "Short Drama", "item": [ { "name": "List Dramas", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas?page=1&per_page=20" } }, { "name": "Popular Dramas", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/popular?per_page=20" } }, { "name": "Trending Dramas", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/trending?per_page=20" } }, { "name": "Search Dramas", "request": { "method": "GET", "url": "{{BASE_URL}}/api/search?q=love&per_page=10" } }, { "name": "Drama Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/1" } }, { "name": "Drama Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/1/episodes?page=1&per_page=100" } }, { "name": "Alphabet Counts", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/alphabet" } }, { "name": "Alphabet List", "request": { "method": "GET", "url": "{{BASE_URL}}/api/dramas/alphabet?letter=A&per_page=20" } }, { "name": "Providers", "request": { "method": "GET", "url": "{{BASE_URL}}/api/providers" } }, { "name": "Tags", "request": { "method": "GET", "url": "{{BASE_URL}}/api/tags" } } ] }, { "name": "Anime", "item": [ { "name": "List Anime", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime?page=1&per_page=20" } }, { "name": "Popular Anime", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/popular?per_page=20" } }, { "name": "Latest Update", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/latest-update?per_page=20" } }, { "name": "Search Anime", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/search?q=naruto&per_page=10" } }, { "name": "Anime Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/one-piece" } }, { "name": "Anime Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/one-piece/episodes?page=1&per_page=25" } }, { "name": "Single Episode", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/one-piece/episodes/1" } }, { "name": "Genres", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/genres" } }, { "name": "Alphabet", "request": { "method": "GET", "url": "{{BASE_URL}}/api/anime/alphabet" } } ] }, { "name": "MovieBox", "item": [ { "name": "List Movies", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox?type=movies&page=1&per_page=20" } }, { "name": "List Series", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox?type=series&page=1&per_page=20" } }, { "name": "Popular", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox/popular?type=movies&per_page=20" } }, { "name": "Trending", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox/trending?per_page=20" } }, { "name": "Search", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox/search?q=batman&per_page=10" } }, { "name": "Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox/1" } }, { "name": "Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/moviebox/1/episodes?page=1&per_page=100" } } ] }, { "name": "iQIYI", "item": [ { "name": "List", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi?page=1&per_page=20" } }, { "name": "Popular", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi/popular?per_page=20" } }, { "name": "Trending", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi/trending?per_page=20" } }, { "name": "Search", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi/search?q=love&per_page=10" } }, { "name": "Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi/1" } }, { "name": "Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/iqiyi/1/episodes?page=1&per_page=100" } } ] }, { "name": "WeTV", "item": [ { "name": "List", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv?page=1&per_page=20" } }, { "name": "Popular", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv/popular?per_page=20" } }, { "name": "Trending", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv/trending?per_page=20" } }, { "name": "Search", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv/search?q=drama&per_page=10" } }, { "name": "Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv/1" } }, { "name": "Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/wetv/1/episodes?page=1&per_page=100" } } ] }, { "name": "DrakorIndo", "item": [ { "name": "List Series", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor?type=series&page=1&per_page=20" } }, { "name": "List Movies", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor?type=movie&page=1&per_page=20" } }, { "name": "Popular", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor/popular?type=series&per_page=20" } }, { "name": "Trending", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor/trending?per_page=20" } }, { "name": "Search", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor/search?q=love&per_page=10" } }, { "name": "Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor/1" } }, { "name": "Episodes", "request": { "method": "GET", "url": "{{BASE_URL}}/api/drakor/1/episodes?page=1&per_page=100" } } ] }, { "name": "Baca (Manga)", "item": [ { "name": "List Manhwa", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhwa?page=1&per_page=20" } }, { "name": "List Manga", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manga?page=1&per_page=20" } }, { "name": "List Manhua", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhua?page=1&per_page=20" } }, { "name": "Popular Manhwa", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhwa/popular?per_page=20" } }, { "name": "Search Manhwa", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhwa/search?q=solo&per_page=10" } }, { "name": "Detail", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhwa/1" } }, { "name": "Chapters", "request": { "method": "GET", "url": "{{BASE_URL}}/api/baca/manhwa/1/chapters?page=1&per_page=100" } } ] } ] } Quick Start Up and Running in 2 Steps Register for a free API key and start fetching drama data in minutes. 00 Get an API Key All API endpoints require an Authorization: Bearer header. Register for free — you get an API key instantly with no credit card required. Register Free → Login Free tier includes 60 req/min with access to Short Drama, Search, Providers, and Tags endpoints. Upgrade to Basic for Anime + MovieBox, or Pro for iQIYI + WeTV. 01 Pick an Endpoint All endpoints are available at the base URL below. Base URL Copy https://api.splay.id /api/dramas List dramas (paginated, filter by provider/tag/language) /api/dramas/:id Drama detail + tags + episodes (subtitles & multi-quality) /api/dramas/popular Popular dramas ranked by episode count /api/anime Anime catalog — 8,500+ titles, HLS streaming (Basic+) /api/moviebox Movies & series — multi-resolution MP4, subtitles (Basic+) /api/iqiyi iQIYI content — Chinese dramas, variety shows (Pro+) /api/wetv WeTV content — Tencent Video International (Pro+) /api/baca/{category} Manga, manhwa, manhua — signed WebP images (Basic+) /api/search?q=... Full-text search with provider/tag/language filters /api/providers List all providers /api/tags List all tags + drama counts 02 Fetch Data cURL $curl -H "Authorization: Bearer sk_live_..." \ "https://api.splay.id/api/dramas?page=1" Response Copy { "data": [ { "id": 1, "title":"Hidden Wolf King", "cover_url":"https://cdn.splay.id/dramabox/.../cover.jpg", "introduction":"...", "chapter_count": 80, "play_count": 0, "shelf_time":"2025-01-15T00:00:00Z", "is_dubbed": false, "language":"en", "provider_slug":"dramabox", "provider_name":"DramaBox", "created_at":"...", "updated_at":"..." } ], "meta": { "page": 1, "per_page": 20, "total": 24838, "total_pages": 1242 } } Done! You now have access to 25,000+ dramas from 30+ providers. Include Authorization: Bearer on every request. Explore /api/search, /api/providers, and/api/tags for more. Signed video URLs: The video_url and qualities fields in episode responses are pre-signed by the API server (HMAC-SHA256, valid for 30 minutes by default, max 4 hours via expires_in). Use them directly in your player — no extra signing needed. Re-fetch episode data before expiry; never cache episode responses for more than 25 minutes. Try It Now Paste your API key above, then hit Send to see live responses. No setup required. GET /api/dramas?per_page=3 Send GET /api/search?q=love&per_page=3 Send GET /api/dramas/popular?per_page=3 AI API — BETA AI API OpenAI-compatible chat completions API. Use your existing OpenAI SDKs — just change the base URL and model name. Streaming, prompt caching, and 256K context window. BETA The AI API is currently in beta and available to all plans. Rate limits and available models may change. During beta, the Free plan gets generous limits (10 RPM / 10,000 RPD). Base URL AI API Base https://api.splay.id/api/ai/v1 Drop-in replacement for https://api.openai.com/v1 — same request and response format. Authentication Same API key as the content APIs. Pass your key in the Authorization header: Request Header Copy Authorization: Bearer sk_live_your_api_key_here Available Models kimi-k2.5REASONING Best for complex tasks. Deep reasoning with chain-of-thought, vision input, and function calling. Ideal for code generation, analysis, and multi-step workflows. 256K context Reasoning Vision Tools Streaming glm-4.7-flashFAST Optimized for speed. Ultra-fast responses with 100+ language support. Best for chat, translation, instruction-following, and high-throughput workloads. 128K context 100+ Languages Tools Streaming Ultra-fast Model Context Best For Speed kimi-k2.5 256K Complex reasoning, code, analysis Standard glm-4.7-flash 128K Chat, translation, high throughput Fast Quick Example cURL — Chat Completion Copy curl https://api.splay.id/api/ai/v1/chat/completions \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "model": "kimi-k2.5", "messages": [ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"} ] }' # Response { "id": "id-1774267914618", "object": "chat.completion", "created": 1774267914, "model": "kimi-k2.5", "choices": [{ "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help you today?" }, "finish_reason": "stop" }], "usage": { "prompt_tokens": 18, "completion_tokens": 9, "total_tokens": 27 } } OpenAI SDK Compatible Works with the official OpenAI SDKs — just set base_url to the SPlay AI endpoint: Python (openai SDK) Copy from openai import OpenAI client = OpenAI( api_key="sk_live_...", base_url="https://api.splay.id/api/ai/v1" ) response = client.chat.completions.create( model="kimi-k2.5", messages=[{"role": "user", "content": "Hello!"}] ) print(response.choices[0].message.content) Node.js (openai SDK) Copy import OpenAI from "openai"; const client = new OpenAI({ apiKey: "sk_live_...", baseURL: "https://api.splay.id/api/ai/v1" }); const response = await client.chat.completions.create({ model: "kimi-k2.5", messages: [{ role: "user", content: "Hello!" }] }); console.log(response.choices[0].message.content); Rate Limits AI rate limits are separate from content API limits. Both counters run independently. Plan RPM RPD Free 60 1,000 Basic 60 2,000 Advanced 60 3,000 Pro 60 3,000 Enterprise 60 4,000 Elite 60 5,000 Ultimate 60 7,500 Rate limits are managed by admins and may change. BETA — Free plan limits are temporarily generous. Streaming Set "stream": true to receive Server-Sent Events (SSE). Each chunk is a chat.completion.chunk object. cURL — Streaming Copy curl -N https://api.splay.id/api/ai/v1/chat/completions \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{"model":"kimi-k2.5","messages":[{"role":"user","content":"Hi"}],"stream":true}' # SSE chunks: data: {"id":"...","model":"kimi-k2.5","choices":[{"delta":{"content":"Hello"}}]} data: {"id":"...","model":"kimi-k2.5","choices":[{"delta":{"content":"!"}}]} data: [DONE] Prompt Caching For multi-turn conversations, add an x-session-id header to enable prompt caching. Cached requests are faster and cheaper. Session Affinity Copy curl https://api.splay.id/api/ai/v1/chat/completions \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -H "x-session-id: my-conversation-123" \ -d '{"model":"kimi-k2.5","messages":[...]}' # Check usage.prompt_tokens_details.cached_tokens in response Supported Parameters Parameter Type Description model string Required. Model ID (e.g. kimi-k2.5) messages array Required. Array of message objects (role + content) stream boolean Enable SSE streaming (default: false) temperature number Sampling temperature 0-2 (default: 1) max_tokens integer Maximum tokens to generate top_p number Nucleus sampling threshold stop string|array Stop sequences tools array Function/tool definitions for function calling tool_choice string|object How the model should use tools Dive Deeper Endpoints Full endpoint reference Examples AI Endpoints AI API Endpoints OpenAI-compatible endpoints for chat completions and model listing. All Endpoints Method Endpoint Description GET /api/ai/v1/models List available AI models GET /api/ai/v1/models/:model Retrieve a specific model POST /api/ai/v1/chat/completions Create chat completion (streaming & non-streaming) GET /api/ai/v1/models Returns a list of all available AI models. Response { "object": "list", "data": [ { "id": "kimi-k2.5", "object": "model", "owned_by": "splay", "context_length": 256000, "_beta": true }, { "id": "glm-4.7-flash", "object": "model", "owned_by": "splay", "context_length": 131072, "_beta": true } ] } POST /api/ai/v1/chat/completions Creates a chat completion. Supports all standard OpenAI parameters. Request Body { "model": "kimi-k2.5", // or "glm-4.7-flash" "messages": [ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"} ], "stream": false, // optional, default false "temperature": 0.7, // optional, 0-2 "max_tokens": 1024, // optional "tools": [...] // optional, function calling } Response (non-streaming) { "id": "id-1774267914618", "object": "chat.completion", "created": 1774267914, "model": "kimi-k2.5", "choices": [{ "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help you?" }, "finish_reason": "stop" }], "usage": { "prompt_tokens": 18, "completion_tokens": 9, "total_tokens": 27, "prompt_tokens_details": { "cached_tokens": 0 } } } Response (streaming) data: {"id":"...","model":"kimi-k2.5","object":"chat.completion.chunk","choices":[{"delta":{"role":"assistant","content":""},"finish_reason":null}]} data: {"id":"...","model":"kimi-k2.5","object":"chat.completion.chunk","choices":[{"delta":{"content":"Hello"},"finish_reason":null}]} data: {"id":"...","model":"kimi-k2.5","object":"chat.completion.chunk","choices":[{"delta":{"content":"!"},"finish_reason":"stop"}]} data: [DONE] Headers Header Required Description Authorization Yes Bearer API key Content-Type Yes application/json x-session-id No Enable prompt caching for multi-turn conversations AI Examples AI API Examples Ready-to-run examples in cURL, Python, and Node.js. All examples use the OpenAI-compatible format. Basic Chat Completion cURL Copy curl https://api.splay.id/api/ai/v1/chat/completions \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "model": "kimi-k2.5", "messages": [ {"role": "user", "content": "Explain quantum computing in 3 sentences"} ] }' Python Copy from openai import OpenAI client = OpenAI( api_key="sk_live_...", base_url="https://api.splay.id/api/ai/v1" ) response = client.chat.completions.create( model="kimi-k2.5", messages=[ {"role": "user", "content": "Explain quantum computing in 3 sentences"} ] ) print(response.choices[0].message.content) Node.js Copy import OpenAI from "openai"; const client = new OpenAI({ apiKey: "sk_live_...", baseURL: "https://api.splay.id/api/ai/v1" }); const response = await client.chat.completions.create({ model: "kimi-k2.5", messages: [ { role: "user", content: "Explain quantum computing in 3 sentences" } ] }); console.log(response.choices[0].message.content); GLM 4.7 Flash (Fast Model) Use glm-4.7-flash for faster responses with 100+ language support. cURL — GLM 4.7 Flash Copy curl https://api.splay.id/api/ai/v1/chat/completions \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "model": "glm-4.7-flash", "messages": [ {"role": "system", "content": "You are a translator."}, {"role": "user", "content": "Translate to Japanese: Hello, how are you?"} ], "temperature": 0.3 }' Streaming cURL — Stream Copy curl -N https://api.splay.id/api/ai/v1/chat/completions \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{"model":"kimi-k2.5","messages":[{"role":"user","content":"Write a haiku"}],"stream":true}' Python — Stream Copy from openai import OpenAI client = OpenAI( api_key="sk_live_...", base_url="https://api.splay.id/api/ai/v1" ) stream = client.chat.completions.create( model="kimi-k2.5", messages=[{"role": "user", "content": "Write a haiku"}], stream=True ) for chunk in stream: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="", flush=True) Node.js — Stream Copy import OpenAI from "openai"; const client = new OpenAI({ apiKey: "sk_live_...", baseURL: "https://api.splay.id/api/ai/v1" }); const stream = await client.chat.completions.create({ model: "kimi-k2.5", messages: [{ role: "user", content: "Write a haiku" }], stream: true }); for await (const chunk of stream) { const content = chunk.choices[0]?.delta?.content; if (content) process.stdout.write(content); } System Prompt + Multi-turn Python — Multi-turn with Prompt Caching Copy from openai import OpenAI client = OpenAI( api_key="sk_live_...", base_url="https://api.splay.id/api/ai/v1" ) messages = [ {"role": "system", "content": "You are a senior Rust developer."}, {"role": "user", "content": "What is ownership in Rust?"}, ] # First request r1 = client.chat.completions.create( model="kimi-k2.5", messages=messages, extra_headers={"x-session-id": "rust-chat-001"} ) messages.append({"role": "assistant", "content": r1.choices[0].message.content}) # Follow-up (prompt cached — faster) messages.append({"role": "user", "content": "Show me an example with String"}) r2 = client.chat.completions.create( model="kimi-k2.5", messages=messages, extra_headers={"x-session-id": "rust-chat-001"} ) print(r2.choices[0].message.content) print(f"Cached tokens: {r2.usage.prompt_tokens_details.cached_tokens}") Function Calling cURL — Function Calling Copy curl https://api.splay.id/api/ai/v1/chat/completions \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "model": "kimi-k2.5", "messages": [ {"role": "user", "content": "What is the weather in Tokyo?"} ], "tools": [{ "type": "function", "function": { "name": "get_weather", "description": "Get current weather for a city", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "City name"} }, "required": ["city"] } } }], "tool_choice": "auto" }' Browser fetch() JavaScript — fetch API Copy const response = await fetch("https://api.splay.id/api/ai/v1/chat/completions", { method: "POST", headers: { "Authorization": "Bearer sk_live_...", "Content-Type": "application/json" }, body: JSON.stringify({ model: "glm-4.7-flash", messages: [{ role: "user", content: "Hello!" }] }) }); const data = await response.json(); console.log(data.choices[0].message.content); Anime API Anime API 8,500+ anime titles with HLS streaming, AniList metadata, season filtering, and signed CDN URLs — same self-hosted infrastructure as the Drama API. Base URL Anime API Base https://api.splay.id All anime endpoints are at /api/anime/* — consistent with /api/dramas/*. Authentication Same API key as the Drama API. Pass your key in the Authorization header: Request Header Copy Authorization: Bearer sk_live_your_api_key_here Quick Example cURL — List Popular Anime Copy curl https://api.splay.id/api/anime/popular?per_page=10 \ -H"Authorization: Bearer sk_live_..." # Response { "data": [ { "id":"attack-on-titan", "name":"Attack on Titan", "cover_url":"https://cdn.splay.id/AnimeAssets/.../Poster.webp", "genres": ["Action","Drama","Fantasy"], "available_episodes": 87, "anilist_data": { "title": {"english":"Attack on Titan","romaji":"Shingeki no Kyojin"}, "averageScore": 84, "popularity": 495000, "status":"FINISHED", "format":"TV", "countryOfOrigin":"JP" } } ], "meta": {"page": 1,"per_page": 10,"total": 8589,"total_pages": 859 } } Data Model AnimeItem — List Response Copy { "id":"attack-on-titan", // string — unique slug ID "name":"Attack on Titan", // string — canonical name "cover_url":"https://...", // string | null — CDN poster URL "description":"...", // string | null "genres": ["Action","Drama"], // string[] "anilist_id": 16498, // number | null "available_episodes": 87, // number — episodes with video "updated_at":"2026-01-10T...", // string | null — ISO 8601 "anilist_data": { "title": { "romaji":"Shingeki no Kyojin", "english":"Attack on Titan", "native":"進撃の巨人" }, "averageScore": 84, // 0–100 (divide by 10 for /10) "popularity": 495000, "status":"FINISHED", // RELEASING | FINISHED | NOT_YET_RELEASED | CANCELLED "season":"SPRING", // WINTER | SPRING | SUMMER | FALL | null "seasonYear": 2013, "format":"TV", // TV | MOVIE | OVA | ONA | SPECIAL | MUSIC "countryOfOrigin":"JP"// JP | CN | KR } } EpisodeDetail — Single Episode Copy { "id":"...", "anime_id":"attack-on-titan", "episode_number": 1, "episode_title":"To You, in 2000 Years", "video_urls": { "1080p":"https://cdn.splay.id/...?sig=...&exp=...", "720p":"https://cdn.splay.id/...?sig=...&exp=...", "hls":"https://cdn.splay.id/.../playlist.m3u8?sig=...&exp=..." }, "video_type":"hls", //"hls"|"mp4" "subtitles": [ { "lang":"id", "label":"Indonesian", "url":"https://cdn.splay.id/.../sub.id.vtt?sig=...&exp=...", "is_default": true }, { "lang":"en", "label":"English", "url":"https://cdn.splay.id/.../sub.en.vtt?sig=...&exp=...", "is_default": false } ], "url_expires_at":"2026-03-09T11:00:00Z"// signed URL TTL } Filtering & Sorting Parameter Type Values Description genre string Action, Romance, … Filter by genre name (exact match) origin string JP / CN / KR — or all / jp / cn / other for /latest-update Filter by country of origin. Exact uppercase (JP/CN) on most endpoints; lowercase shorthand (jp/cn/other) on /latest-update status string RELEASING / FINISHED / NOT_YET_RELEASED Filter by airing status season string WINTER / SPRING / SUMMER / FALL Filter by airing season year integer e.g. 2024 Filter by season year sort_by string popularity / rating / latest Sort order (default: popularity) page integer ≥ 1 Page number (default: 1) per_page integer 1–100 Items per page (default: 20) Anime Endpoints Anime Endpoints Complete reference for all 11 anime API endpoints. All require Authorization: Bearer header when REQUIRE_API_KEY is enabled. All Endpoints Method Endpoint Description GET /api/anime List anime (paginated, filter by genre/origin/status/season/year, sort by popularity/rating/latest) GET /api/anime/popular Popular anime ranked by AniList popularity score GET /api/anime/latest-update Curated recently-updated list (category curation, filter: origin=all/jp/cn/other) GET /api/anime/season Seasonal anime (filter by season: WINTER/SPRING/SUMMER/FALL + year) GET /api/anime/upcoming Upcoming / announced anime (status: NOT_YET_RELEASED) GET /api/anime/genres List all available anime genres GET /api/anime/spotlight Spotlight / featured anime (high score + popularity) GET /api/anime/search Full-text search anime by title (query param: q) GET /api/anime/:id Anime detail with full AniList metadata and episode count GET /api/anime/:id/episodes Paginated episode list with subtitle info and thumbnails GET /api/anime/:id/episodes/:ep Single episode — signed HLS/MP4 video URLs + subtitle tracks Query Parameters Parameter Type Default page integer 1 per_page integer 20 genre string — origin string — status string — season string — year integer — sort_by string popularity q string — expires_in integer 1800 Response Shapes GET /api/anime/latest-update — Curated Recently Updated Copy # All origins (default) GET /api/anime/latest-update?page=1&per_page=30 # Japanese anime only GET /api/anime/latest-update?origin=jp # Chinese donghua only GET /api/anime/latest-update?origin=cn # Other origins (KR, TH, etc.) GET /api/anime/latest-update?origin=other # Response — same shape as /api/anime list { "data": [ { "id":"bungou-stray-dogs", "name":"Bungou Stray Dogs", "cover_url":"https://...", "available_episodes": 60, "anilist_data": { "countryOfOrigin":"JP", "status":"RELEASING", "averageScore": 80 }, "updated_at":"2026-03-12T04:00:00Z" } ], "meta": {"page": 1,"per_page": 30,"total": 312,"total_pages": 11 } } GET /api/anime — Paginated List Copy { "data": [ { "id":"attack-on-titan", "name":"Attack on Titan", "cover_url":"https://cdn.splay.id/AnimeAssets/Attack_on_Titan/Poster.webp", "description":"...", "genres": ["Action","Mystery","Drama"], "anilist_id": 16498, "available_episodes": 87, "updated_at":"2026-01-10T08:00:00Z", "anilist_data": { "title": {"romaji":"Shingeki no Kyojin","english":"Attack on Titan","native":"進撃の巨人"}, "averageScore": 84, "popularity": 495000, "status":"FINISHED", "season":"SPRING", "seasonYear": 2013, "format":"TV", "countryOfOrigin":"JP" } } ], "meta": {"page": 1,"per_page": 20,"total": 8589,"total_pages": 430 } } GET /api/anime/:id — Detail Copy { "data": { "anime": { "id":"attack-on-titan", "name":"Attack on Titan", "cover_url":"https://...", "description":"...", "genres": ["Action","Drama"], "anilist_id": 16498, "available_episodes": 87, "anilist_data": { /* full AniList object */ } }, "episode_count": 87 } } GET /api/anime/:id/episodes — Episode List Copy { "data": [ { "id":"...", "anime_id":"attack-on-titan", "episode_number": 1, "episode_title":"To You, in 2000 Years", "has_subtitle": true, "subtitle_langs": ["id","en"], "thumbnail":"https://cdn.splay.id/.../thumb.jpg" } ], "meta": {"page": 1,"per_page": 50,"total": 87,"total_pages": 2 } } GET /api/anime/:id/episodes/:ep — Single Episode Copy { "data": { "id":"...", "anime_id":"attack-on-titan", "episode_number": 1, "episode_title":"To You, in 2000 Years", "video_urls": { "hls":"https://cdn.splay.id/.../playlist.m3u8?sig=HMAC&exp=1741521600", "1080p":"https://cdn.splay.id/.../1080p.mp4?sig=HMAC&exp=1741521600", "720p":"https://cdn.splay.id/.../720p.mp4?sig=HMAC&exp=1741521600", "480p":"https://cdn.splay.id/.../480p.mp4?sig=HMAC&exp=1741521600" }, "video_type":"hls", "subtitles": [ {"lang":"id","label":"Indonesian","url":"https://cdn.splay.id/.../sub.id.vtt?sig=HMAC&exp=...","is_default": true }, {"lang":"en","label":"English","url":"https://cdn.splay.id/.../sub.en.vtt?sig=HMAC&exp=...","is_default": false } ], "url_expires_at":"2026-03-09T12:00:00Z" } } Streaming Streaming & Signed URLs Anime video is delivered via pre-signed CDN URLs with configurable TTL. Supports HLS adaptive streaming, multi-quality direct MP4, and VTT subtitle tracks. Delivery Architecture Storage Cloudflare R2 (anime-project bucket) CDN cdn.splay.id (Hono CF Worker) Signing HMAC-SHA256 — Rust API signs, Worker verifies Default TTL 1800s (30 min) · max 14400s (4h) HLS Streaming Most anime episodes are served as HLS adaptive streams. Use the hls key from video_urls as the source for your player. HLS Playback — video.js Copy // The signed .m3u8 URL is ready to use directly const hlsUrl = episode.video_urls["hls"]; // video.js example const player = videojs("my-player"); player.src({ src: hlsUrl, type:"application/x-mpegURL"}); // hls.js example if (Hls.isSupported()) { const hls = new Hls(); hls.loadSource(hlsUrl); hls.attachMedia(videoElement); } HLS Playback — HTML5 native (Safari) Copy Multi-Quality Direct MP4 When direct MP4 variants exist, they appear alongside hls in video_urls. Keys vary by available quality. Quality Selection Copy const { video_urls } = episode; // Preferred quality order function pickUrl(urls) { return ( urls["hls"] || // HLS adaptive — best for streaming urls["1080p"] || urls["720p"] || urls["480p"] || Object.values(urls)[0] ||"" ); } // Quality switcher — build a menu from available keys const qualities = Object.keys(video_urls).filter(k => k !=="hls"); // e.g. ["1080p","720p","480p"] Subtitle Tracks Subtitle URLs are pre-signed VTT files. Attach them as elements or load with your player's subtitle API. HTML5 Video with Subtitles Copy video.js Subtitle Integration Copy player.ready(() => { subtitles.forEach(sub => { player.addRemoteTextTrack({ kind:"subtitles", src: sub.url, srclang: sub.lang, label: sub.label, default: sub.is_default, }, false); }); }); Signed URL TTL All video and subtitle URLs are signed with HMAC-SHA256 and expire after a configurable TTL. Pass expires_in to the episode endpoint to extend TTL for long-playing sessions. URLs expire after the configured TTL. If your user pauses for longer than the TTL, re-fetch the episode endpoint to get fresh URLs. Default: 1800s (30 min). Max: 14400s (4h). Custom TTL — 4 hour session Copy GET /api/anime/attack-on-titan/episodes/1?expires_in=14400 Authorization: Bearer sk_live_... # Response includes URL with 4-hour expiry { "data": { "video_urls": { "hls":"https://cdn.splay.id/.../playlist.m3u8?exp=1741528800&sig=..." }, "url_expires_at":"2026-03-09T16:00:00Z"// 4h from now } } R2 Storage Structure Object Paths Copy # Video qualities {anime_id}/{episode_number}/1080p.mp4 {anime_id}/{episode_number}/720p.mp4 {anime_id}/{episode_number}/480p.mp4 {anime_id}/{episode_number}/playlist.m3u8 # HLS master playlist # Subtitle tracks {anime_id}/{episode_number}/sub.{lang}.vtt # e.g. sub.id.vtt, sub.en.vtt # Cover images {anime_id}/cover.webp Quality Plans Anime Quality Plans Video quality returned by /anime/:id/episodes/:ep is filtered per API plan. The API only returns signed URLs for qualities your plan allows — unauthenticated /play viewers follow the Free tier. Plan Overview Plan Max Quality HLS / Auto Direct MP4 Free 480p ✗ 360p, 480p Basic 480p ✗ 360p, 480p Advanced 720p ✗ 360p – 720p Pro 1080p ✗ 360p – 1080p Enterprise HLS (Auto) ✓ All Custom HLS (Auto) ✓ All Per-Plan Detail Free Max: 480p Allowed 360p 480p Denied 540p 720p 1080p Auto (HLS) Default for all unauthenticated requests and /play section visitors. Basic Max: 480p Allowed 360p 480p Denied 540p 720p 1080p Auto (HLS) Same quality cap as Free. Upgrade for higher rate limits. Advanced Max: 720p Allowed 360p 480p 540p 720p Denied 1080p Auto (HLS) HD streaming. Good for mobile and mid-range clients. Pro Max: 1080p Allowed 360p 480p 540p 720p 1080p Denied Auto (HLS/Master) Full HD direct MP4. HLS adaptive stream excluded — use 1080p direct. Enterprise Max: HLS (Auto) Allowed 360p 480p 540p 720p 1080p Auto (HLS) Master All qualities unlocked including ABR/HLS adaptive streaming — best for production apps. Custom Max: HLS (Auto) Allowed 360p 480p 540p 720p 1080p Auto (HLS) Master Same as Enterprise. Custom rate limits and pricing. How It Works When you call GET /api/anime/:id/episodes/:ep, the API reads your plan from the API key, filters video_urls to only include allowed qualities, then signs each URL with your plan's max quality embedded in the HMAC. The CDN worker (cdn.splay.id) re-verifies the quality claim on every request — even if a client modifies the URL parameters, the HMAC won't match and the request will be rejected with 403 Forbidden. Enterprise only: HLS adaptive streaming (hls / master keys) is exclusively available to Enterprise and Custom plan API keys. All lower plans receive only direct MP4 URLs up to their quality cap. Response Comparison Free / Basic video_urls { "480p":"https://cdn-anime..." } Advanced video_urls { "480p":"https://cdn-anime...", "720p":"https://cdn-anime..." } Pro video_urls { "480p":"https://cdn-anime...", "720p":"https://cdn-anime...", "1080p":"https://cdn-anime..." } Enterprise video_urls { "480p":"https://cdn-anime...", "720p":"https://cdn-anime...", "1080p":"https://cdn-anime...", "hls":"https://cdn-anime.../playlist.m3u8" } Anime API Code Examples Ready-to-use examples for the Anime API. Paste your API key below to try live requests and inject it into code snippets. Your API Key Active Paste your API key to authenticate the "Try" buttons and inject it into code examples.Get your key → sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc Save Clear Try It Live Homepage GET /api/anime/home Send GET /api/anime/home?origin=jp Send GET /api/anime/home?origin=cn Send Browse Anime GET /api/anime?page=1&per_page=5 Send GET /api/anime?genre=Action&per_page=5 Send GET /api/anime?origin=JP&status=RELEASING&per_page=5 Send GET /api/anime?season=WINTER&year=2024&per_page=5 Send GET /api/anime?sort_by=rating&per_page=5 Send GET /api/anime/popular?per_page=5 Send GET /api/anime/popular?origin=CN&per_page=5 Send GET /api/anime/latest-update?per_page=5 Send GET /api/anime/latest-update?origin=cn&per_page=5 Send GET /api/anime/latest-update?origin=jp&per_page=5 Send GET /api/anime/latest-update?origin=other&per_page=5 Send GET /api/anime/genres Send Detail & Episodes GET /api/anime/attack-on-titan Send GET /api/anime/attack-on-titan/episodes?page=1&per_page=10 Send GET /api/anime/attack-on-titan/episodes/1 Send GET /api/anime/attack-on-titan/episodes/1?expires_in=14400 Send Search GET /api/anime/search?q=attack+on+titan Send GET /api/anime/search?q=romance&genre=Romance&per_page=5 Send cURL cURL Examples Copy API_KEY="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" BASE="https://api.splay.id" # ── List anime ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime?per_page=20" # ── Filter: genre, origin, status, season/year ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime?genre=Action&origin=JP&per_page=20" curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime?season=WINTER&year=2024&sort_by=rating&per_page=20" curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime?status=RELEASING&per_page=20" # ── Home (combined first-load: spotlight + latest_update + popular) ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/home" curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/home?origin=jp" curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/home?origin=cn" # ── Popular & Latest Update ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/popular?per_page=10" curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/popular?origin=CN&per_page=10"# donghua only curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/latest-update?per_page=30" curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/latest-update?origin=jp&per_page=30" curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/latest-update?origin=cn&per_page=30" curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/latest-update?origin=other&per_page=30" # ── Genres list ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/genres" # ── Search ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/search?q=attack+on+titan" # ── Anime detail ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/attack-on-titan" # ── Episode list ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/attack-on-titan/episodes?page=1&per_page=50" # ── Single episode (signed video + subtitle URLs, 1h TTL) ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/attack-on-titan/episodes/1" # ── Custom TTL (4h) ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/anime/attack-on-titan/episodes/1?expires_in=14400" JavaScript / TypeScript Browse & Filter Copy const BASE ="https://api.splay.id"; const API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // ── Home — spotlight + latest_update (30) + popular (24) in one request ── const { data: home } = await (await fetch(`${BASE}/api/anime/home`, { headers })).json(); const { data: homeJP } = await (await fetch(`${BASE}/api/anime/home?origin=jp`, { headers })).json(); console.log(`${home.spotlight.length} spotlight, ${home.latest_update.length} latest, ${home.popular.length} popular`); // ── List anime ── const res = await fetch(`${BASE}/api/anime?per_page=20`, { headers }); const { data, meta } = await res.json(); console.log(`${meta.total} anime`); data.forEach(a => { const score = a.anilist_data?.averageScore; console.log(`[${a.id}] ${a.name} — ${score ??"N/A"}/100, ${a.available_episodes} eps`); }); // ── Filter: genre, origin, status ── const action = await fetch( `${BASE}/api/anime?genre=Action&origin=JP&status=RELEASING&per_page=20`, { headers } ); const winter2024 = await fetch( `${BASE}/api/anime?season=WINTER&year=2024&sort_by=rating&per_page=20`, { headers } ); // ── Popular ── const { data: popular } = await (await fetch(`${BASE}/api/anime/popular?per_page=10`, { headers })).json(); const { data: donghua } = await (await fetch(`${BASE}/api/anime/popular?origin=CN&per_page=10`, { headers })).json(); // ── Latest Update — curated recently-updated (origin: all | jp | cn | other) ── const { data: latestAll } = await (await fetch(`${BASE}/api/anime/latest-update?per_page=30`, { headers })).json(); const { data: latestJP } = await (await fetch(`${BASE}/api/anime/latest-update?origin=jp&per_page=30`, { headers })).json(); const { data: latestCN } = await (await fetch(`${BASE}/api/anime/latest-update?origin=cn&per_page=30`, { headers })).json(); // ── Genres ── const { data: genres } = await (await fetch(`${BASE}/api/anime/genres`, { headers })).json(); // ── Search ── const { data: results } = await (await fetch(`${BASE}/api/anime/search?q=attack+on+titan`, { headers })).json(); Stream an Episode Copy const BASE ="https://api.splay.id"; const API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // ── Anime detail ── const { data: { anime, episode_count } } = await ( await fetch(`${BASE}/api/anime/attack-on-titan`, { headers }) ).json(); console.log(`${anime.name} — ${episode_count} eps | score: ${anime.anilist_data?.averageScore}`); // ── Episode list ── const { data: episodes, meta } = await ( await fetch(`${BASE}/api/anime/attack-on-titan/episodes?page=1&per_page=50`, { headers }) ).json(); console.log(`${meta.total} total episodes`); // ── Single episode — request 4h TTL so URL stays valid during playback ── const { data: ep } = await ( await fetch(`${BASE}/api/anime/attack-on-titan/episodes/1?expires_in=14400`, { headers }) ).json(); console.log("Expires:", ep.url_expires_at); // ep.video_urls: { hls,"1080p","720p","480p"} // ep.subtitles: [{ lang, label, url, is_default }] // ── Play with HLS.js ── import Hls from"hls.js"; const video = document.querySelector("video"); if (Hls.isSupported() && ep.video_urls.hls) { const hls = new Hls(); hls.loadSource(ep.video_urls.hls); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, () => video.play()); } else { video.src = ep.video_urls["1080p"] ?? ep.video_urls["720p"]; video.play(); } // ── Load subtitles ── ep.subtitles.forEach(sub => { const track = document.createElement("track"); track.kind ="subtitles"; track.label = sub.label; track.srclang = sub.lang; track.src = sub.url; if (sub.is_default) track.default = true; video.appendChild(track); }); Python Full Example Copy import requests BASE ="https://api.splay.id" API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" headers = {"Authorization": f"Bearer {API_KEY}"} # ── List anime ── res = requests.get(f"{BASE}/api/anime", params={"per_page": 20}, headers=headers) for a in res.json()["data"]: score = (a.get("anilist_data") or {}).get("averageScore","N/A") print(f"[{a['id']}] {a['name']} — {score}/100, {a['available_episodes']} eps") # ── Filter ── requests.get(f"{BASE}/api/anime", params={ "genre":"Action","origin":"JP","status":"RELEASING","per_page": 20 }, headers=headers) requests.get(f"{BASE}/api/anime", params={ "season":"WINTER","year": 2024,"sort_by":"rating","per_page": 20 }, headers=headers) # ── Popular, Genres, Search ── popular = requests.get(f"{BASE}/api/anime/popular", params={"per_page": 10}, headers=headers) donghua = requests.get(f"{BASE}/api/anime/popular", params={"origin":"CN","per_page": 10}, headers=headers) genres = requests.get(f"{BASE}/api/anime/genres", headers=headers) search = requests.get(f"{BASE}/api/anime/search", params={"q":"attack on titan"}, headers=headers) # ── Latest Update — curated recently-updated list ── # origin:"all"(default) |"jp"|"cn"|"other" latest_all = requests.get(f"{BASE}/api/anime/latest-update", params={"per_page": 30}, headers=headers) latest_jp = requests.get(f"{BASE}/api/anime/latest-update", params={"origin":"jp","per_page": 30}, headers=headers) latest_cn = requests.get(f"{BASE}/api/anime/latest-update", params={"origin":"cn","per_page": 30}, headers=headers) for a in latest_cn.json()["data"]: print(f"[Donghua] {a['name']} — {a['available_episodes']} eps") # ── Anime detail ── detail = requests.get(f"{BASE}/api/anime/attack-on-titan", headers=headers) info = detail.json()["data"] print(f"{info['anime']['name']} — {info['episode_count']} episodes") # ── Episode list ── eps = requests.get(f"{BASE}/api/anime/attack-on-titan/episodes", params={ "page": 1,"per_page": 50 }, headers=headers) for ep in eps.json()["data"]: langs =",".join(ep.get("subtitle_langs", [])) or"none" print(f"Ep {ep['episode_number']}: {ep.get('episode_title', '')} (subs: {langs})") # ── Single episode (signed URLs, 4h TTL) ── ep = requests.get( f"{BASE}/api/anime/attack-on-titan/episodes/1", params={"expires_in": 14400}, headers=headers ).json()["data"] print("Expires:", ep["url_expires_at"]) video_urls = ep.get("video_urls", {}) print("HLS:", video_urls.get("hls")) print("1080p:", video_urls.get("1080p")) for sub in ep.get("subtitles", []): mark ="[default]"if sub.get("is_default") else"" print(f"[{sub['lang']}] {sub['label']}{mark}: {sub['url']}") Baca API Baca Overview Manga, manhwa, and manhua reading API. Three categories, chapter-based pagination, per-chapter signed image URLs. Same familiar data model used across the platform -- titles, tags, and chapters instead of episodes. Categories 3 Titles Growing Chapters Growing Format Image Base URL Base URL https://api.splay.id GET /api/baca/{category}?per_page=20 Categories All Baca endpoints are scoped by category. Replace {category} with one of the following: manga Japanese comics -- read right-to-left manhwa Korean comics -- vertical scroll format manhua Chinese comics -- vertical scroll format Data Model Baca uses the same Drama type as other APIs, with chapters instead of episodes. Each title has a cover image, tags, introduction, and chapter list. Each chapter provides a signed directory URL -- append image filenames to construct per-page image URLs. Field Type Description id number Unique title ID title string Title name cover_url string Signed cover image URL provider_slug string Provider identifier chapter_count number Total chapter count introduction string Synopsis / description tags Tag[] Genre/category tags chapters Chapter[] Chapter list with signed image URLs Chapter Format (Images) Each chapter contains individual images (JPEG/PNG, one per page). The content_url field holds a signed chapter directory URL. The qualities object contains the page count and format. Construct image URLs by appending the page filename to the directory URL. Field Type Description content_url string Signed chapter directory URL (HMAC-SHA256, 30min TTL) qualities.pages number Total number of images (pages) in the chapter qualities.format string Image format -- "image" (original JPEG/PNG) Image URL pattern: {content_url}/001.jpg?sig=...&expires=... -- one signature covers all images in the chapter (the sig and expires params from content_url are reused). All URLs are HMAC-SHA256 signed with 30-minute default TTL (max 4 hours via expires_in). No subtitle support -- manga content is visual. Authentication Same API Key Baca endpoints use the same Authorization: Bearer authentication as all other APIs. Get your key atapi-dashboard. Quick Example GET /api/baca/manga Copy curl"https://api.splay.id/api/baca/manga?per_page=20"\ -H"Authorization: Bearer " Dive Deeper Baca API Endpoints Dedicated /api/baca/{category}/* endpoints for manga, manhwa, and manhua content. All endpoints follow the same patterns as other APIs -- pagination, sorting, filtering, and per-chapter signed image URLs. Authentication Required All data endpoints require Authorization: Bearer . Get your key atapi-dashboard. Category Path Parameter Replace {category} with manga, manhwa, or manhua in all endpoints below. GET /api/baca/{category} List titles in a category -- paginated, with filtering and sorting. Category must be manga, manhwa, or manhua. Parameter Type Required Description category string required manga | manhwa | manhua (path param) page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) provider string optional Filter by provider slug tag string optional Filter by tag name language string optional ISO 639-1 language code (en, ja, ko, zh, ...) sort_by string optional updated_at | created_at | title | play_count | chapter_count sort_order string optional desc | asc Example /api/baca/manga?per_page=20&sort_by=updated_at GET /api/baca/{category}/popular Popular titles ranked by read count Parameter Type Required Description category string required manga | manhwa | manhua (path param) page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) language string optional ISO 639-1 language code Example /api/baca/manhwa/popular?per_page=10 GET /api/baca/{category}/trending Trending titles (recently updated, sorted by read count) Parameter Type Required Description category string required manga | manhwa | manhua (path param) page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) language string optional ISO 639-1 language code Example /api/baca/manhua/trending GET /api/baca/{category}/search Full-text search across titles in a category Parameter Type Required Description category string required manga | manhwa | manhua (path param) q string required Search query page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) Example /api/baca/manga/search?q=one+piece GET /api/baca/{category}/alphabet Browse A-Z -- returns letter counts, or titles starting with a specific letter Parameter Type Required Description category string required manga | manhwa | manhua (path param) letter string optional Single letter (A-Z) to filter titles. Omit for letter counts. page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) Example /api/baca/manga/alphabet?letter=N GET /api/baca/{category}/{id} Get title detail with tags and chapters with signed image URLs Parameter Type Required Description category string required manga | manhwa | manhua (path param) id number required Title ID (integer) expires_in number optional Signed URL TTL in seconds (max 14400, default 1800) Example /api/baca/manga/42 GET /api/baca/{category}/{id}/chapters Paginated chapters for a title with signed image URLs Parameter Type Required Description category string required manga | manhwa | manhua (path param) id number required Title ID (integer) page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) expires_in number optional Signed URL TTL in seconds (max 14400, default 1800) Example /api/baca/manga/42/chapters?page=1&per_page=50 Chapter Response Shape Each chapter object contains a content_url (signed chapter directory path) and a qualities object with page count and format. Construct individual image URLs by appending the page filename to the directory URL. Chapter object Copy { "id": 456, "drama_id": 78, "episode_index": 1, "episode_name":"Chapter 1", "status":"published", // Signed chapter directory URL (HMAC-SHA256, 30min TTL) "content_url":"https://cdn.splay.id/baca/manga/42/1?sig=abc123&expires=1742320000", // Image metadata -- page count + format "qualities": { "pages": 24, "format":"image" }, // No subtitles for manga content "subtitles": [], "released_at":"2025-08-01T00:00:00Z", "created_at":"2026-02-20T08:00:00Z" } // Construct image URLs: // {content_url}/001.jpg?sig=abc123&expires=1742320000 // {content_url}/002.jpg?sig=abc123&expires=1742320000 // ... up to {qualities.pages} images // The sig and expires params from content_url apply to all images in the chapter. Pagination All list endpoints return paginated responses with a meta object containing pagination info. Response meta Copy { "data": [...], "meta": { "page": 1, "per_page": 20, "total": 500, "total_pages": 25 } } Baca API Code Examples Ready-to-use examples for the Baca API -- browse manga, manhwa, manhua, search titles, and read chapters via signed image URLs. Your API Key Active Paste your API key to authenticate the "Try" buttons and inject it into code examples.Get your key → sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc Save Clear Try It Live Browse Manga GET /api/baca/manga?per_page=5 Send GET /api/baca/manga?sort_by=updated_at&sort_order=desc&per_page=5 Send GET /api/baca/manga/popular?per_page=5 Send GET /api/baca/manga/trending?per_page=5 Send GET /api/baca/manga/alphabet Send GET /api/baca/manga/alphabet?letter=N&per_page=5 Send Browse Manhwa GET /api/baca/manhwa?per_page=5 Send GET /api/baca/manhwa/popular?per_page=5 Send Browse Manhua GET /api/baca/manhua?per_page=5 Send GET /api/baca/manhua/popular?per_page=5 Send Search GET /api/baca/manga/search?q=one+piece&per_page=5 Send GET /api/baca/manhwa/search?q=solo+leveling&per_page=5 Send cURL cURL Examples Copy API_KEY="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" BASE="https://api.splay.id" # -- List manga -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/baca/manga?per_page=20" # -- Sort by latest updated -- curl -H"Authorization: Bearer $API_KEY"\ "$BASE/api/baca/manga?sort_by=updated_at&sort_order=desc&per_page=20" # -- Popular manhwa -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/baca/manhwa/popular" # -- Trending manhua -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/baca/manhua/trending" # -- Browse A-Z (get letter counts) -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/baca/manga/alphabet" # -- Browse letter N -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/baca/manga/alphabet?letter=N" # -- Search -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/baca/manga/search?q=one+piece" # -- Title detail (all chapters + signed image URLs) -- curl -H"Authorization: Bearer $API_KEY""$BASE/api/baca/manga/TITLE_ID" # -- Paginated chapters -- curl -H"Authorization: Bearer $API_KEY"\ "$BASE/api/baca/manga/TITLE_ID/chapters?page=1&per_page=50" # -- Construct image URLs from chapter response -- # content_url = signed chapter directory URL # Append page filename: {content_url}/001.jpg?sig=...&expires=... # The sig and expires from content_url are reused for all images JavaScript / TypeScript Browse & Search Copy const BASE ="https://api.splay.id"; const API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // -- List manga (paginated) -- const res = await fetch(`${BASE}/api/baca/manga?per_page=20`, { headers }); const { data, meta } = await res.json(); console.log(`${meta.total} titles (page ${meta.page}/${meta.total_pages})`); data.forEach(d => console.log(`[${d.id}] ${d.title}`)); // -- Popular manhwa -- const { data: popular } = await ( await fetch(`${BASE}/api/baca/manhwa/popular`, { headers }) ).json(); // -- Trending manhua -- const { data: trending } = await ( await fetch(`${BASE}/api/baca/manhua/trending`, { headers }) ).json(); // -- Search -- const { data: results, meta: searchMeta } = await ( await fetch(`${BASE}/api/baca/manga/search?q=one+piece`, { headers }) ).json(); console.log(`Found ${searchMeta.total} results`); // -- A-Z Browse -- const { data: letters } = await ( await fetch(`${BASE}/api/baca/manga/alphabet`, { headers }) ).json(); // letters = [{"letter":"A","count": 42 }, ...] Get Detail + Render Chapter Images Copy const BASE ="https://api.splay.id"; const API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // -- Title detail (title + chapters with signed URLs) -- const res = await fetch(`${BASE}/api/baca/manga/TITLE_ID`, { headers }); const { data: { drama, chapters } } = await res.json(); console.log(`${drama.title} -- ${chapters.length} chapters`); // -- Chapter image URLs -- const chapter = chapters[0]; // content_url = signed chapter directory (HMAC-SHA256, 30min TTL) const chapterUrl = chapter.content_url; const pageCount = chapter.qualities?.pages; const format = chapter.qualities?.format; // "image" console.log(`Chapter 1: ${pageCount} pages (${format})`); // -- Extract sig and expires from the directory URL -- const url = new URL(chapterUrl); const sig = url.searchParams.get("sig"); const expires = url.searchParams.get("expires"); // -- Construct individual page image URLs -- const imageUrls = []; for (let i = 1; i <= pageCount; i++) { const filename = String(i).padStart(3, "0") + ".jpg"; imageUrls.push(`${chapterUrl}/${filename}?sig=${sig}&expires=${expires}`); } // -- Render images in a container -- const container = document.getElementById("reader"); if (container) { imageUrls.forEach((src, i) => { const img = document.createElement("img"); img.src = src; img.alt = `Page ${i + 1}`; img.loading = i < 3 ? "eager" : "lazy"; // lazy-load after first 3 img.style.maxWidth = "100%"; container.appendChild(img); }); } // -- Paginated chapters -- const { data: chapters, meta } = await ( await fetch(`${BASE}/api/baca/manga/TITLE_ID/chapters?page=1&per_page=50`, { headers }) ).json(); console.log(`${meta.total} total chapters, showing ${chapters.length}`); Python Full Example Copy import requests BASE ="https://api.splay.id" API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" headers = {"Authorization": f"Bearer {API_KEY}"} # -- List manga -- res = requests.get(f"{BASE}/api/baca/manga", params={ "per_page": 20,"sort_by":"updated_at","sort_order":"desc" }, headers=headers) for d in res.json()["data"]: print(f"[{d['id']}] {d['title']} ({d['chapter_count']} chapters)") # -- Popular manhwa -- popular = requests.get(f"{BASE}/api/baca/manhwa/popular", headers=headers) for d in popular.json()["data"][:5]: print(f"Popular: {d['title']}") # -- Search -- search = requests.get(f"{BASE}/api/baca/manga/search", params={ "q":"one piece","per_page": 10 }, headers=headers) results = search.json() print(f"Found {results['meta']['total']} results") # -- Title detail with chapters -- detail = requests.get(f"{BASE}/api/baca/manga/TITLE_ID", headers=headers) info = detail.json()["data"] title_info, chapters = info["drama"], info["chapters"] print(f"\n=== {title_info['title']} ===") print(f"Chapters: {len(chapters)}") # -- Image URLs (signed, 30min TTL) -- ch = chapters[0] chapter_url = ch.get("content_url") # signed directory URL qualities = ch.get("qualities") or {} page_count = qualities.get("pages", 0) img_format = qualities.get("format", "image") print(f"\nChapter 1: {page_count} pages ({img_format})") # -- Extract sig and expires from the directory URL -- from urllib.parse import urlparse, parse_qs parsed = urlparse(chapter_url) params = parse_qs(parsed.query) sig = params.get("sig", [""])[0] expires = params.get("expires", [""])[0] # -- Download all page images -- import os os.makedirs("chapter_1", exist_ok=True) for i in range(1, page_count + 1): filename = f"{i:03d}.jpg" img_url = f"{chapter_url}/{filename}?sig={sig}&expires={expires}" img_data = requests.get(img_url) with open(f"chapter_1/{filename}","wb") as f: f.write(img_data.content) print(f"Downloaded {filename}") print(f"Saved {page_count} images to chapter_1/") iQIYI API iQIYI Overview Chinese streaming platform content — dramas, variety shows, and more. Multi-quality video (up to 1080p), multi-language subtitles, HMAC-signed CDN URLs. Same familiar Drama/Episode data model used across the platform. Titles Growing Episodes Growing Quality 240p-1080p Subtitles Multi-lang Base URL Base URL https://api.splay.id GET /api/iqiyi?per_page=20 Data Model iQIYI uses the same Drama and Episode types as the Short Drama API. Each drama has a title, cover image, tags, introduction, and episode list. Each episode includes signed video URLs with multiple quality levels and subtitle tracks. Field Type Description id number Unique drama ID title string Drama title cover_url string Signed cover image URL provider_slug string Provider identifier (e.g. iqiyi) chapter_count number Total episode count introduction string Drama synopsis tags Tag[] Genre/category tags episodes Episode[] Episode list with video URLs Video Quality Each episode has a primary video_url and a qualities JSON object with all available resolutions. Quality JSON key in qualities{} Notes 240p qualities["240p"] Low bandwidth fallback 360p qualities["360p"] Available on most content 480p qualities["480p"] Standard definition 720p video_url · qualities["720p"] Primary — HD 1080p qualities["1080p"] Full HD — premium content All video URLs are HMAC-SHA256 signed with 1-hour TTL. Use video_url as your primary source; fall back through qualities for other resolutions. Authentication Same API Key iQIYI endpoints use the same Authorization: Bearer authentication as all other APIs. Get your key atapi-dashboard. Quick Example GET /api/iqiyi Copy curl"https://api.splay.id/api/iqiyi?per_page=20"\ -H"Authorization: Bearer " Dive Deeper iQIYI API Endpoints Dedicated /api/iqiyi/* endpoints for iQIYI content. All endpoints follow the same patterns as the Short Drama API — pagination, sorting, filtering, and signed video URLs. Authentication Required All data endpoints require Authorization: Bearer . Get your key atapi-dashboard. GET /api/iqiyi List iQIYI dramas — paginated, with filtering and sorting Parameter Type Required Description page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) provider string optional Filter by provider slug tag string optional Filter by tag name language string optional ISO 639-1 language code (en, zh, ko, ...) sort_by string optional updated_at | created_at | title | play_count | chapter_count sort_order string optional desc | asc Example /api/iqiyi?per_page=20&sort_by=updated_at GET /api/iqiyi/popular Popular iQIYI dramas ranked by play count Parameter Type Required Description page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) language string optional ISO 639-1 language code Example /api/iqiyi/popular?per_page=10 GET /api/iqiyi/trending Trending iQIYI dramas (recently updated, sorted by play count) Parameter Type Required Description page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) language string optional ISO 639-1 language code Example /api/iqiyi/trending GET /api/iqiyi/search Full-text search across iQIYI dramas Parameter Type Required Description q string required Search query page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) Example /api/iqiyi/search?q=love GET /api/iqiyi/alphabet Browse A-Z — returns letter counts, or dramas starting with a specific letter Parameter Type Required Description letter string optional Single letter (A-Z) to filter dramas. Omit for letter counts. page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) Example /api/iqiyi/alphabet?letter=L GET /api/iqiyi/{id} Get iQIYI drama detail with all episodes and signed video URLs Parameter Type Required Description id number required Drama ID (integer) expires_in number optional Signed URL TTL in seconds (max 14400, default 1800) Example /api/iqiyi/42 GET /api/iqiyi/{id}/episodes Paginated episodes for an iQIYI drama Parameter Type Required Description id number required Drama ID (integer) page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) expires_in number optional Signed URL TTL in seconds (max 14400, default 1800) Example /api/iqiyi/42/episodes?page=1&per_page=50 Episode Response Shape Each episode object contains video_url (primary, signed) and a qualities JSON object with all available resolutions. Episode object Copy { "id": 123, "drama_id": 45, "episode_index": 1, "episode_name":"Episode 1", "status":"published", // Primary video — HMAC-SHA256 signed, 1h TTL "video_url":"https://cdn.splay.id/iqiyi/.../video.mp4?sig=...&expires=...", // All available resolutions — same signed CDN URLs "qualities": { "240p":"https://cdn.splay.id/.../video_240p.mp4?sig=...&expires=...", "360p":"https://cdn.splay.id/.../video_360p.mp4?sig=...&expires=...", "480p":"https://cdn.splay.id/.../video_480p.mp4?sig=...&expires=...", "720p":"https://cdn.splay.id/.../video.mp4?sig=...&expires=...", "1080p":"https://cdn.splay.id/.../video_1080p.mp4?sig=...&expires=..." }, // Subtitles — signed SRT URLs "subtitles": [ {"lang":"en","label":"English","url":"https://cdn.splay.id/.../subtitle_en.srt?sig=..."}, {"lang":"zh","label":"Chinese","url":"https://cdn.splay.id/.../subtitle_zh.srt?sig=..."}, {"lang":"id","label":"Indonesian","url":"https://cdn.splay.id/.../subtitle_id.srt?sig=..."} ], "released_at":"2025-06-01T00:00:00Z", "created_at":"2026-02-15T08:00:00Z" } Pagination All list endpoints return paginated responses with a meta object containing pagination info. Response meta Copy { "data": [...], "meta": { "page": 1, "per_page": 20, "total": 1500, "total_pages": 75 } } iQIYI API Code Examples Ready-to-use examples for the iQIYI API — browse dramas, search, video playback, and subtitle handling. Your API Key Active Paste your API key to authenticate the "Try" buttons and inject it into code examples.Get your key → sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc Save Clear Try It Live Browse Content GET /api/iqiyi?per_page=5 Send GET /api/iqiyi?sort_by=updated_at&sort_order=desc&per_page=5 Send GET /api/iqiyi/popular?per_page=5 Send GET /api/iqiyi/trending?per_page=5 Send GET /api/iqiyi/alphabet Send GET /api/iqiyi/alphabet?letter=L&per_page=5 Send Search GET /api/iqiyi/search?q=love&per_page=5 Send cURL cURL Examples Copy API_KEY="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" BASE="https://api.splay.id" # ── List dramas ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/iqiyi?per_page=20" # ── Sort by latest updated ── curl -H"Authorization: Bearer $API_KEY"\ "$BASE/api/iqiyi?sort_by=updated_at&sort_order=desc&per_page=20" # ── Popular dramas ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/iqiyi/popular" # ── Trending dramas ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/iqiyi/trending" # ── Browse A-Z (get letter counts) ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/iqiyi/alphabet" # ── Browse letter L ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/iqiyi/alphabet?letter=L" # ── Search ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/iqiyi/search?q=love" # ── Drama detail (all episodes + signed video URLs) ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/iqiyi/DRAMA_ID" # ── Paginated episodes ── curl -H"Authorization: Bearer $API_KEY"\ "$BASE/api/iqiyi/DRAMA_ID/episodes?page=1&per_page=50" JavaScript / TypeScript Browse & Search Copy const BASE ="https://api.splay.id"; const API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // ── List dramas (paginated) ── const res = await fetch(`${BASE}/api/iqiyi?per_page=20`, { headers }); const { data, meta } = await res.json(); console.log(`${meta.total} dramas (page ${meta.page}/${meta.total_pages})`); data.forEach(d => console.log(`[${d.id}] ${d.title}`)); // ── Popular ── const { data: popular } = await ( await fetch(`${BASE}/api/iqiyi/popular`, { headers }) ).json(); // ── Trending ── const { data: trending } = await ( await fetch(`${BASE}/api/iqiyi/trending`, { headers }) ).json(); // ── Search ── const { data: results, meta: searchMeta } = await ( await fetch(`${BASE}/api/iqiyi/search?q=love`, { headers }) ).json(); console.log(`Found ${searchMeta.total} results`); // ── A-Z Browse ── const { data: letters } = await ( await fetch(`${BASE}/api/iqiyi/alphabet`, { headers }) ).json(); // letters = [{"letter":"A","count": 42 }, ...] Get Detail + Play Video Copy const BASE ="https://api.splay.id"; const API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // ── Drama detail (drama + episodes with signed URLs) ── const res = await fetch(`${BASE}/api/iqiyi/DRAMA_ID`, { headers }); const { data: { drama, episodes } } = await res.json(); console.log(`${drama.title} — ${episodes.length} episodes`); // ── Video URLs ── const ep = episodes[0]; // video_url = primary, signed HMAC-SHA256 console.log("Primary:", ep.video_url); // qualities = all resolutions as JSON object console.log("240p:", ep.qualities?.["240p"]); console.log("360p:", ep.qualities?.["360p"]); console.log("480p:", ep.qualities?.["480p"]); console.log("720p:", ep.qualities?.["720p"]); console.log("1080p:", ep.qualities?.["1080p"]); // ── Pick best available quality ── const videoUrl = ep.qualities?.["1080p"] ?? ep.qualities?.["720p"] ?? ep.video_url ?? ep.qualities?.["480p"] ?? ep.qualities?.["360p"] ?? ep.qualities?.["240p"]; const video = document.querySelector("video"); if (video && videoUrl) { video.src = videoUrl; // direct MP4 — no HLS library needed video.play(); } // ── Subtitles (signed SRT URLs) ── for (const sub of ep.subtitles ?? []) { console.log(`[${sub.lang}] ${sub.label}: ${sub.url}`); } // ── Paginated episodes ── const { data: eps, meta } = await ( await fetch(`${BASE}/api/iqiyi/DRAMA_ID/episodes?page=1&per_page=50`, { headers }) ).json(); console.log(`${meta.total} total episodes, showing ${eps.length}`); Python Full Example Copy import requests BASE ="https://api.splay.id" API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" headers = {"Authorization": f"Bearer {API_KEY}"} # ── List dramas ── res = requests.get(f"{BASE}/api/iqiyi", params={ "per_page": 20,"sort_by":"updated_at","sort_order":"desc" }, headers=headers) for d in res.json()["data"]: print(f"[{d['id']}] {d['title']} ({d['chapter_count']} eps)") # ── Popular dramas ── popular = requests.get(f"{BASE}/api/iqiyi/popular", headers=headers) for d in popular.json()["data"][:5]: print(f"Popular: {d['title']}") # ── Search ── search = requests.get(f"{BASE}/api/iqiyi/search", params={ "q":"love","per_page": 10 }, headers=headers) results = search.json() print(f"Found {results['meta']['total']} results") # ── Drama detail with episodes ── detail = requests.get(f"{BASE}/api/iqiyi/DRAMA_ID", headers=headers) info = detail.json()["data"] drama, episodes = info["drama"], info["episodes"] print(f"\n=== {drama['title']} ===") print(f"Episodes: {len(episodes)}") # ── Video URLs (signed MP4, 1h TTL) ── ep = episodes[0] qualities = ep.get("qualities") or {} video_url = ( qualities.get("1080p") or qualities.get("720p") or ep.get("video_url") or qualities.get("480p") or qualities.get("360p") or qualities.get("240p") ) print(f"\nBest video URL: {video_url}") # ── Subtitles ── for sub in ep.get("subtitles", []): print(f"[{sub['lang']}] {sub['label']}: {sub['url']}") MovieBox API MovieBox Overview Movies and series from MovieBox — multi-resolution MP4 (360p / 480p / 720p / 1080p), 12+ subtitle languages, HMAC-signed CDN URLs, and full TMDB enrichment (cast, crew, genres, trailers, ratings, certification, and more) via raw_data.tmdb. Movies 8,000+ Series 140+ Quality 360p–1080p Subtitles 12+ langs Base URL Base URL https://api.splay.id GET /api/moviebox?type=movies Content Types Type Provider Slug Description Movies moviebox-movies Full-length films — 1 episode or multi-episode Series moviebox-series TV series — multi-season, multi-episode (e.g. Stranger Things, Wednesday) Video Quality Each episode has a primary video_url (720p) and a qualities JSON object with all available resolutions — same structure as the Drama API. Quality JSON key in qualities{} Notes 360p qualities["360p"] Always available 480p qualities["480p"] Always available 720p video_url · qualities["720p"] Primary — available on most titles 1080p qualities["1080p"] Available on premium content All video URLs are HMAC-SHA256 signed with 1-hour TTL. Use video_url as your primary source; fall back through qualities for other resolutions. Episode Response Shape Episode object (inside drama detail) Copy { "id": 42, "drama_id": 7, "episode_index": 1001, // season×1000 + ep — Movie: 1, S1E1: 1001, S2E5: 2005 "episode_name":"Episode 1", "status":"published", // Primary video (720p) — HMAC-SHA256 signed, 1h TTL "video_url":"https://cdn.splay.id/moviebox-movies/.../video.mp4?sig=...&expires=...", // All available resolutions — same signed CDN URLs "qualities": { "360p":"https://cdn.splay.id/.../video_360p.mp4?sig=...&expires=...", "480p":"https://cdn.splay.id/.../video_480p.mp4?sig=...&expires=...", "720p":"https://cdn.splay.id/.../video.mp4?sig=...&expires=...", "1080p":"https://cdn.splay.id/.../video_1080p.mp4?sig=...&expires=..." }, // Subtitles array — signed SRT URLs "subtitles": [ {"lang":"en","label":"English","url":"https://cdn.splay.id/.../subtitle_en.srt?sig=...&expires=..."}, {"lang":"id","label":"Indonesian","url":"https://cdn.splay.id/.../subtitle_id.srt?sig=...&expires=..."} ], "released_at":"2024-01-15T00:00:00Z", "created_at":"2026-01-10T08:00:00Z" } Subtitle Languages English (en) Indonesian (id) Arabic (ar) Chinese (zh) French (fr) German (de) Hindi (hi) Korean (ko) Portuguese (pt) Russian (ru) Spanish (es) Turkish (tr) Returned as subtitles[] array with lang, label, and signed url (SRT format). Quick Example GET /api/moviebox?type=movies Copy curl"https://api.splay.id/api/moviebox?type=movies&per_page=20"\ -H"Authorization: Bearer " MovieBox API Endpoints Dedicated /api/moviebox/* endpoints for MovieBox content (movies + series). Use ?type=movies or ?type=series to scope results, or omit for both. Authentication Required All data endpoints require Authorization: Bearer . Get your key atapi-dashboard. GET /api/moviebox List MovieBox content — movies, series, or both Parameter Type Required Description type string optional movies | series (absent = both) page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) language string optional ISO 639-1 language code (en, id, zh, ko, …) tag string optional Filter by tag name sort_by string optional updated_at | created_at | title | vote_average | release_year | play_count | chapter_count sort_order string optional desc | asc Example /api/moviebox?type=movies&per_page=20&sort_by=updated_at GET /api/moviebox/popular Popular MovieBox titles ranked by play_count Parameter Type Required Description type string optional movies | series (absent = both) language string optional ISO 639-1 language code Example /api/moviebox/popular?type=series GET /api/moviebox/trending Trending titles (updated last 60 days, sorted by play_count) Parameter Type Required Description type string optional movies | series (absent = both) language string optional ISO 639-1 language code Example /api/moviebox/trending?type=movies GET /api/moviebox/search Full-text search across MovieBox content Parameter Type Required Description q string required Search query type string optional movies | series (absent = both) language string optional ISO 639-1 language code Example /api/moviebox/search?q=stranger+things&type=series GET /api/moviebox/{id} Get movie/series detail with all episodes and signed video URLs Parameter Type Required Description id number required Drama ID (integer) expires_in number optional Signed URL TTL in seconds (max 14400, default 1800) Example /api/moviebox/42 GET /api/moviebox/{id}/episodes Paginated episodes for a movie/series Parameter Type Required Description id number required Drama ID (integer) page number optional Page number (default: 1) per_page number optional Results per page (max 100, default 20) expires_in number optional Signed URL TTL in seconds (max 14400, default 1800) Example /api/moviebox/42/episodes?page=1&per_page=50 Episode Response Shape Each episode object contains video_url (primary 720p, signed) and a qualities JSON object with all available resolutions. Episode object Copy { "id": 42, "drama_id": 7, "episode_index": 1001, // season×1000 + ep — Movie: 1, S1E1: 1001, S2E5: 2005 "episode_name":"Episode 1", "status":"published", // Primary video (720p) — HMAC-SHA256 signed, 5min TTL by default "video_url":"https://cdn.splay.id/moviebox-movies/.../video.mp4?sig=...&expires=...", // All available resolutions — same signed CDN URLs "qualities": { "360p":"https://cdn.splay.id/.../video_360p.mp4?sig=...&expires=...", "480p":"https://cdn.splay.id/.../video_480p.mp4?sig=...&expires=...", "720p":"https://cdn.splay.id/.../video.mp4?sig=...&expires=...", "1080p":"https://cdn.splay.id/.../video_1080p.mp4?sig=...&expires=..." }, // Subtitles — signed SRT URLs "subtitles": [ {"lang":"en","label":"English","url":"https://cdn.splay.id/.../subtitle_en.srt?sig=..."}, {"lang":"id","label":"Indonesian","url":"https://cdn.splay.id/.../subtitle_id.srt?sig=..."}, {"lang":"zh","label":"Chinese","url":"https://cdn.splay.id/.../subtitle_zh.srt?sig=..."} ], "released_at":"2024-01-15T00:00:00Z", "created_at":"2026-01-10T08:00:00Z" } Drama Response Shape Each drama object includes a raw_data field with full TMDB enrichment — ratings, cast, crew, genres, trailers, production info, and more. Drama object (raw_data.tmdb enrichment) Copy { "id": 123, "title":"Oppenheimer", "cover_url":"https://cdn.splay.id/moviebox-movies/.../cover.jpg", "provider_slug":"moviebox-movies", "chapter_count": 1, "introduction":"The story of J. Robert Oppenheimer...", "raw_data": { "release_year": 2023, "tmdb": { "id": 872585, "imdb_id":"tt15398776", "original_title":"Oppenheimer", "original_language":"en", "overview":"The story of J. Robert Oppenheimer...", "tagline":"The world forever changes.", "status":"Released", "release_date":"2023-07-19", "runtime": 180, "vote_average": 8.1, "vote_count": 18254, "certification":"R", "popularity": 85.4, "budget": 100000000, "revenue": 952000000, "genres": [{"id": 18,"name":"Drama"}, {"id": 36,"name":"History"}], "keywords": [{"id": 1,"name":"nuclear bomb"}, {"id": 2,"name":"manhattan project"}], "cast": [ {"id": 1185335,"name":"Cillian Murphy","character":"J. Robert Oppenheimer","order": 0 }, {"id": 3291,"name":"Emily Blunt","character":"Katherine Oppenheimer","order": 1 } ], "directors": [{"id": 525,"name":"Christopher Nolan","job":"Director"}], "writers": [{"id": 525,"name":"Christopher Nolan","job":"Screenplay"}], "producers": [{"id": 9813,"name":"Emma Thomas","job":"Producer"}], "production_companies": [{"id": 9996,"name":"Syncopy","origin_country":"GB"}], "production_countries": [{"iso":"US","name":"United States of America"}], "spoken_languages": [{"iso":"en","name":"English","english_name":"English"}], "collection": {"id": 0,"name":"Oppenheimer Collection"}, "poster_path":"/8Gxv8gSFCU0XGDykEGv7zR1n2ua.jpg", "backdrop_path":"/fm6KqXpk3M2HVveHwCrBSSBaO0V.jpg", "backdrops": [{"file_path":"/...","width": 1280,"height": 720 }], "trailers": [{"key":"uYPbbksJxIY","site":"YouTube","type":"Trailer","official": true }] } } } TMDB images: https://image.tmdb.org/t/p/w500{poster_path} · Backdrop: w1280 · Trailer: https://youtube.com/watch?v={key} Episode Index Encoding MovieBox uses a compound episode_index: season × 1000 + episode Season/Episode episode_index Notes Movie (se=0, ep=1) 1 All movies use index 1 S1E1 1001 S1E10 1010 S2E5 2005 S3E12 3012 MovieBox API Code Examples Ready-to-use examples for the MovieBox API — browse, search, video playback, TMDB enrichment (cast, genres, trailers, images, ratings, and more). Your API Key Active Paste your API key to authenticate the "Try" buttons and inject it into code examples.Get your key → sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc Save Clear Try It Live Browse Content GET /api/moviebox?type=movies&per_page=5 Send GET /api/moviebox?type=series&per_page=5 Send GET /api/moviebox?type=movies&sort_by=vote_average&sort_order=desc&per_page=5 Send GET /api/moviebox?type=movies&sort_by=release_year&sort_order=desc&per_page=5 Send GET /api/moviebox/popular?type=movies Send GET /api/moviebox/popular?type=series Send GET /api/moviebox/trending Send Search GET /api/moviebox/search?q=money+heist&per_page=5 Send GET /api/moviebox/search?q=john+wick&type=movies&per_page=5 Send GET /api/moviebox/search?q=stranger+things&type=series&per_page=5 Send cURL cURL Examples Copy API_KEY="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" BASE="https://api.splay.id" # ── List movies ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/moviebox?type=movies&per_page=20" # ── List series ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/moviebox?type=series&per_page=20" # ── List both (movies + series) ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/moviebox?per_page=20" # ── Sort by rating (highest rated first) ── curl -H"Authorization: Bearer $API_KEY"\ "$BASE/api/moviebox?type=movies&sort_by=vote_average&sort_order=desc&per_page=20" # ── Sort by release year (newest first) ── curl -H"Authorization: Bearer $API_KEY"\ "$BASE/api/moviebox?type=movies&sort_by=release_year&sort_order=desc&per_page=20" # ── Popular movies / series / both ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/moviebox/popular?type=movies" curl -H"Authorization: Bearer $API_KEY""$BASE/api/moviebox/popular?type=series" # ── Trending ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/moviebox/trending" # ── Movie/series detail (all episodes + TMDB enrichment + signed video URLs) ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/moviebox/DRAMA_ID" # ── Paginated episodes ── curl -H"Authorization: Bearer $API_KEY"\ "$BASE/api/moviebox/DRAMA_ID/episodes?page=1&per_page=50" # ── Search ── curl -H"Authorization: Bearer $API_KEY""$BASE/api/moviebox/search?q=money+heist" curl -H"Authorization: Bearer $API_KEY""$BASE/api/moviebox/search?q=stranger+things&type=series" JavaScript / TypeScript Browse & Search Copy const BASE ="https://api.splay.id"; const API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // ── List movies (paginated) ── const res = await fetch(`${BASE}/api/moviebox?type=movies&per_page=20`, { headers }); const { data, meta } = await res.json(); console.log(`${meta.total} movies (page ${meta.page}/${meta.total_pages})`); data.forEach(m => console.log(`[${m.id}] ${m.title}`)); // ── Sort by TMDB rating (highest first) ── const topRated = await fetch( `${BASE}/api/moviebox?type=movies&sort_by=vote_average&sort_order=desc&per_page=20`, { headers } ); // ── Sort by release year (newest first) ── const newest = await fetch( `${BASE}/api/moviebox?type=movies&sort_by=release_year&sort_order=desc&per_page=20`, { headers } ); // ── Popular ── const { data: popularMovies } = await ( await fetch(`${BASE}/api/moviebox/popular?type=movies`, { headers }) ).json(); // ── Trending ── const { data: trending } = await ( await fetch(`${BASE}/api/moviebox/trending`, { headers }) ).json(); // ── Search ── const { data: results, meta: searchMeta } = await ( await fetch(`${BASE}/api/moviebox/search?q=money+heist&type=series`, { headers }) ).json(); console.log(`Found ${searchMeta.total} results`); Get Detail + Play Video Copy const BASE ="https://api.splay.id"; const API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc"; const headers = { Authorization: `Bearer ${API_KEY}` }; // ── Movie/Series detail (drama + episodes with signed URLs + TMDB data) ── const res = await fetch(`${BASE}/api/moviebox/DRAMA_ID`, { headers }); const { data: { drama, episodes } } = await res.json(); console.log(`${drama.title} — ${episodes.length} episodes`); // ── Video URLs — episode_index encoding: // Movie (se=0, ep=1) → 1 // S1E1 → 1001, S2E5 → 2005, S3E12 → 3012 const ep = episodes[0]; // video_url = primary (720p), signed HMAC-SHA256, 5min TTL console.log("Primary (720p):", ep.video_url); // qualities = all resolutions as JSON object console.log("360p:", ep.qualities?.["360p"]); // always available console.log("480p:", ep.qualities?.["480p"]); // always available console.log("720p:", ep.qualities?.["720p"]); // same as video_url console.log("1080p:", ep.qualities?.["1080p"]); // premium content // ── Pick best available quality ── const videoUrl = ep.qualities?.["1080p"] ?? ep.qualities?.["720p"] ?? ep.video_url ?? ep.qualities?.["480p"] ?? ep.qualities?.["360p"]; const video = document.querySelector("video"); if (video && videoUrl) { video.src = videoUrl; // direct MP4 — no HLS library needed video.play(); } // ── Subtitles (signed SRT URLs, 12+ languages) ── // subtitles: [{ lang, label, url }] for (const sub of ep.subtitles ?? []) { console.log(`[${sub.lang}] ${sub.label}: ${sub.url}`); } // ── Paginated episodes for a long series ── const { data: eps, meta } = await ( await fetch(`${BASE}/api/moviebox/DRAMA_ID/episodes?page=1&per_page=50`, { headers }) ).json(); console.log(`${meta.total} total episodes, showing ${eps.length}`); TMDB Enrichment Every drama includes a raw_data.tmdb field with full TMDB metadata — ratings, cast, crew, genres, trailers, images, keywords, production info, and more. JavaScript — using TMDB data Copy const { data: { drama } } = await ( await fetch(`${BASE}/api/dramas/DRAMA_ID`, { headers }) ).json(); const tmdb = drama.raw_data?.tmdb; if (!tmdb) { console.log("No TMDB data"); process.exit(0); } // ── Basic info ── console.log("Title:", drama.title); console.log("Original:", tmdb.original_title, `(${tmdb.original_language})`); console.log("Tagline:", tmdb.tagline); console.log("Year:", drama.raw_data?.release_year ?? tmdb.release_date?.slice(0,4)); console.log("Runtime:", tmdb.runtime,"min"); // e.g. 180 console.log("Rating:", tmdb.vote_average, `(${tmdb.vote_count} votes)`); console.log("Cert:", tmdb.certification); //"PG-13","R","TV-MA", etc. console.log("Status:", tmdb.status); //"Released","Ended","Returning Series" // ── Poster / backdrop images (TMDB CDN) ── const TMDB_IMG ="https://image.tmdb.org/t/p"; if (tmdb.poster_path) console.log("Poster 500px:", `${TMDB_IMG}/w500${tmdb.poster_path}`); if (tmdb.backdrop_path) console.log("Backdrop:", `${TMDB_IMG}/w1280${tmdb.backdrop_path}`); // Top backdrops (w1280, voted by quality) for (const img of tmdb.backdrops ?? []) { console.log(`Backdrop ${img.width}×${img.height}: ${TMDB_IMG}/w1280${img.file_path}`); } // ── Genres ── console.log("Genres:", (tmdb.genres ?? []).map(g => g.name).join(",")); // e.g."Action, Thriller, Crime" // ── Keywords ── console.log("Keywords:", (tmdb.keywords ?? []).map(k => k.name).join(",")); // e.g."heist, bank robbery, gang" // ── Cast (top 20) ── for (const actor of tmdb.cast ?? []) { console.log(`${actor.name} as ${actor.character}`); if (actor.profile_path) console.log("Photo:", `${TMDB_IMG}/w185${actor.profile_path}`); } // ── Crew ── console.log("Directors:", (tmdb.directors ?? []).map(d => d.name).join(",")); console.log("Writers:", (tmdb.writers ?? []).map(w => w.name).join(",")); console.log("Producers:", (tmdb.producers ?? []).map(p => p.name).join(",")); // ── Trailers (YouTube) ── const trailer = (tmdb.trailers ?? []).find(t => t.type ==="Trailer"&& t.site ==="YouTube"); if (trailer) console.log("Trailer:", `https://youtube.com/watch?v=${trailer.key}`); // ── Production ── console.log("Studios:", (tmdb.production_companies ?? []).map(c => c.name).join(",")); console.log("Countries:", (tmdb.production_countries ?? []).map(c => c.name).join(",")); console.log("Languages:", (tmdb.spoken_languages ?? []).map(l => l.english_name).join(",")); // ── Box office (movies only) ── if (tmdb.budget) console.log("Budget:", `$${(tmdb.budget / 1e6).toFixed(0)}M`); if (tmdb.revenue) console.log("Revenue:", `$${(tmdb.revenue / 1e6).toFixed(0)}M`); // ── Series-specific ── console.log("Seasons:", tmdb.number_of_seasons); console.log("Total eps:", tmdb.number_of_episodes); console.log("Networks:", (tmdb.networks ?? []).map(n => n.name).join(",")); // Netflix, HBO... console.log("Creators:", (tmdb.creators ?? []).map(c => c.name).join(",")); // ── Franchise / collection (movies) ── if (tmdb.collection) console.log("Collection:", tmdb.collection.name); // ── External IDs ── if (tmdb.imdb_id) console.log("IMDb:", `https://imdb.com/title/${tmdb.imdb_id}`); if (tmdb.tvdb_id) console.log("TVDB ID:", tmdb.tvdb_id); Build a movie card UI (React) Copy import type { Drama } from"./types"; const TMDB_IMG ="https://image.tmdb.org/t/p"; function MovieCard({ drama }: { drama: Drama }) { const tmdb = drama.raw_data?.tmdb; const year = drama.raw_data?.release_year ?? tmdb?.release_date?.slice(0, 4); const runtime = tmdb?.runtime ? `${Math.floor(tmdb.runtime / 60)}h ${tmdb.runtime % 60}m` : null; const genres = (tmdb?.genres ?? []).slice(0, 3).map(g => g.name); const trailer = (tmdb?.trailers ?? []).find( t => t.type ==="Trailer"&& t.site ==="YouTube" ); return (
{/* Poster from TMDB (or fallback to CDN cover) */} {drama.title}

{drama.title}

{tmdb?.tagline &&

{tmdb.tagline}

}
{year && {year}} {tmdb?.certification && {tmdb.certification}} {runtime && {runtime}} {tmdb?.vote_average && ( ★ {tmdb.vote_average.toFixed(1)} )}
{genres.map(g => {g})}

{tmdb?.overview ?? drama.introduction}

{(tmdb?.cast ?? []).slice(0, 5).map(actor => (
{actor.profile_path && ( {actor.name} )} {actor.name} {actor.character}
))}
{trailer && ( Watch Trailer )}
); } Python Full Example Copy import requests BASE ="https://api.splay.id" API_KEY ="sk_live_afb4c24ea8c44d30a06c67ecc67a8f85a46a0987c8d899bc" headers = {"Authorization": f"Bearer {API_KEY}"} TMDB_IMG ="https://image.tmdb.org/t/p" # ── List movies ── res = requests.get(f"{BASE}/api/moviebox", params={ "type":"movies","per_page": 20,"sort_by":"vote_average", "sort_order":"desc" }, headers=headers) for m in res.json()["data"]: tmdb = (m.get("raw_data") or {}).get("tmdb") or {} rating = tmdb.get("vote_average", 0) year = (m.get("raw_data") or {}).get("release_year","") print(f"[{m['id']}] {m['title']} ({year}) ★{rating:.1f}") # ── Top-rated series ── series = requests.get(f"{BASE}/api/moviebox", params={ "type":"series","per_page": 20, "sort_by":"vote_average","sort_order":"desc" }, headers=headers) # ── Detail with full TMDB data ── detail = requests.get(f"{BASE}/api/moviebox/DRAMA_ID", headers=headers) info = detail.json()["data"] drama, episodes = info["drama"], info["episodes"] tmdb = (drama.get("raw_data") or {}).get("tmdb") or {} print(f"\n=== {drama['title']} ===") print(f"Tagline: {tmdb.get('tagline')}") print(f"Rating: {tmdb.get('vote_average')} ({tmdb.get('vote_count')} votes)") print(f"Certification: {tmdb.get('certification')}") print(f"Runtime: {tmdb.get('runtime')} min") print(f"Genres: {', '.join(g['name'] for g in tmdb.get('genres', []))}") print(f"Keywords: {', '.join(k['name'] for k in tmdb.get('keywords', [])[:10])}") # Poster / backdrop if tmdb.get("poster_path"): print(f"Poster: {TMDB_IMG}/w500{tmdb['poster_path']}") if tmdb.get("backdrop_path"): print(f"Backdrop: {TMDB_IMG}/w1280{tmdb['backdrop_path']}") # Cast print("\nCast:") for actor in tmdb.get("cast", [])[:5]: print(f"{actor['name']} as {actor.get('character', '?')}") # Crew print("Directors:",",".join(d["name"] for d in tmdb.get("directors", []))) print("Writers:",",".join(w["name"] for w in tmdb.get("writers", []))) # Trailer for t in tmdb.get("trailers", []): if t["type"] =="Trailer"and t["site"] =="YouTube": print(f"Trailer: https://youtube.com/watch?v={t['key']}") break # Production print("Studios:",",".join(c["name"] for c in tmdb.get("production_companies", []))) if tmdb.get("budget"): print(f"Budget: ${tmdb['budget'] / 1e6:.0f}M") if tmdb.get("revenue"): print(f"Revenue: ${tmdb['revenue'] / 1e6:.0f}M") # Series-specific if tmdb.get("number_of_seasons"): print(f"Seasons: {tmdb['number_of_seasons']}, Episodes: {tmdb['number_of_episodes']}") print("Networks:",",".join(n["name"] for n in tmdb.get("networks", []))) # External links if tmdb.get("imdb_id"): print(f"IMDb: https://imdb.com/title/{tmdb['imdb_id']}") # ── Video URLs (signed MP4, 1h TTL) ── # episode_index: Movie→1, S1E1→1001, S2E5→2005, S3E12→3012 ep = episodes[0] qualities = ep.get("qualities") or {} video_url = ( qualities.get("1080p") or qualities.get("720p") or ep.get("video_url") or qualities.get("480p") or qualities.get("360p") ) print(f"\nBest video URL: {video_url}") # Subtitles (signed SRT URLs, 12+ languages) for sub in ep.get("subtitles", []): print(f"[{sub['lang']}] {sub['label']}: {sub['url']}") TMDB Image URLs poster_path andbackdrop_path are relative paths — prepend the TMDB image CDN base: Use Case Size URL Pattern Poster — card w342 https://image.tmdb.org/t/p/w342{poster_path} Poster — detail w500 https://image.tmdb.org/t/p/w500{poster_path} Poster — original original https://image.tmdb.org/t/p/original{poster_path} Backdrop — hero w1280 https://image.tmdb.org/t/p/w1280{backdrop_path} Profile — cast w185 https://image.tmdb.org/t/p/w185{cast[n].profile_path} Trailers: https://youtube.com/watch?v={trailers[0].key} — always YouTube, official Trailer or Teaser type. Episode Index Encoding episode_index = season × 1000 + episode Season/Episode episode_index Notes Movie (se=0, ep=1) 1 All movies S1E1 1001 S1E10 1010 S2E5 2005 S3E12 3012 dari semuanya sudah saya lengkapi tolong buatkan website premium tampilannya degan semuanya jadi satu di website memiiliki navbarbawah seperti android buatkan fulllstack websitenya semuanya harus ada yg jika bisa digunakan AI (BETA) Anime Baca iQIYI MovieBox Short Drama DrakorIndo WeTV