Melolo is an Indonesian short drama platform powered by ByteDance's Fizzo engine, featuring 821+ drama series. This API provides search, trending, episode streaming with CENC DRM decryption, multi-quality video options, and 16 language support.
Melolo videos are CENC AES-128-CTR encrypted (DRM protected by ByteDance/Fizzo). The API provides 4 methods to play them — from zero-effort to full DIY.
hlsUrl from the episode response. Our server fetches the encrypted MP4 from TikTok CDN, decrypts it with CENC AES-128-CTR, and streams you a clean MP4. Zero client-side DRM code needed./api/melolo/player URL in a browser. The page fetches the encrypted MP4 directly from TikTok CDN, decrypts it client-side using SubtleCrypto (WebCrypto API), and plays via Blob URL. Our server uses zero bandwidth./sw-play requests, streams decrypted MP4./api/melolo/decrypt-info, then implement your own CENC decryption. Useful for native apps, ffmpeg pipelines, or custom players.Which method should I use?
• Method 1 (Server HLS) — Simplest. Just use hlsUrl. Server handles everything.
• Method 2 (Client Player) — Best for web apps. Zero server bandwidth, full browser decrypt.
• Method 3 (SW Streaming) — Fastest playback start. Progressive decrypt in ~2 seconds.
• Method 4 (DIY) — For custom integrations, native apps, ffmpeg pipelines.
melolo-decrypt.jsA standalone JavaScript library for client-side CENC AES-128-CTR decryption using the WebCrypto API. Supports streaming overlap decrypt (decrypts while downloading), pre-allocated buffers, and parallel sample processing.
MeloloDecrypt.play() method handles everything: fetches episode data, gets the DRM key, downloads + decrypts the encrypted MP4, and plays it.MeloloDecrypt.decrypt() for manual control. Pass the encrypted CDN URL and hex key, get back a playable Blob.Streaming overlap: melolo-decrypt.js starts decrypting samples as soon as their bytes arrive — while the rest of the file is still downloading. This reduces total time by up to 40% compared to download-then-decrypt.
All Melolo endpoints require the X-API-Key header.
| Plan | Requests / min |
|---|---|
| Free | 10 |
| Monthly | 5,000 |
| Lifetime | Unlimited |
foryou — both use the same content feed.| Parameter | Type | Description |
|---|---|---|
| langoptional | string | Language code (default: id) |
| pageoptional | integer | Page number (default: 1) |
trending and latest.| Parameter | Type | Description |
|---|---|---|
| langoptional | string | Language code (default: id) |
| pageoptional | integer | Page number (default: 1) |
page and limit params.| Parameter | Type | Description |
|---|---|---|
| queryrequired | string | Search keyword |
| pageoptional | integer | Page number (default: 1) |
| limitoptional | integer | Results per page, max 50 (default: 30) |
| langoptional | string | Language code (default: id) |
| Parameter | Type | Description |
|---|---|---|
| idrequired | string | Book ID from search or trending results |
| langoptional | string | Language code (default: id) |
episode endpoint which returns hlsUrl (direct playable MP4).
| Parameter | Type | Description |
|---|---|---|
| idrequired | string | Book ID |
| langoptional | string | Language code (default: id) |
hlsUrl.
hlsUrl (direct playable MP4, server-side decrypt),
qualityList with per-quality hlsUrl, contentKey (for advanced clients doing their own decrypt).
| Parameter | Type | Description |
|---|---|---|
| idrequired | string | Book ID |
| eprequired | integer | Episode number (1-based) |
| langoptional | string | Language code (default: id) |
| qoptional | string | Quality label (e.g. 720p) |
hlsUrl from the /episode response. Requires API key (either X-API-Key header or api_key query parameter).
| Parameter | Type | Description |
|---|---|---|
| idrequired | string | Book ID |
| eprequired | integer | Episode number (1-based) |
| langoptional | string | Language code (default: id) |
| qoptional | string | Quality label (e.g. 720p) |
| api_keyoptional | string | API Key (alternative to X-API-Key header, useful for direct video links) |
| Parameter | Type | Description |
|---|---|---|
| idrequired | string | Book ID |
| eprequired | integer | Episode number (1-based) |
| langoptional | string | Language code (default: id) |
| qoptional | string | Quality label (e.g. 720p) |
| Parameter | Type | Description |
|---|---|---|
| idrequired | string | Book ID |
| eprequired | integer | Episode number (1-based) |
| langoptional | string | Language code (default: id) |
| qoptional | string | Quality label (e.g. 720p) |
| Parameter | Type | Description |
|---|---|---|
| vidrequired | string | Video ID or KID from episode qualityList |
| Parameter | Type | Description |
|---|---|---|
| kidoptional | string | Key ID (hex). Can also be sent in request body as {"kids":["base64url_kid"]} |
videoID must have been previously registered via an /episode call.
| Parameter | Type | Description |
|---|---|---|
| videoIDrequired | path | Video ID from episode qualityList (path segment, not query param) |
/api/melolo/license for browser-native DRM playback.
| Parameter | Type | Description |
|---|---|---|
| videoIDrequired | path | Video ID (must be registered via /episode call first) |
| Parameter | Type | Description |
|---|---|---|
| bookIDrequired | path | Book ID (path segment) |
| epoptional | integer | Episode number (default: 1) |
/melolo-sw.js) so its scope covers /sw-play requests.
The SW intercepts /sw-play?url=CDN&key=HEX fetches, downloads encrypted MP4,
parses moov early, then streams decrypted bytes progressively.
MeloloDecrypt.decrypt() and
MeloloDecrypt.play() methods. See the JavaScript SDK section above for usage.
Encryption: Melolo uses CENC AES-128-CTR (Common Encryption with AES-128 in Counter mode). Each video is an ISO BMFF (MP4) container with encrypted mdat samples. The content key is derived from ByteDance's spade_a blob via a proprietary key derivation function.
Key Storage: Content keys are automatically derived and stored when you call the /episode endpoint. Keys are indexed by both videoID and KID (from the MP4's tenc box). The keystore persists to keys.json on disk.
Decryption Flow (CENC sample-based):
moov → trak → stblsenc box (8-byte initialization vectors)stsz + stsc + stcoAES-CTR(key, counter=IV||0x00000000, sample_data)encv→hvc1, sinf/senc/tenc→freeCDN: Encrypted videos are hosted on TikTok's CDN (v3-default.ixigua.com, v26-default.ixigua.com, etc.). Client-side decrypt methods fetch directly from CDN, using zero server bandwidth.