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 | Текст озвучки. Без текста — видео без звука. Вставь маркеры сцен между абзацами, чтобы менять кадр (и при желании выбрать переход): {scene} · {scene:slide} · {scene:zoom:0.8} · {scene:0.8} |
| scene_durations | optional | null | Явные длительности кадров в секундах, напр. [10, 15, 5]. Длина = числу media. Перекрывает авто-тайминг {scene}, работает даже без озвучки |
| scene_transitions | optional | null | Явный переход на каждом стыке (длина = photos − 1), напр. ["slide","zoom"]. Альтернатива маркерам {scene:type} |
| target_duration | optional | null | Целевая длина ролика в секундах. Если результат длиннее — его ускоряют (видео+звук+субтитры синхронно), чтобы уложиться. Короче — не трогают. Ускорение ограничено ×2. Должно быть ≤ лимита тарифа |
| format | optional | "9_16" | "9_16" · "16_9" · "1_1" · "original" |
| animation | optional | "none" | "none" · "ken_burns" |
| transition | optional | "crossfade" | Глобальный переход для немаркированных стыков: none · random · fade · dissolve · slide · cover · reveal · zoom · squeeze · wind · pixel · circle (crossfade = алиас dissolve). Действует только когда animation ≠ none |
| transition_duration | optional | 0.5 | Длительность перехода в секундах. Отдельную длительность на стык можно задать через {scene:type:сек} |
| 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 | — | Язык озвучки — любой код из раздела Языки ("ar", "fa"…) или полная локаль "ru-RU". Для редких языков — 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 | Статичные надписи поверх кадра, независимо от озвучки (см. «Текст на видео» ниже) |
| text_overlays_raw | optional | null | То же компактной строкой-кодами, парсится на сервере (см. ниже). Используется только если нет text_overlays |
| auto_text | optional | false | ⚡ Авто-текст. LLM выбирает самые сильные слова озвучки и добавляет их как анимированные надписи, синхронно с таймкодами слов TTS (см. «Авто-текст» ниже). Требует text. Считается из месячной квоты авто-текста |
| 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 |
🎬 Динамические сцены — когда менять кадр
- С озвучкой: вставь маркеры {scene} в text между абзацами. Каждый сегмент таймится по озвучке и мапится на media по порядку. Маркеры убираются перед TTS — голос их не читает.
- Без озвучки / явно: передай scene_durations (напр. [10, 15, 5]) — по одному значению на media. Видео-клипы обрезаются/зацикливаются под сцену, фото показываются заданное время.
- Сцены ↔ media: поровну → 1:1; меньше сцен → последняя делится на остальные; больше → последнее media держит остаток.
✨ Переходы между кадрами — как менять кадр
- В тексте: расширь маркер типом и/или длительностью: {scene:slide}, {scene:zoom:0.8}, {scene:0.8} (только длительность). Переход применяется к стыку в эту сцену.
- Явный массив: scene_transitions (длина = photos − 1), напр. ["slide","zoom","fade"] — по одному переходу на стык. Удобно для видео без текста с явными длительностями.
- Типы: fade · dissolve · slide · cover · reveal · zoom · squeeze · wind · pixel · circle · random. Направленные (slide/cover/reveal/wind) выбирают случайное направление на каждом стыке.
🅰️ Текст на видео — статичные надписи
Добавь произвольные надписи/титры поверх видео, независимо от субтитров. Работает с озвучкой или без. У каждой надписи свой стиль, позиция, тайминг и плавное появление/исчезновение. Два способа передать:
Структурировано — text_overlays (массив, макс. 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 }
]
| Поле | ||
|---|---|---|
| text | required | обязательное, макс. 200 символов |
| start | optional | сек. null → с 0 |
| end | optional | сек. null → до конца видео |
| style | optional | стиль титра (ниже) |
| size | optional | small · medium · large |
| position | optional | 9-сетка: top_left · top_center · top_right · middle_left · center · middle_right · bottom_left · bottom_center · bottom_right |
| bold / italic | optional | перекрывает вес/наклон стиля |
| color | optional | ASS hex &HAABBGGRR, напр. "&H00B469FF" (розовый) |
| fade | optional | плавное появление/исчезновение (300 мс) |
| anim | optional | Анимация появления: pop · slide_left · slide_right · type (печатная машинка). Приоритетнее fade |
Стили титров (style): clean_white · bold_yellow · outline_black · soft_pink · elegant_script · news_bar · impact_red.
Коды — text_overlays_raw (строка). Универсальный англоязычный синтаксис (одинаков в любом языке интерфейса), парсится на сервере. Одна надпись на строку (или через /); поля внутри надписи — через |:
TEXT | attributes | start-end
"text_overlays_raw": "Hello | large italic center | 0-3 / Subscribe | bottom pink pop | 3-end"
- размер — small · medium · large
- вес/наклон — bold · thin · italic
- вертикаль — top · middle · bottom; горизонталь — left · center · right
- цвет — white · yellow · red · green · blue · pink · orange · purple · black · cyan
- время — 0-3, 2.5-8, 5-end (сек, точка/запятая). Без времени → надпись видна весь ролик
- анимация — pop · slide · type (печатная машинка) · fade · none
⚡ Авто-текст — автоматические надписи ключевых слов
auto_text: true включает ⚡ Авто-текст. Вместо ручной расстановки надписей LLM читает распознанные слова озвучки, сам выбирает самые сильные (имена, числа, громкие утверждения) и рендерит их как анимированные надписи, точно по таймкодам слов TTS. Выбирает современный стиль, цвет и анимацию появления (pop / slide / typewriter) для каждого слова, складывает звучащие вместе слова в стек и не лезет в зону субтитров.
- Нужна озвучка (text не пустой). Без озвучки таймкодов слов нет — auto_text игнорируется.
- Дополнительно: сгенерированные надписи добавляются к твоим text_overlays / text_overlays_raw, а не заменяют их.
- Полностью автоматически: параметров на слово нет. Если LLM ничего не подобрал — рендер просто идёт без доп. надписей (запрос не падает).
- Квота: каждый успешный рендер с авто-текстом списывает единицу месячной квоты (auto_text_limit; на Free — ограничено, на платных — безлимит). Превышение → 429.
- Авто-текст работает во всех таск-типах API: video, dubbing и subtitles. Перевод по API делается через subtitles с translate_to (отдельного типа translation нет), поэтому auto_text охватывает и переведённые субтитры.
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.
| Поле | ||
|---|---|---|
| translate_to | optional | ISO-код целевого языка. Задано → субтитры переводятся на него (тайминг сохраняется, звук остаётся оригинальным). Пропущено → на языке оригинала |
| auto_text | optional | ⚡ Авто-текст — надписи ключевых слов из таймингов (переведённых) субтитров. Считается из квоты авто-текста |
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" или любой код из раздела Языки ("ar", "fa", "tr"…). Whisper авто-определяет при "auto" |
| target_lang | required | — | Язык дубляжа — любой код из раздела Языки. Если провайдер его не озвучивает — авто-фолбек на 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 | ⚡ Авто-текст поверх дублированной речи — анимированные надписи ключевых слов, выбранные LLM. Считается из квоты авто-текста |
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/..." }
Языки
Поля language (озвучка/TTS), source_lang и target_lang (дубляж) принимают короткий ISO-код ("fa") или полную локаль ("fa-IR"). Для транскрипции/перевода Whisper + LLM понимают ~99 языков — ниже те, что имеют готовый TTS-голос.
31 язык с TTS-голосами:
| код | язык | локаль | 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 |
| he | Hebrew (RTL) | he-IL | Edge, Google |
| ur | Urdu (RTL) | ur-PK | только 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 | только Edge |
| kk | Kazakh | kk-KZ | только Edge |
| uz | Uzbek | uz-UZ | только 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