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 "file=@photo.jpg"
# {"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. Without text — silent video. Insert scene markers between paragraphs to switch the shot (and optionally pick the transition): {scene} · {scene:slide} · {scene:zoom:0.8} · {scene:0.8} |
| scene_durations | optional | null | Explicit per-media durations in seconds, e.g. [10, 15, 5]. Length must equal media count. Overrides {scene} auto-timing, works even without voice |
| scene_transitions | optional | null | Explicit transition per cut (length = photos − 1), e.g. ["slide","zoom"]. Alternative to {scene:type} markers |
| target_duration | optional | null | Target clip length in seconds. If the result is longer it is sped up (video+audio+subtitles in sync) to fit. Shorter is left untouched. Speed-up capped at ×2. Must be ≤ your plan limit |
| format | optional | "9_16" | "9_16" · "16_9" · "1_1" · "original" |
| animation | optional | "none" | "none" · "ken_burns" |
| transition | optional | "crossfade" | Global transition for unmarked cuts: none · random · fade · dissolve · slide · cover · reveal · zoom · squeeze · wind · pixel · circle (crossfade = alias of dissolve). Applies only when animation ≠ none |
| transition_duration | optional | 0.5 | Transition length in seconds. Per-cut length can be set 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 | — | Voiceover language — any code from the Languages section ("ar", "fa"…) or a full locale "ru-RU". For the long tail use 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 | Static captions burned over the frame, independent of the voice-over (see Text on video below) |
| text_overlays_raw | optional | null | The same feature as a compact “codes” string, parsed on the server (see below). Used only if text_overlays is absent |
| auto_text | optional | false | ⚡ Auto-text. An LLM picks the strongest keywords from the voice-over and adds them as animated on-screen captions, timed to the TTS word timestamps (see Auto-text below). Requires text. Counts against your monthly auto-text quota |
| 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 |
🎬 Dynamic scenes — when the shot changes
- With voice: insert {scene} markers in text between paragraphs. Each segment is timed by the narration and mapped to media in order. Markers are stripped before TTS — the voice never reads them.
- Without voice / explicit: pass scene_durations (e.g. [10, 15, 5]) — one value per media. Video clips are trimmed/looped to fit, photos are shown for the scene length.
- Scenes ↔ media: equal → 1:1; fewer scenes → the last splits across the rest; more → the last media holds the leftover.
✨ Per-cut transitions — how the shot changes
- In text: extend a marker with a type and/or duration: {scene:slide}, {scene:zoom:0.8}, {scene:0.8} (duration only). The transition applies to the cut into that scene.
- Explicit array: scene_transitions (length = photos − 1), e.g. ["slide","zoom","fade"] — one transition per cut. Handy for silent videos with explicit durations.
- Types: fade · dissolve · slide · cover · reveal · zoom · squeeze · wind · pixel · circle · random. Directional ones (slide/cover/reveal/wind) pick a random direction per cut.
🅰️ Text on video — static captions
Add arbitrary captions/titles on top of the video, independent of the subtitles. Works with or without narration. Each caption has its own style, position, timing and fade in/out. Two ways to pass them:
Structured — 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 }
]
| Field | ||
|---|---|---|
| text | required | required, max 200 chars |
| start | optional | sec. null → from 0 |
| end | optional | sec. null → until end of video |
| style | optional | title style (below) |
| size | optional | small · medium · large |
| position | optional | 9-grid: top_left · top_center · top_right · middle_left · center · middle_right · bottom_left · bottom_center · bottom_right |
| bold / italic | optional | overrides the style weight/slant |
| color | optional | ASS hex &HAABBGGRR, e.g. "&H00B469FF" (pink) |
| fade | optional | smooth fade in/out (300 ms) |
| anim | optional | Appearance animation: pop · slide_left · slide_right · type (typewriter). Overrides fade |
Title styles (style): clean_white · bold_yellow · outline_black · soft_pink · elegant_script · news_bar · impact_red.
Codes — text_overlays_raw (string). A universal English syntax (same in every UI language), parsed on the server. One caption per line (or separated by /); fields inside a caption separated by |:
TEXT | attributes | start-end
"text_overlays_raw": "Hello | large italic center | 0-3 / Subscribe | bottom pink pop | 3-end"
- size — small · medium · large
- weight/slant — bold · thin · italic
- vertical — top · middle · bottom; horizontal — left · center · right
- color — white · yellow · red · green · blue · pink · orange · purple · black · cyan
- time — 0-3, 2.5-8, 5-end (sec, dot/comma). No time → caption shows the whole clip
- animation — pop · slide · type (typewriter) · fade · none
⚡ Auto-text — automatic keyword captions
auto_text: true turns on ⚡ Auto-text. Instead of positioning captions yourself, an LLM reads the recognized words of the voice-over, picks the strongest ones (names, numbers, punchy claims) and renders them as animated captions, exactly on the TTS word timestamps. It chooses a modern style, color and appearance animation (pop / slide / typewriter) per word, stacks words spoken together and keeps out of the subtitle zone.
- Requires a voice-over (text non-empty). With no narration there are no word timestamps, so auto_text is ignored.
- Additive: generated captions are appended to your text_overlays / text_overlays_raw, they don't replace them.
- Fully automatic: there are no per-word parameters. If the LLM matches nothing, the render simply proceeds without the extra captions (never fails the request).
- Quota: each successful auto-text render consumes one unit of your monthly allowance (auto_text_limit; free plans limited, paid plans unlimited). Over the limit → 429.
- Auto-text works across every API task type: video, dubbing and subtitles. Translation over the API is done through subtitles with translate_to (there is no separate translation type), so auto_text covers translated subtitles too.
🎬 AI-tables — animated cards over the video
ai_graphics: true turns on 🎬 AI-tables (smart scenes): animated cards drawn over the video — lists, numbers, quotes, comparisons, step lists, bar/percent charts, trend arrows, plus subscribe / like call-to-action cards. Cards avoid faces and your subtitle zone automatically, and are sized for vertical (Reels) playback. Available on video, subtitles (cards in the subtitle language) and dubbing (cards in the dubbing language).
- ai_graphics_mode: auto — an LLM picks the moments from the voice-over (needs narration); semi — auto plus your directives (directives win on overlap); manual — only your directives (works on a silent video).
- ai_graphics_density: 0.6 (rare) · 1.0 (normal) · 1.5 (dense).
- ai_graphics_directives (manual / semi): one card per line — MM:SS[-MM:SS] template args [@position]. Templates: caption, quote, subscribe, like, list, steps, stat, percent, trend, compare. Positions: @center @top @bottom @left @right.
- ai_graphics_sfx: a short sound as each card appears (see Sound effects). null = silent.
- Quota: each successful render consumes one unit of your monthly ai_graphics_limit. Over the limit → 429; plans without the feature → 403. Never fatal: if nothing is selected, the render proceeds without cards.
{
"type": "video", "photos": ["upload_abc"],
"text": "Three things to pack for Hawaii...",
"ai_graphics": true, "ai_graphics_mode": "auto",
"ai_graphics_density": 1.0, "ai_graphics_sfx": "whoosh"
}
// manual directives example
{
"ai_graphics": true, "ai_graphics_mode": "manual",
"ai_graphics_directives": "0:15 subscribe\n0:33-0:45 list What to take | Passport | Money | Tickets\nend like Hit like"
}
🔊 Sound effects
Short sound effects synced to on-screen events. Independent, optional channels — all off by default (null = silent). The value is the filename (without extension) of a sound in the server's SFX library; an unknown value is treated as null.
| Field | Applies to | Values | Fires on |
|---|---|---|---|
| sfx_auto_sound | video, dubbing, subtitles, smart_clip | "click" · "pop" · "whoosh" | Each ⚡ auto-text caption appearing (requires auto_text:true) |
| sfx_transition_sound | video | "whoosh" · "paper_flip" | Each scene change in a photo slideshow (2+ photos) |
| ai_graphics_sfx | video, dubbing, subtitles | "whoosh" · "paper_flip" | Each 🎬 AI-table card appearing (requires ai_graphics:true) |
Sounds are mixed below the voice-over / music, so they accent without masking speech. In the Telegram bot these live inside the ⚡ Auto-text screen, the 🎬 AI-tables screen and the 🎵 Background screen.
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.
| Field | ||
|---|---|---|
| translate_to | optional | ISO code of a target language. Set → subtitles are translated into it (timing preserved, audio stays original). Omit → subtitles in the original language |
| auto_text | optional | ⚡ Auto-text — keyword captions from the (translated) subtitle timings. Counts against your monthly auto-text quota |
| reels_mode | optional | true → convert the video to vertical 9:16 (for Reels/TikTok). false = original format |
| reels_reframe | optional | 9:16 reframe strategy (only when reels_mode:true): blur (default) · fill · fill_blur · zoom · crop · auto (auto face-crop) |
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" or any code from the Languages section ("ar", "fa", "tr"…). Whisper auto-detects when "auto" |
| target_lang | required | — | Dubbing language — any code from the Languages section. If the provider can't speak it, the bot auto-falls back to 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" |
| auto_text | optional | false | ⚡ Auto-text over the dubbed speech — LLM-picked animated keyword captions. Counts against your monthly auto-text quota |
| reels_mode | optional | false | true → convert the video to vertical 9:16 (for Reels/TikTok). false = original format |
| reels_reframe | optional | "blur" | 9:16 reframe strategy (only when reels_mode): blur · fill · fill_blur · zoom · crop · auto (auto face-crop) |
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.Type: smart_clip — smart clips
One long video (podcast, interview, vlog) → Whisper detects the language → an LLM picks the strongest self-contained moments → ffmpeg cuts several ready short clips. One call = several clips. Requires a plan with smart clips.
{
"type": "smart_clip", "file": "upload_id_or_https_url",
"max_clips": 6, "target_sec": 60, "language": "uk",
"context": "business podcast, look for tips and strong quotes",
"reels_mode": true, "subtitles": true, "sub_style": "yellow_basic",
"auto_text": true, "filters": ["cinema"],
"webhook_url": "https://mysite.com/hooks/reelora"
}
| Field | Default | Description | |
|---|---|---|---|
| file | required | — | upload_id or a direct https:// link to the long video |
| max_clips | optional | 0 | Max number of clips. 0 = auto (~1 per 5 min, within 4..10). A ceiling, not a plan |
| target_sec | optional | 60 | Target clip length (sec). Actual bounds snap to speech pauses |
| language | optional | null | Video language for Whisper (uk, en, ru…). null/"auto" = autodetect |
| context | optional | null | Context for the LLM: what the video is and what to look for. Noticeably boosts accuracy |
| reels_mode | optional | false | true → each clip vertical 9:16 (blurred bg). false = original format |
| reels_reframe | optional | "blur" | 9:16 reframe strategy (when reels_mode): blur · fill · fill_blur · zoom · crop · auto (auto face-crop) |
| subtitles | optional | true | Burn karaoke subtitles onto each clip |
| sub_style | optional | "yellow_basic" | Subtitle style (same presets) |
| sub_position | optional | "bottom" | top · center · bottom |
| sub_size | optional | "medium" | small · medium · large |
| sub_color | optional | null | HEX subtitle color, e.g. "#00FF00" |
| auto_text | optional | false | ⚡ Auto-text — dynamic captions on key words |
| filters | optional | [] | Color filters: vivid · contrast · ocean · forest · warm · cinema · bw · vintage |
Clips come back in result_urls.clips[]. result_url = the first clip (for compatibility). Clip fields: title, hook, start/end/duration, score (1–100).
{
"task_id": 12345, "status": "completed",
"result_urls": { "clips": [
{ "index": 1, "title": "...", "hook": "...",
"start": 132.4, "end": 197.8, "duration": 65.4,
"score": 92, "result_url": "https://cdn.../..._01_....mp4" }
] }
}
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/..." }
Languages
The language (voiceover/TTS), source_lang and target_lang (dubbing) fields accept a short ISO code ("fa") or a full locale ("fa-IR"). For transcription/translation Whisper + the LLM understand ~99 languages — below are the ones with a curated TTS voice.
31 languages with TTS voices:
| code | language | 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 | Edge only |
| he | Hebrew (RTL) | he-IL | Edge, Google |
| ur | Urdu (RTL) | ur-PK | Edge only |
| 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 only |
| kk | Kazakh | kk-KZ | Edge only |
| uz | Uzbek | uz-UZ | Edge only |
TTS Providers
| Provider | Value | Quality | Limit |
|---|---|---|---|
| Google (Standard/Wavenet/Chirp) | "google" | Good | 1M chars/month |
| Gemini 2.5 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 (free-text directive) and tts_style preset (standard/calm/expressive/energetic/dramatic/cheerful). Add -3.1 for the 3.1 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 |
| elegant_white | Elegant white — bold karaoke, ultra-transparent bar |
| dual_duet | Duet — two paired lines (yellow + white) |
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 "file=@podcast.mp3" \
| 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