Reelora API
REST API for programmatic integration of subtitles, voiceover, transcription, dubbing, and pause removal. The same capabilities as the Telegram bot — via HTTP. Available on all plans, including Free.
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /health | Service health check |
| GET | /v1/me | Profile, limits, usage |
| POST | /v1/uploads | Upload file |
| POST | /v1/tasks | Create task |
| GET | /v1/tasks | List of tasks |
| GET | /v1/tasks/{id} | Task status + result |
Quick Start
Get API Key
In the bot @reelora_ai_bot send /apikey or open Settings → 🔑 API Access. The key is shown only once.
Upload File
POST /v1/uploads → get upload_id
Create Task
POST /v1/tasks with type and parameters
Get Result
Poll GET /v1/tasks/{id} or specify webhook_url
Authentication
All requests (except /health) require the header:
X-API-Key: reel_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Base URL
https://api.reelora.cc
Interactive Swagger documentation: https://api.reelora.cc/docs
Status Check
curl https://api.reelora.cc/health
# {"status":"ok","service":"reelora-api"}
Profile and Limits
curl https://api.reelora.cc/v1/me -H "X-API-Key: reel_..."
{
"user_id": 618899534, "tariff": "pro_plus",
"tariff_expires_at": "2026-07-17T07:20:20",
"limits": {
"seconds_per_month": 36000, "tts_chars_limit": 1000000,
"elevenlabs_chars_limit": 25000, "transcription_seconds": 72000,
"max_photos": 30, "max_video_duration": 600, "max_file_size_mb": 500,
"can_translate": true, "can_dub": true, "premium_voices": true
},
"usage": {
"used_seconds_this_month": 705, "used_chars_this_month": 12674,
"used_eleven_chars_this_month": 0, "used_transcription_seconds": 0,
"limit_reset_date": "2026-07-17T07:18:07"
},
"api_key_prefix": "xxxxxxxx", "api_key_created_at": "2026-06-19T22:43:23"
}
File Upload
Uploads a file and returns upload_id. Files live for 2 hours. Limit: 20 uploads/min.
curl -X POST https://api.reelora.cc/v1/uploads \
-H "X-API-Key: reel_..." -F "[email protected]"
# {"upload_id":"550e8400-...","filename":"photo.jpg","size_bytes":245891}
| Type | Formats | Max. |
|---|---|---|
| Images | JPEG, PNG, WebP | 500 MB |
| Video | MP4, MOV, AVI | 500 MB |
| Audio | MP3, WAV, M4A | 500 MB |
| Subtitles | SRT | — |
Use upload_id in the photos, file, srt_file, bgm_file fields. Alternatively, you can pass direct https:// URLs instead of uploading.
Task Creation
Task type is defined in the "type" field. Executed asynchronously. All types support webhook_url and send_to_telegram.
{ "task_id": 744, "status": "pending" }
Type: video — video creation
Photos or video clips + voiceover + karaoke subtitles + music → MP4.
{
"type": "video",
"photos": ["upload_id_1", "https://example.com/img.jpg"],
"text": "Text for voiceover",
"scene_durations": null, "scene_transitions": null, "target_duration": 30,
"format": "9_16", "animation": "ken_burns", "transition": "random", "transition_duration": 0.5,
"tts_provider": "google", "tts_voice": "Chirp3-HD-Aoede",
"tts_scene": "Speak like a news anchor.",
"subtitles": true, "sub_style": "yellow_basic", "sub_position": "bottom",
"bgm_track": "chill_background-lofi-vibes-113884.mp3", "bgm_volume": 0.2
}
| Field | Default | Description | |
|---|---|---|---|
| photos | required | — | upload_id or https:// (images or video clips, max. 30) |
| text | optional | null | Texte de la voix off. Sans texte — vidéo sans son. Insère des marqueurs de scène entre les paragraphes pour changer le plan (et choisir la transition) : {scene} · {scene:slide} · {scene:zoom:0.8} · {scene:0.8} |
| scene_durations | optional | null | Durées explicites par média en secondes, ex. [10, 15, 5]. Longueur = nombre de médias. Remplace l’auto-timing {scene}, fonctionne même sans voix |
| scene_transitions | optional | null | Transition explicite par coupe (longueur = photos − 1), ex. ["slide","zoom"]. Alternative aux marqueurs {scene:type} |
| target_duration | optional | null | Durée cible du clip en secondes. Si le résultat est plus long, il est accéléré (vidéo+audio+sous-titres synchronisés) pour tenir. Plus court — laissé tel quel. Accélération limitée à ×2. Doit être ≤ la limite de votre forfait |
| format | optional | "9_16" | "9_16" · "16_9" · "1_1" · "original" |
| animation | optional | "none" | "none" · "ken_burns" |
| transition | optional | "crossfade" | Transition globale pour les coupes non marquées : none · random · fade · dissolve · slide · cover · reveal · zoom · squeeze · wind · pixel · circle (crossfade = alias de dissolve). Actif seulement quand animation ≠ none |
| transition_duration | optional | 0.5 | Durée de transition en secondes. Durée par coupe via {scene:type:sec} |
| tts_provider | optional | "google" | TTS provider (see Providers section) |
| tts_voice | optional | from profile | Voice name (see Voices section) |
| tts_speed | optional | 1.0 | 0.8 · 1.0 · 1.2 · 1.5 |
| language | optional | — | Langue de la voix off — n’importe quel code de la section Langues ("ar", "fa"…) ou un locale complet "ru-RU". Pour les langues rares — tts_provider:"edge" |
| tts_scene | optional | null | Speech style instruction (for Gemini TTS) |
| tts_style | optional | null | Voice style preset: standard · calm · expressive · energetic · dramatic · cheerful (Gemini and ElevenLabs) |
| subtitles | optional | true | Karaoke subtitles |
| sub_style | optional | "yellow_basic" | Subtitle style |
| sub_position | optional | "bottom" | "top" · "center" · "bottom" |
| sub_size | optional | "medium" | "small" · "medium" · "large" |
| sub_color | optional | null | ASS color: "&H0000E6FF" (yellow) |
| text_overlays | optional | null | Légendes statiques par-dessus l'image, indépendantes de la voix off (voir « Texte sur la vidéo » ci-dessous) |
| text_overlays_raw | optional | null | La même chose sous forme de chaîne « codes » compacte, analysée côté serveur (voir ci-dessous). Utilisé seulement si text_overlays est absent |
| auto_text | optional | false | ⚡ Auto-texte. Un LLM choisit les mots-clés les plus forts de la voix off et les ajoute en légendes animées, synchronisées sur les timestamps de mots du TTS (voir « Auto-texte » ci-dessous). Nécessite text. Décompté de votre quota mensuel d'auto-texte |
| bgm_track | optional | null | File name from the music library (see BGM section) |
| bgm_file | optional | null | upload_id of your own MP3 file (mutually exclusive with bgm_track) |
| bgm_volume | optional | 0.2 | Music volume 0.0–1.0 |
| audio_mix_type | optional | "replace" | Mixing for video clips: "replace" · "add" · "overlay" |
audio_mix_type — for clips with original sound
| Value | Behavior |
|---|---|
| replace | TTS/BGM only — clip sound is removed |
| add | TTS on top of original (both at full volume) |
| overlay | TTS at full volume + original audio is ducked |
🎬 Scènes dynamiques — quand le plan change
- Avec voix : insère des marqueurs {scene} dans text entre les paragraphes. Chaque segment est cadencé par la narration et associé aux médias dans l’ordre. Les marqueurs sont retirés avant le TTS — la voix ne les lit jamais.
- Sans voix / explicite : passe scene_durations (ex. [10, 15, 5]) — une valeur par média. Les clips sont coupés/bouclés, les photos affichées pour la durée de la scène.
- Scènes ↔ médias : égal → 1:1 ; moins de scènes → la dernière se répartit sur le reste ; plus → le dernier média garde le reste.
✨ Transitions par coupe — comment le plan change
- Dans le texte : étends un marqueur avec un type et/ou une durée : {scene:slide}, {scene:zoom:0.8}, {scene:0.8} (durée seule). La transition s’applique à la coupe vers cette scène.
- Tableau explicite : scene_transitions (longueur = photos − 1), ex. ["slide","zoom","fade"] — une transition par coupe. Pratique pour les vidéos muettes à durées explicites.
- Types : fade · dissolve · slide · cover · reveal · zoom · squeeze · wind · pixel · circle · random. Les directionnelles (slide/cover/reveal/wind) choisissent une direction aléatoire par coupe.
🅰️ Texte sur la vidéo — légendes statiques
Ajoutez des légendes/titres arbitraires par-dessus la vidéo, indépendamment des sous-titres. Fonctionne avec ou sans narration. Chaque légende a son style, sa position, son timing et son fondu. Deux façons de les passer :
Structuré — text_overlays (tableau, max 10) :
"text_overlays": [
{ "text": "BIG TITLE", "style": "bold_yellow", "size": "large",
"position": "top_center", "start": 0.0, "end": 3.0, "fade": true, "anim": "pop" },
{ "text": "the end", "style": "soft_pink", "position": "bottom_center", "start": 3.0 }
]
| Champ | ||
|---|---|---|
| text | required | obligatoire, max 200 caractères |
| start | optional | s. null → à partir de 0 |
| end | optional | s. null → jusqu'à la fin de la vidéo |
| style | optional | style de titre (ci-dessous) |
| size | optional | small · medium · large |
| position | optional | grille 9 : top_left · top_center · top_right · middle_left · center · middle_right · bottom_left · bottom_center · bottom_right |
| bold / italic | optional | remplace la graisse/l'italique du style |
| color | optional | ASS hex &HAABBGGRR, ex. "&H00B469FF" (rose) |
| fade | optional | fondu d'entrée/sortie doux (300 ms) |
| anim | optional | Animation d'apparition : pop · slide_left · slide_right · type (machine à écrire). Prioritaire sur fade |
Styles de titre (style) : clean_white · bold_yellow · outline_black · soft_pink · elegant_script · news_bar · impact_red.
Codes — text_overlays_raw (chaîne). Syntaxe universelle en anglais (identique dans toutes les langues d'interface), analysée côté serveur. Une légende par ligne (ou séparées par /) ; champs internes séparés par |:
TEXT | attributes | start-end
"text_overlays_raw": "Hello | large italic center | 0-3 / Subscribe | bottom pink pop | 3-end"
- taille — small · medium · large
- graisse/italique — bold · thin · italic
- vertical — top · middle · bottom ; horizontal — left · center · right
- couleur — white · yellow · red · green · blue · pink · orange · purple · black · cyan
- temps — 0-3, 2.5-8, 5-end (s, point/virgule). Sans temps → la légende s'affiche tout le clip
- animation — pop · slide · type (machine à écrire) · fade · none
⚡ Auto-texte — légendes automatiques de mots-clés
auto_text: true active ⚡ Auto-texte. Au lieu de placer les légendes vous-même, un LLM lit les mots reconnus de la voix off, choisit les plus forts (noms, chiffres, affirmations percutantes) et les rend en légendes animées, exactement sur les timestamps de mots du TTS. Il choisit par mot un style moderne, une couleur et une animation d'apparition (pop / slide / typewriter), empile les mots dits ensemble et évite la zone des sous-titres.
- Nécessite une voix off (text non vide). Sans narration, il n'y a pas de timestamps de mots, donc auto_text est ignoré.
- Additif : les légendes générées s'ajoutent à vos text_overlays / text_overlays_raw, elles ne les remplacent pas.
- Entièrement automatique : aucun paramètre par mot. Si le LLM ne trouve rien, le rendu se poursuit simplement sans légendes supplémentaires (la requête n'échoue jamais).
- Quota : chaque rendu auto-texte réussi consomme une unité de votre quota mensuel (auto_text_limit ; gratuit limité, offres payantes illimitées). Au-delà de la limite → 429.
- L'auto-texte fonctionne dans tous les types de tâche de l'API : video, dubbing et subtitles. La traduction via l'API se fait par subtitles avec translate_to (pas de type translation séparé), donc auto_text couvre aussi les sous-titres traduits.
Type: transcription — transcription
Audio or video → text + .SRT with timecodes.
{
"type": "transcription", "file": "upload_id_or_https_url",
"language": "uk", "ai_prompt": "Medical podcast. Correct terminology.",
"output_format": "both"
}
| Field | Description | |
|---|---|---|
| file | required | upload_id or https:// URL |
| language | optional | "uk" · "en" · "de" · "fr" etc. null = auto |
| ai_prompt | optional | Context for Whisper (improves accuracy) |
| output_format | optional | "txt" · "srt" · "both" (default) |
// result_urls for transcription
{ "txt_url": "https://cdn.reelora.cc/.../transcript.txt",
"srt_url": "https://cdn.reelora.cc/.../transcript.srt" }
Type: audio — voiceover (TTS)
Text → MP3 file without video.
{
"type": "audio", "text": "Hello! This is a Reelora API test.",
"tts_provider": "gemini", "tts_voice": "Puck",
"tts_speed": 1.0, "tts_scene": "Warm and friendly tone",
"tts_style": "expressive"
}
| Field | Default | Description | |
|---|---|---|---|
| text | required | — | Text to synthesize |
| tts_provider | optional | "google" | TTS provider (see Providers section) |
| tts_voice | optional | from profile | Voice name (see Voices section) |
| tts_speed | optional | 1.0 | 0.8 · 1.0 · 1.2 · 1.5 |
| tts_scene | optional | null | Speech style instruction (for Gemini TTS) |
| tts_style | optional | null | Voice style preset: standard · calm · expressive · energetic · dramatic · cheerful (Gemini and ElevenLabs) |
Type: subtitles — subtitles on video
Burns karaoke subtitles into a finished video via Whisper + FFmpeg. Standard+ plan.
{
"type": "subtitles", "file": "upload_id_or_https_url",
"language": "uk", "sub_style": "yellow_basic",
"sub_position": "bottom", "sub_size": "medium"
}
Result: MP4 with subtitles in result_url. Seconds are deducted from the monthly limit.
| Champ | ||
|---|---|---|
| translate_to | optional | Code ISO d'une langue cible. Défini → les sous-titres y sont traduits (le timing est conservé, l'audio reste d'origine). Omis → dans la langue d'origine |
| auto_text | optional | ⚡ Auto-texte — légendes de mots-clés à partir des temps des sous-titres (traduits). Décompté de votre quota d'auto-texte |
Type: pause_removal — pause removal
Automatically cuts out silence and pauses from video. Standard+ plan. Silence threshold is detected automatically.
{ "type": "pause_removal", "file": "upload_id_or_https_url" }
Result: processed MP4 in result_url.
Type: dubbing — AI dubbing
Transcribes video, translates, synthesizes a new voice, mixes audio. Three modes. Available on all plans within the monthly limit.
Mode A: auto — fully automatic
{
"type": "dubbing", "mode": "auto",
"file": "upload_id_or_https_url",
"source_lang": "auto", "target_lang": "en",
"tts_provider": "edge", "tts_voice": "en-US-GuyNeural",
"mix_mode": "overlay", "overlay_volume": 20,
"sub_lang": "dubbed", "sub_style": "yellow_basic"
}
| Field | Default | Description | |
|---|---|---|---|
| file | required | — | upload_id or URL of the video to dub |
| source_lang | optional | "auto" | "auto" ou n’importe quel code de la section Langues ("ar", "fa", "tr"…). Whisper détecte automatiquement avec "auto" |
| target_lang | required | — | Langue de doublage — n’importe quel code de la section Langues. Si le fournisseur ne la parle pas — repli auto sur Edge |
| tts_provider | optional | "edge" | TTS provider for the new voice |
| tts_voice | optional | auto | Voice for the target language |
| mix_mode | optional | "overlay" | "overlay" (original is ducked) · "replace" (full replacement) |
| overlay_volume | optional | 20 | Original volume % when mix_mode=overlay (0–100) |
| sub_lang | optional | "dubbed" | "dubbed" · "original" · "none" · or ISO language code |
| sub_style | optional | "yellow_basic" | Subtitle style |
| sub_position | optional | "bottom" | "top" · "center" · "bottom" |
| tts_style | optional | null | Voice style preset: standard · calm · expressive · energetic · dramatic · cheerful (Gemini and ElevenLabs) |
| auto_text | optional | false | ⚡ Auto-texte par-dessus la voix doublée — légendes animées de mots-clés choisies par le LLM. Décompté de votre quota d'auto-texte |
Mode B: semi_auto — with verification (2 steps)
// Step 1: transcription
{ "type": "dubbing", "mode": "semi_auto", "step": "transcribe",
"file": "upload_id_video", "source_lang": "uk", "target_lang": "en" }
// → srt_url: download, edit, upload via /v1/uploads
// Step 2: render with edited SRT
{ "type": "dubbing", "mode": "semi_auto", "step": "render",
"file": "upload_id_video", "srt_file": "upload_id_of_your_srt",
"target_lang": "en", "tts_provider": "edge",
"tts_voice": "en-US-GuyNeural", "mix_mode": "overlay", "overlay_volume": 20 }
Mode C: manual — own SRT file
Skips transcription. You provide your own SRT file containing text in the target language.
{ "type": "dubbing", "mode": "manual",
"file": "upload_id_video", "srt_file": "upload_id_of_srt_file",
"target_lang": "uk", "tts_voice": "uk-UA-Wavenet-A", "mix_mode": "replace" }
1\n00:00:00,000 --> 00:00:03,500\nLine text\n\n2\n... Timecodes must not exceed video duration.List of Tasks
curl "https://api.reelora.cc/v1/tasks?limit=10&offset=0" -H "X-API-Key: reel_..."
Parameters: limit (default 20, max 100), offset (default 0).
Task Status
{
"task_id": 744, "type": "voiceover", "status": "completed", "progress": 100,
"result_url": "https://cdn.reelora.cc/audio/.../744_a3f.mp3",
"result_url_expires_at": "2026-06-21T23:03:19",
"result_urls": null, "error_message": null,
"created_at": "2026-06-19T23:03:17", "updated_at": "2026-06-19T23:03:19"
}
Async Flow
Task Statuses
Webhooks
Specify a webhook_url — you will receive a POST request when the task is finished.
// POST to your webhook_url
{ "task_id": 744, "status": "completed", "result_url": "https://cdn.reelora.cc/..." }
Langues
Les champs language (voix off/TTS), source_lang et target_lang (doublage) acceptent un code ISO court ("fa") ou un locale complet ("fa-IR"). Pour la transcription/traduction, Whisper + le LLM comprennent ~99 langues — voici celles avec une voix TTS dédiée.
31 langues avec voix TTS :
| code | langue | locale | moteurs TTS |
|---|---|---|---|
| uk | Ukrainian | uk-UA | Edge, Gemini, 11Labs, Google |
| en | English | en-US | Edge, Gemini, 11Labs, Google |
| ru | Russian | ru-RU | Edge, Gemini, 11Labs, Google |
| es | Spanish | es-ES | Edge, Gemini, 11Labs, Google |
| de | German | de-DE | Edge, Gemini, 11Labs, Google |
| fr | French | fr-FR | Edge, Gemini, 11Labs, Google |
| pl | Polish | pl-PL | Edge, Gemini, 11Labs, Google |
| it | Italian | it-IT | Edge, Gemini, 11Labs, Google |
| pt | Portuguese | pt-BR | Edge, Gemini, 11Labs, Google |
| zh | Chinese | zh-CN | Edge, Gemini, 11Labs, Google |
| ja | Japanese | ja-JP | Edge, Gemini, 11Labs, Google |
| ar | Arabic (RTL) | ar-SA | Edge, Gemini, 11Labs, Google |
| fa | Persian (RTL) | fa-IR | Edge uniquement |
| he | Hebrew (RTL) | he-IL | Edge, Google |
| ur | Urdu (RTL) | ur-PK | Edge uniquement |
| tr | Turkish | tr-TR | Edge, Gemini, 11Labs, Google |
| hi | Hindi | hi-IN | Edge, Gemini, 11Labs, Google |
| bn | Bengali | bn-BD | Edge, Gemini, Google |
| id | Indonesian | id-ID | Edge, Gemini, 11Labs, Google |
| ms | Malay | ms-MY | Edge, 11Labs, Google |
| vi | Vietnamese | vi-VN | Edge, Gemini, Google |
| th | Thai | th-TH | Edge, Gemini, Google |
| ko | Korean | ko-KR | Edge, Gemini, 11Labs, Google |
| nl | Dutch | nl-NL | Edge, Gemini, 11Labs, Google |
| ro | Romanian | ro-RO | Edge, Gemini, 11Labs, Google |
| el | Greek | el-GR | Edge, 11Labs, Google |
| cs | Czech | cs-CZ | Edge, 11Labs, Google |
| sv | Swedish | sv-SE | Edge, 11Labs, Google |
| az | Azerbaijani | az-AZ | Edge uniquement |
| kk | Kazakh | kk-KZ | Edge uniquement |
| uz | Uzbek | uz-UZ | Edge uniquement |
TTS Providers
| Provider | Value | Quality | Limit |
|---|---|---|---|
| Google (Standard/Wavenet/Chirp) | "google" | Good | 1M chars/month |
| Gemini 2.5 / 3.1 TTS | "gemini" | Excellent | plan limit |
| Azure Neural | "azure" | Good | plan limit |
| Edge TTS (Microsoft) | "edge" | Good | unlimited |
| HuggingFace | "hf" | Basic | plan limit |
| ElevenLabs | "elevenlabs" | Premium | Pro and Pro+ |
Voices
Google ("google")
Locale is taken from account settings. Change it via: Settings → 🌍 Language.
| tts_voice | Description |
|---|---|
| Standard-A | Female, basic quality |
| Standard-B | Male, basic quality |
| Wavenet-A | Female, neural quality |
| Wavenet-B | Male, neural quality |
| Journey-F | Female, EN only, natural |
| Chirp3-HD-Aoede | Female, multilingual, HD |
| Chirp3-HD-Puck | Male, multilingual, HD |
Gemini 2.5 / 3.1 TTS ("gemini")
Supports tts_scene and tts_style for speech styling. Add -3.1 for the 3.1 version variant (e.g. Puck-3.1).
| tts_voice | Character |
|---|---|
| Zephyr | Bright 🌤 |
| Puck | Upbeat 🎉 |
| Charon | Informative 📚 |
| Kore | Firm 💪 |
| Fenrir | Excitable ⚡ |
| Leda | Youthful 🌱 |
| Aoede | Breezy 🍃 |
| Callirrhoe | Easy-going 😌 |
| Sadachbia | Lively 🎵 |
| Sulafat | Warm 🔥 |
| Achird | Friendly 🤝 |
| Enceladus | Breathy 🌬 |
| Gacrux | Mature 🍷 |
Edge TTS ("edge") — unlimited
| tts_voice | Language |
|---|---|
| uk-UA-OstapNeural | Ukrainian, male |
| uk-UA-PolinaNeural | Ukrainian, female |
| en-US-GuyNeural | English US, male |
| en-US-JennyNeural | English US, female |
| en-GB-RyanNeural | English GB, male |
| de-DE-ConradNeural | German, male |
| fr-FR-HenriNeural | French, male |
| es-ES-AlvaroNeural | Spanish, male |
| pl-PL-MarekNeural | Polish, male |
| it-IT-DiegoNeural | Italian, male |
| tr-TR-AhmetNeural | Turkish, male |
| cs-CZ-AntoninNeural | Czech, male |
| ru-RU-DmitryNeural | Russian, male |
ElevenLabs ("elevenlabs") — Pro and Pro+
| tts_voice (ID) | Name |
|---|---|
| pNInz6obpgDQGcFmaJgB | Adam (male, multilingual) |
| 21m00Tcm4TlvDq8ikWAM | Rachel (female, multilingual) |
| AZnzlk1XvdvUeBnXmlld | Domi (female, multilingual) |
Background Music
Pass the exact file name in the bgm_track field. Alternatively, upload your own MP3 via /v1/uploads and pass bgm_file.
| bgm_track (file name) | Style |
|---|---|
| chill_background-lofi-vibes-113884.mp3 | Lofi chill |
| chill_background-the-weekend-117427.mp3 | Lofi weekend |
| bodleasons-lofi-chill-smooth-chill-lofi-for-vlogs-and-background-music-159456.mp3 | Lofi smooth |
| alexgrohl-phonk-505963.mp3 | Phonk |
| white_records-neon-drift-phonk-house-background-music-for-video-27-second-496492.mp3 | Phonk house (27s) |
| white_records-toxic-drift-slap-house-background-music-for-video-stories-37-second-503887.mp3 | Slap house (37s) |
| diamond_tunes-majestic-tides-60sec-286729.mp3 | Cinematic majestic (60s) |
| raspberrymusic-relic-of-honor-cinematic-video-game-epic-478243.mp3 | Cinematic epic |
| raspberrymusic-be-the-change-epic-documentary-corporate-394293.mp3 | Documentary |
| raspberrymusic-triumph-adventure-news-cinematic-394333.mp3 | News cinematic |
| Under_the_Clock.mp3 | Dramatic |
| The_Approaching_Hour.mp3 | Dramatic ambient |
bgm_volume: 0.1 (quiet background) → 1.0 (full volume). Default is 0.2.
Subtitle Styles
| sub_style | Description |
|---|---|
| yellow_basic | MrBeast style — bold yellow words |
| purple_green | Neon — purple + green highlight |
| minimal_white | Minimal white, clean |
| news_style | News rolling ticker line style |
| fire_orange | Fiery orange highlight |
| pop_green | Bright green |
| word_box_orange | Orange bounding box around word |
| karaoke_cyan | Karaoke cyan |
| cursor_selection | Cursor selection style |
| single_green_box | Green bounding box on a single word |
| business_news | Business news style |
| dynamic_colors | Dynamic colors |
Video Formats
| format | Aspect Ratio | Platforms |
|---|---|---|
| 9_16 | 9:16 (vertical) | TikTok, Instagram Reels, YouTube Shorts |
| 16_9 | 16:9 (horizontal) | YouTube, Desktop |
| 1_1 | 1:1 (square) | Instagram Feed, Facebook |
| original | original | Keep source dimensions |
Plan Requirements
| Feature | Free | Standard | Pro | Pro+ |
|---|---|---|---|---|
| video | ✅ | ✅ | ✅ | ✅ |
| transcription | ✅ | ✅ | ✅ | ✅ |
| audio (TTS) | ✅ | ✅ | ✅ | ✅ |
| subtitles | ✅ | ✅ | ✅ | ✅ |
| pause_removal | ✅ | ✅ | ✅ | ✅ |
| dubbing | ✅ | ✅ | ✅ | ✅ |
| ElevenLabs voices | ❌ | ❌ | ✅ | ✅ |
| API access | ✅ | ✅ | ✅ | ✅ |
Error Codes
| HTTP | Reason |
|---|---|
| 401 | Missing or invalid X-API-Key |
| 403 | Feature unavailable on the current plan |
| 404 | Task or file not found (upload_id might have expired after 2h) |
| 413 | File exceeds 500 MB |
| 415 | Unsupported file type |
| 429 | Monthly limit exceeded or 30 requests/min rate limit hit |
| 500 | Internal server error |
{ "detail": "Monthly video render limit exceeded" }
Example: Python — full video pipeline
import httpx, time
API_KEY = "reel_xxxxxxxx_..."
BASE = "https://api.reelora.cc"
H = {"X-API-Key": API_KEY}
def poll(task_id):
while True:
r = httpx.get(f"{BASE}/v1/tasks/{task_id}", headers=H).json()
print(f" status={r['status']} progress={r.get('progress')}%")
if r["status"] == "completed": return r["result_url"]
if r["status"] == "failed": raise RuntimeError(r["error_message"])
time.sleep(3)
with open("photo.jpg", "rb") as f:
upload = httpx.post(f"{BASE}/v1/uploads", headers=H, files={"file": f}).json()
task = httpx.post(f"{BASE}/v1/tasks", headers=H, json={
"type": "video",
"photos": [upload["upload_id"]],
"text": "Breaking news from our channel.",
"format": "9_16",
"tts_provider": "google",
"tts_voice": "Chirp3-HD-Aoede",
"subtitles": True,
"sub_style": "news_style",
"bgm_track": "raspberrymusic-triumph-adventure-news-cinematic-394333.mp3",
"bgm_volume": 0.15,
}).json()
print("Download:", poll(task["task_id"]))
Example: Python — semi_auto dubbing
# Step 1: transcription
with open("video.mp4", "rb") as f:
vid = httpx.post(f"{BASE}/v1/uploads", headers=H, files={"file": f}).json()
t1 = httpx.post(f"{BASE}/v1/tasks", headers=H, json={
"type": "dubbing", "mode": "semi_auto", "step": "transcribe",
"file": vid["upload_id"], "source_lang": "uk", "target_lang": "en",
}).json()
srt_url = poll(t1["task_id"])
# download srt_url → edit → save as edited.srt
# Step 2: render with edited SRT
with open("edited.srt", "rb") as f:
srt = httpx.post(f"{BASE}/v1/uploads", headers=H, files={"file": f}).json()
t2 = httpx.post(f"{BASE}/v1/tasks", headers=H, json={
"type": "dubbing", "mode": "semi_auto", "step": "render",
"file": vid["upload_id"], "srt_file": srt["upload_id"],
"target_lang": "en", "tts_provider": "edge",
"tts_voice": "en-US-GuyNeural",
"mix_mode": "overlay", "overlay_volume": 20,
}).json()
print("Dubbed video:", poll(t2["task_id"]))
Example: JavaScript / Node.js
const API_KEY = "reel_xxxxxxxx_...";
const BASE = "https://api.reelora.cc";
const H = { "X-API-Key": API_KEY, "Content-Type": "application/json" };
async function poll(taskId) {
while (true) {
await new Promise(r => setTimeout(r, 3000));
const d = await fetch(`${BASE}/v1/tasks/${taskId}`, { headers: H }).then(r => r.json());
if (d.status === "completed") return d.result_url;
if (d.status === "failed") throw new Error(d.error_message);
}
}
const { task_id } = await fetch(`${BASE}/v1/tasks`, {
method: "POST", headers: H,
body: JSON.stringify({ type: "audio", text: "Hello from JS!", tts_provider: "google", tts_voice: "Chirp3-HD-Puck" }),
}).then(r => r.json());
console.log("MP3:", await poll(task_id));
Example: curl — transcription
# Upload file
UPLOAD=$(curl -s -X POST https://api.reelora.cc/v1/uploads \
-H "X-API-Key: reel_..." -F "[email protected]" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['upload_id'])")
# Transcription task
TASK=$(curl -s -X POST https://api.reelora.cc/v1/tasks \
-H "X-API-Key: reel_..." -H "Content-Type: application/json" \
-d "{\"type\":\"transcription\",\"file\":\"$UPLOAD\",\"language\":\"uk\",\"output_format\":\"both\"}" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['task_id'])")
# Polling
while true; do
RESP=$(curl -s https://api.reelora.cc/v1/tasks/$TASK -H "X-API-Key: reel_...")
STATUS=$(echo $RESP | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
echo "Status: $STATUS"
[ "$STATUS" = "completed" ] && echo $RESP | python3 -m json.tool && break
[ "$STATUS" = "failed" ] && echo "Failed!" && break
sleep 3
done