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 | Voiceover-Text. Ohne Text — Video ohne Ton. Füge Szenenmarker zwischen Absätzen ein, um den Schnitt zu wechseln (und optional den Übergang zu wählen): {scene} · {scene:slide} · {scene:zoom:0.8} · {scene:0.8} |
| scene_durations | optional | null | Explizite Dauer pro Medium in Sekunden, z. B. [10, 15, 5]. Länge = Medienanzahl. Überschreibt das {scene}-Auto-Timing, funktioniert auch ohne Stimme |
| scene_transitions | optional | null | Expliziter Übergang pro Schnitt (Länge = photos − 1), z. B. ["slide","zoom"]. Alternative zu {scene:type}-Markern |
| target_duration | optional | null | Ziel-Cliplänge in Sekunden. Ist das Ergebnis länger, wird es beschleunigt (Video+Audio+Untertitel synchron), um zu passen. Kürzeres bleibt unangetastet. Beschleunigung max. ×2. Muss ≤ Tariflimit sein |
| format | optional | "9_16" | "9_16" · "16_9" · "1_1" · "original" |
| animation | optional | "none" | "none" · "ken_burns" |
| transition | optional | "crossfade" | Globaler Übergang für unmarkierte Schnitte: none · random · fade · dissolve · slide · cover · reveal · zoom · squeeze · wind · pixel · circle (crossfade = Alias von dissolve). Wirkt nur wenn animation ≠ none |
| transition_duration | optional | 0.5 | Übergangslänge in Sekunden. Pro-Schnitt-Länge via {scene:type:sek} |
| 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 | — | Voiceover-Sprache — beliebiger Code aus dem Abschnitt Sprachen ("ar", "fa"…) oder volles Locale "ru-RU". Für seltene Sprachen — 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 | Statische Beschriftungen über dem Bild, unabhängig vom Voice-over (siehe „Text im Video“ unten) |
| text_overlays_raw | optional | null | Dasselbe als kompakter „Codes“-String, serverseitig geparst (siehe unten). Nur genutzt, wenn text_overlays fehlt |
| auto_text | optional | false | ⚡ Auto-Text. Ein LLM wählt die stärksten Schlüsselwörter des Voice-overs und fügt sie als animierte Einblendungen hinzu, synchron zu den TTS-Wort-Timestamps (siehe „Auto-Text“ unten). Erfordert text. Zählt gegen dein monatliches Auto-Text-Kontingent |
| 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 |
🎬 Dynamische Szenen — wann der Schnitt wechselt
- Mit Stimme: füge {scene}-Marker in text zwischen Absätzen ein. Jedes Segment wird durch die Erzählung getaktet und der Reihe nach den Medien zugeordnet. Marker werden vor TTS entfernt — die Stimme liest sie nie.
- Ohne Stimme / explizit: übergib scene_durations (z. B. [10, 15, 5]) — ein Wert pro Medium. Clips werden zugeschnitten/geloopt, Fotos für die Szenenlänge gezeigt.
- Szenen ↔ Medien: gleich → 1:1; weniger Szenen → die letzte teilt sich auf den Rest; mehr → das letzte Medium hält den Rest.
✨ Übergänge pro Schnitt — wie der Schnitt wechselt
- Im Text: erweitere einen Marker um Typ und/oder Dauer: {scene:slide}, {scene:zoom:0.8}, {scene:0.8} (nur Dauer). Der Übergang gilt für den Schnitt in diese Szene.
- Explizites Array: scene_transitions (Länge = photos − 1), z. B. ["slide","zoom","fade"] — ein Übergang pro Schnitt. Praktisch für stumme Videos mit expliziten Dauern.
- Typen: fade · dissolve · slide · cover · reveal · zoom · squeeze · wind · pixel · circle · random. Gerichtete (slide/cover/reveal/wind) wählen pro Schnitt eine zufällige Richtung.
🅰️ Text im Video — statische Einblendungen
Füge beliebige Beschriftungen/Titel über dem Video hinzu, unabhängig von den Untertiteln. Mit oder ohne Sprecher. Jede Einblendung hat eigenen Stil, Position, Timing und Ein-/Ausblendung. Zwei Wege:
Strukturiert — text_overlays (Array, 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 }
]
| Feld | ||
|---|---|---|
| text | required | erforderlich, max. 200 Zeichen |
| start | optional | Sek. null → ab 0 |
| end | optional | Sek. null → bis Videoende |
| style | optional | Titelstil (unten) |
| size | optional | small · medium · large |
| position | optional | 9er-Raster: top_left · top_center · top_right · middle_left · center · middle_right · bottom_left · bottom_center · bottom_right |
| bold / italic | optional | überschreibt Gewicht/Kursiv des Stils |
| color | optional | ASS hex &HAABBGGRR, z. B. "&H00B469FF" (rosa) |
| fade | optional | sanftes Ein-/Ausblenden (300 ms) |
| anim | optional | Erscheinungs-Animation: pop · slide_left · slide_right · type (Schreibmaschine). Hat Vorrang vor fade |
Titelstile (style): clean_white · bold_yellow · outline_black · soft_pink · elegant_script · news_bar · impact_red.
Codes — text_overlays_raw (String). Universelle englische Syntax (in jeder UI-Sprache gleich), serverseitig geparst. Eine Einblendung pro Zeile (oder durch /); Felder innerhalb durch |:
TEXT | attributes | start-end
"text_overlays_raw": "Hello | large italic center | 0-3 / Subscribe | bottom pink pop | 3-end"
- Größe — small · medium · large
- Gewicht/Kursiv — bold · thin · italic
- vertikal — top · middle · bottom; horizontal — left · center · right
- Farbe — white · yellow · red · green · blue · pink · orange · purple · black · cyan
- Zeit — 0-3, 2.5-8, 5-end (Sek., Punkt/Komma). Ohne Zeit → Einblendung im ganzen Clip
- Animation — pop · slide · type (Schreibmaschine) · fade · none
⚡ Auto-Text — automatische Schlüsselwort-Einblendungen
auto_text: true aktiviert ⚡ Auto-Text. Statt Einblendungen selbst zu platzieren, liest ein LLM die erkannten Wörter des Voice-overs, wählt die stärksten (Namen, Zahlen, prägnante Aussagen) und rendert sie als animierte Einblendungen, exakt auf den TTS-Wort-Timestamps. Es wählt pro Wort einen modernen Stil, Farbe und Erscheinungs-Animation (pop / slide / typewriter), stapelt zusammen gesprochene Wörter und hält sich aus der Untertitelzone.
- Erfordert ein Voice-over (text nicht leer). Ohne Sprecher gibt es keine Wort-Timestamps, daher wird auto_text ignoriert.
- Additiv: erzeugte Einblendungen werden an deine text_overlays / text_overlays_raw angehängt, sie ersetzen sie nicht.
- Voll automatisch: keine Parameter pro Wort. Findet das LLM nichts, läuft das Rendering einfach ohne Zusatz-Einblendungen weiter (der Request schlägt nie fehl).
- Kontingent: jedes erfolgreiche Auto-Text-Rendering verbraucht eine Einheit deines Monatskontingents (auto_text_limit; Free begrenzt, Bezahlpläne unbegrenzt). Über dem Limit → 429.
- Auto-Text funktioniert in allen API-Task-Typen: video, dubbing und subtitles. Übersetzung per API läuft über subtitles mit translate_to (kein eigener translation-Typ), daher deckt auto_text auch übersetzte Untertitel ab.
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.
| Feld | ||
|---|---|---|
| translate_to | optional | ISO-Code einer Zielsprache. Gesetzt → Untertitel werden dorthin übersetzt (Timing bleibt, Ton bleibt original). Weggelassen → in der Originalsprache |
| auto_text | optional | ⚡ Auto-Text — Schlüsselwort-Einblendungen aus den Zeiten der (übersetzten) Untertitel. Zählt gegen dein Auto-Text-Kontingent |
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" oder beliebiger Code aus dem Abschnitt Sprachen ("ar", "fa", "tr"…). Whisper erkennt automatisch bei "auto" |
| target_lang | required | — | Synchronisationssprache — beliebiger Code aus dem Abschnitt Sprachen. Kann der Anbieter sie nicht sprechen — Auto-Fallback auf 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-Text über der synchronisierten Sprache — vom LLM gewählte animierte Schlüsselwort-Einblendungen. Zählt gegen dein Auto-Text-Kontingent |
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/..." }
Sprachen
Die Felder language (Voiceover/TTS), source_lang und target_lang (Synchronisation) akzeptieren einen kurzen ISO-Code ("fa") oder ein volles Locale ("fa-IR"). Für Transkription/Übersetzung verstehen Whisper + LLM ~99 Sprachen — unten die mit kuratierter TTS-Stimme.
31 Sprachen mit TTS-Stimmen:
| Code | Sprache | Locale | TTS-Engines |
|---|---|---|---|
| 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 | nur Edge |
| he | Hebrew (RTL) | he-IL | Edge, Google |
| ur | Urdu (RTL) | ur-PK | nur Edge |
| 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 | nur Edge |
| kk | Kazakh | kk-KZ | nur Edge |
| uz | Uzbek | uz-UZ | nur Edge |
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