Reelora API

API REST pour l'intégration par programme des sous-titres, voix off, transcription, doublage et suppression des pauses. Les mêmes capacités que le bot Telegram — via HTTP. Disponible à tous : le solde de jetons est partagé avec le bot.

Endpoints

MethodPathDescription
GET/healthService health check
GET/v1/meProfile, limits, usage
POST/v1/uploadsUpload file
POST/v1/tasksCreate task
GET/v1/tasksList of tasks
GET/v1/tasks/{id}Task status + result

Quick Start

1

Get API Key

In the bot @reelora_ai_bot send /apikey or open Settings → 🔑 API Access. The key is shown only once.

2

Upload File

POST /v1/uploads → get upload_id

3

Create Task

POST /v1/tasks with type and parameters

4

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
⚠️The key is shown only once. If lost — run /revokekey in the bot and generate a new one via /apikey.
ℹL'API est disponible à tous. Les tâches sont facturées en jetons au même tarif que dans le bot — le solde est partagé.

Base URL

https://api.reelora.cc

Interactive Swagger documentation: https://api.reelora.cc/docs

Status Check

GET/healthno auth required
curl https://api.reelora.cc/health
# {"status":"ok","service":"reelora-api"}

Profil et solde

GET/v1/me
curl https://api.reelora.cc/v1/me -H "X-API-Key: reel_..."
{
  "user_id": 618899534, "token_balance": 24000,
  "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

POST/v1/uploads

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}
TypeFormatsMax.
ImagesJPEG, PNG, WebP500 MB
VideoMP4, MOV, AVI500 MB
AudioMP3, WAV, M4A500 MB
SubtitlesSRT—

Use upload_id in the photos, file, srt_file, bgm_file fields. Alternatively, you can pass direct https:// URLs instead of uploading.

Task Creation

POST/v1/tasks202 Accepted

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
}
FieldDefaultDescription
photosrequired—upload_id or https:// (images or video clips, max. 30)
textoptionalnullTexte 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_durationsoptionalnullDuré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_transitionsoptionalnullTransition explicite par coupe (longueur = photos − 1), ex. ["slide","zoom"]. Alternative aux marqueurs {scene:type}
target_durationoptionalnullDuré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
formatoptional"9_16""9_16" · "16_9" · "1_1" · "original"
animationoptional"none""none" · "ken_burns"
transitionoptional"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_durationoptional0.5Durée de transition en secondes. Durée par coupe via {scene:type:sec}
tts_provideroptional"google"TTS provider (see Providers section)
tts_voiceoptionalfrom profileVoice name (see Voices section)
tts_speedoptional1.00.8 · 1.0 · 1.2 · 1.5
languageoptional—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_sceneoptionalnullSpeech style instruction (for Gemini TTS)
tts_styleoptionalnullVoice style preset: standard · calm · expressive · energetic · dramatic · cheerful (Gemini and ElevenLabs)
subtitlesoptionaltrueKaraoke subtitles
sub_styleoptional"yellow_basic"Subtitle style
sub_positionoptional"bottom""top" · "center" · "bottom"
sub_sizeoptional"medium""small" · "medium" · "large"
sub_coloroptionalnullASS color: "&H0000E6FF" (yellow)
text_overlaysoptionalnullLégendes statiques par-dessus l'image, indépendantes de la voix off (voir « Texte sur la vidéo » ci-dessous)
text_overlays_rawoptionalnullLa 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_textoptionalfalse⚡ 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_trackoptionalnullFile name from the music library (see BGM section)
bgm_fileoptionalnullupload_id of your own MP3 file (mutually exclusive with bgm_track)
bgm_volumeoptional0.2Music volume 0.0–1.0
audio_mix_typeoptional"replace"Mixing for video clips: "replace" · "add" · "overlay"

audio_mix_type — for clips with original sound

ValueBehavior
replaceTTS/BGM only — clip sound is removed
addTTS on top of original (both at full volume)
overlayTTS 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.
ℹ️Les transitions ne sont rendues que si animation ≠ none. Un none par coupe n’est pas supporté — il revient à la transition globale.

🅰️ 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
textrequiredobligatoire, max 200 caractères
startoptionals. null → à partir de 0
endoptionals. null → jusqu'à la fin de la vidéo
styleoptionalstyle de titre (ci-dessous)
sizeoptionalsmall · medium · large
positionoptionalgrille 9 : top_left · top_center · top_right · middle_left · center · middle_right · bottom_left · bottom_center · bottom_right
bold / italicoptionalremplace la graisse/l'italique du style
coloroptionalASS hex &HAABBGGRR, ex. "&H00B469FF" (rose)
fadeoptionalfondu d'entrée/sortie doux (300 ms)
animoptionalAnimation 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
📋Exemple : première légende — « Bonjour » en grand italique centré 0–3 s ; seconde — « Abonne-toi » en bas rose de la 3ᵉ seconde à la fin. Les attributs et le temps sont optionnels et indépendants de l'ordre. Les tokens inconnus sont ignorés (la requête n'échoue jamais).

⚡ 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).
  • Coût : chaque rendu auto-texte réussi coûte 50 jetons. Si le solde est insuffisant → 402.
  • 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.

🎬 Cartes IA — cartes animées sur la vidéo

ai_graphics: true active 🎬 Cartes IA (scènes intelligentes) : cartes animées sur la vidéo — listes, nombres, citations, comparaisons, étapes, graphiques barres/pourcentage, flèches de tendance, et cartes CTA subscribe / like. Les cartes évitent les visages et la zone des sous-titres automatiquement. Disponible pour video, subtitles et dubbing.

  • ai_graphics_mode: auto (LLM picks moments from the voice-over; needs narration) · semi (auto + your directives) · 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. Quota: ai_graphics_limit per month (over → 429; feature not on plan → 403). Never fatal.
{
  "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"
}

🔊 Effets sonores

Effets sonores courts synchronisés aux événements à l'écran. Canaux indépendants et facultatifs — désactivés par défaut (null = silence). La valeur est le nom de fichier (sans extension) d'un son de la bibliothèque SFX.

FieldApplies toValuesFires on
sfx_auto_soundvideo, dubbing, subtitles, smart_clip"click" · "pop" · "whoosh"Each ⚡ auto-text caption (requires auto_text:true)
sfx_transition_soundvideo"whoosh" · "paper_flip"Each scene change in a photo slideshow (2+ photos)
ai_graphics_sfxvideo, dubbing, subtitles"whoosh" · "paper_flip"Each 🎬 AI-table card (requires ai_graphics:true)

Les sons sont mixés sous la voix/musique. Dans le bot Telegram : ⚡ Auto-texte, 🎬 Cartes IA et 🎵 Fond.

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"
}
FieldDescription
filerequiredupload_id or https:// URL
languageoptional"uk" · "en" · "de" · "fr" etc. null = auto
ai_promptoptionalContext for Whisper (improves accuracy)
output_formatoptional"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"
}
FieldDefaultDescription
textrequired—Text to synthesize
tts_provideroptional"google"TTS provider (see Providers section)
tts_voiceoptionalfrom profileVoice name (see Voices section)
tts_speedoptional1.00.8 · 1.0 · 1.2 · 1.5
tts_sceneoptionalnullSpeech style instruction (for Gemini TTS)
tts_styleoptionalnullVoice style preset: standard · calm · expressive · energetic · dramatic · cheerful (Gemini and ElevenLabs)

Type: subtitles — subtitles on video

Grave les sous-titres karaoké dans une vidéo finie via Whisper + FFmpeg. 50 jetons par minute.

{
  "type": "subtitles", "file": "upload_id_or_https_url",
  "language": "uk", "sub_style": "yellow_basic",
  "sub_position": "bottom", "sub_size": "medium"
}

Résultat : fichier MP4 avec sous-titres dans result_url. Les jetons sont facturés selon la durée du résultat.

Champ
translate_tooptionalCode 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_textoptional⚡ Auto-texte — légendes de mots-clés à partir des temps des sous-titres (traduits). Décompté de votre quota d'auto-texte
reels_modeoptionaltrue → convertir la vidéo en vertical 9:16 (pour Reels/TikTok). false = format d’origine
reels_reframeoptionalStratégie de recadrage 9:16 (seulement si reels_mode:true) : blur (défaut) · fill · fill_blur · zoom · crop · auto (recadrage auto du visage)

Type: pause_removal — pause removal

Coupe automatiquement les silences et pauses de la vidéo. 50 jetons par minute. Le seuil de silence est détecté automatiquement.

{ "type": "pause_removal", "file": "upload_id_or_https_url" }

Result: processed MP4 in result_url.

Type: dubbing — AI dubbing

Transcrit la vidéo, traduit, synthétise une nouvelle voix, mixe l'audio. Trois modes. Disponible à tous : 100–141 jetons par minute, selon la voix.

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"
}
FieldDefaultDescription
filerequired—upload_id or URL of the video to dub
source_langoptional"auto""auto" ou n’importe quel code de la section Langues ("ar", "fa", "tr"…). Whisper détecte automatiquement avec "auto"
target_langrequired—Langue de doublage — n’importe quel code de la section Langues. Si le fournisseur ne la parle pas — repli auto sur Edge
tts_provideroptional"edge"TTS provider for the new voice
tts_voiceoptionalautoVoice for the target language
mix_modeoptional"overlay""overlay" (original is ducked) · "replace" (full replacement)
overlay_volumeoptional20Original volume % when mix_mode=overlay (0–100)
sub_langoptional"dubbed""dubbed" · "original" · "none" · or ISO language code
sub_styleoptional"yellow_basic"Subtitle style
sub_positionoptional"bottom""top" · "center" · "bottom"
tts_styleoptionalnullVoice style preset: standard · calm · expressive · energetic · dramatic · cheerful (Gemini and ElevenLabs)
auto_textoptionalfalse⚡ 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
reels_modeoptionalfalsetrue → convertir la vidéo en vertical 9:16 (pour Reels/TikTok). false = format d’origine
reels_reframeoptional"blur"Stratégie de recadrage 9:16 (si reels_mode) : blur · fill · fill_blur · zoom · crop · auto (recadrage auto du visage)

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" }
📋SRT format: 1\n00:00:00,000 --> 00:00:03,500\nLine text\n\n2\n... Timecodes must not exceed video duration.
ℹLe doublage fonctionne avec chaque fournisseur du moment que vous avez des jetons. Coût : 100–141 jetons par minute de vidéo, selon la voix.

Type : smart_clip — clips intelligents

Une longue vidéo (podcast, interview, vlog) → Whisper détecte la langue → un LLM choisit les moments les plus forts et autonomes → ffmpeg découpe plusieurs clips courts prêts à l'emploi. Un appel = plusieurs clips. Nécessite une offre avec clips intelligents.

{
  "type": "smart_clip", "file": "upload_id_or_https_url",
  "max_clips": 6, "target_sec": 60, "language": "uk",
  "context": "podcast business, cherche des conseils et citations fortes",
  "reels_mode": true, "subtitles": true, "sub_style": "yellow_basic",
  "auto_text": true, "filters": ["cinema"],
  "webhook_url": "https://mysite.com/hooks/reelora"
}
FieldDefaultDescription
filerequired—upload_id ou lien https:// direct vers la longue vidéo
max_clipsoptional0Nombre max de clips. 0 = auto (~1 pour 5 min, entre 4 et 10). Un plafond, pas un plan
target_secoptional60Durée cible du clip (sec). Les bornes réelles suivent les pauses de parole
languageoptionalnullLangue de la vidéo pour Whisper (uk, en, ru…). null/"auto" = détection auto
contextoptionalnullContexte pour le LLM : de quoi parle la vidéo et quoi chercher. Améliore nettement la pertinence
reels_modeoptionalfalsetrue → chaque clip en vertical 9:16 (fond flou). false = format original
reels_reframeoptional"blur"Stratégie de recadrage 9:16 (si reels_mode) : blur · fill · fill_blur · zoom · crop · auto (recadrage auto du visage)
subtitlesoptionaltrueIncruster des sous-titres karaoké sur chaque clip
sub_styleoptional"yellow_basic"Style de sous-titres (mêmes préréglages)
sub_positionoptional"bottom"top · center · bottom
sub_sizeoptional"medium"small · medium · large
sub_coloroptionalnullCouleur des sous-titres en HEX, ex. "#00FF00"
auto_textoptionalfalse⚡ Texte auto — incrustations dynamiques des mots-clés
filtersoptional[]Filtres couleur : vivid · contrast · ocean · forest · warm · cinema · bw · vintage

Les clips reviennent dans result_urls.clips[]. result_url = le premier clip (compatibilité). Champs du clip : 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" }
  ] }
}
💳Compteur unique — ce sont les minutes de la vidéo d'entrée qui sont facturées (transcription + sélection des moments + rendu de tous les clips inclus). Disponible aussi via webhook_url.
📋Entrée max par fichier : 120 min. Coût : 80 jetons par minute de vidéo d'entrée. Votre solde est dans GET /v1/me.

Type: motion — motion video

Turn text, a voice-over or a talking-head clip into a fully animated video (Remotion): a text/graphics explainer or a dynamic auto-edit. One call = one mp4. Requires a plan with motion enabled (or booster credits).

{
  "type": "motion", "source": "text",
  "text": "Three habits that quietly ruin your focus…",
  "format": "9:16", "style": "cream_editorial",
  "bgm_track": "chill_background-lofi-vibes-113884.mp3", "bgm_volume": 0.2,
  "webhook_url": "https://mysite.com/hooks/reelora"
}
FieldDefaultDescription
sourceoptional"text""text" · "voice" · "video"
fileoptional—upload_id or https:// URL. Required for voice/video
textoptional—Required for source:"text". Capped to your plan’s motion length
formatoptional"9:16"9:16 · 16:9 · 1:1 (ignored for source:"video")
styleoptional"cream_editorial"One of 13 themes: dark_bold, purple_block, green_neon, business_gold, psychology_calm, history_sepia, news_red, ocean_tech, bloom_pastel, kitchen_warm, mono_minimal, cyber_neon
tts_provideroptionalnullsource:"text" only. Overrides account TTS provider
tts_voiceoptionalnullsource:"text" only. Overrides account voice
bgm_trackoptionalnullBackground-music filename from the BGM list (mutually exclusive with bgm_file)
bgm_fileoptionalnullupload_id (or https:// URL) of your own MP3/audio (mutually exclusive with bgm_track)
bgm_volumeoptional0.2Music volume 0.0–1.0. Kept below the voice-over
webhook_urloptionalnullPOST on completion
send_to_telegramoptionalfalseAlso deliver to your Telegram
🎵Background music: a stock track via bgm_track or your own upload via bgm_file (mutually exclusive; omit both for no music). The track plays quieter than the voice-over and is trimmed to the video length — a shorter track plays to its end without looping. See the Background Music list.
📋Billing: a monthly count of videos plus optional pay-per-video boosters. Errors: 403 disabled/not on plan · 429 monthly limit · 400 bad input.

List of Tasks

GET/v1/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

GET/v1/tasks/{task_id}
{
  "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"
}
⏱️result_url is valid for 48 hours. For transcription, result_urls contains both: txt_url and srt_url.

Async Flow

POST /v1/tasks │ ▼ {"task_id": 744, "status": "pending"} │ ▼ Poll every 3–5 sec: GET /v1/tasks/744 │ ├── status: "pending" → wait ├── status: "processing" → wait (progress 0–100) ├── status: "completed" → download result_url ✅ └── status: "failed" → read error_message ❌

Task Statuses

pending
In queue, not started yet
processing
In progress. progress: 0–99
completed
Ready. File is in result_url
failed
Error in error_message

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/..." }
ℹWebhook retries up to 3 times (15s, 30s) if the server returns 5xx. We recommend backing it up with polling.

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 :

codelanguelocalemoteurs TTS
ukUkrainianuk-UAEdge, Gemini, 11Labs, Google
enEnglishen-USEdge, Gemini, 11Labs, Google
ruRussianru-RUEdge, Gemini, 11Labs, Google
esSpanishes-ESEdge, Gemini, 11Labs, Google
deGermande-DEEdge, Gemini, 11Labs, Google
frFrenchfr-FREdge, Gemini, 11Labs, Google
plPolishpl-PLEdge, Gemini, 11Labs, Google
itItalianit-ITEdge, Gemini, 11Labs, Google
ptPortuguesept-BREdge, Gemini, 11Labs, Google
zhChinesezh-CNEdge, Gemini, 11Labs, Google
jaJapaneseja-JPEdge, Gemini, 11Labs, Google
arArabic (RTL)ar-SAEdge, Gemini, 11Labs, Google
faPersian (RTL)fa-IREdge uniquement
heHebrew (RTL)he-ILEdge, Google
urUrdu (RTL)ur-PKEdge uniquement
trTurkishtr-TREdge, Gemini, 11Labs, Google
hiHindihi-INEdge, Gemini, 11Labs, Google
bnBengalibn-BDEdge, Gemini, Google
idIndonesianid-IDEdge, Gemini, 11Labs, Google
msMalayms-MYEdge, 11Labs, Google
viVietnamesevi-VNEdge, Gemini, Google
thThaith-THEdge, Gemini, Google
koKoreanko-KREdge, Gemini, 11Labs, Google
nlDutchnl-NLEdge, Gemini, 11Labs, Google
roRomanianro-ROEdge, Gemini, 11Labs, Google
elGreekel-GREdge, 11Labs, Google
csCzechcs-CZEdge, 11Labs, Google
svSwedishsv-SEEdge, 11Labs, Google
azAzerbaijaniaz-AZEdge uniquement
kkKazakhkk-KZEdge uniquement
uzUzbekuz-UZEdge uniquement
💡tts_provider: "edge" fonctionne pour les 31 langues et est gratuit — le choix par défaut sûr pour les langues rares (fa, ur, az, kk, uz — Edge uniquement). Si tu omets tts_voice, la bonne voix est choisie depuis language.
🌐Langues RTL (ar, fa, he, ur) : les sous-titres se rendent de droite à gauche avec une police arabe. Les styles karaoké animés reviennent au texte simple pour le RTL.

TTS Providers

ProviderValueQualityLimit
Google (Standard/Wavenet/Chirp)"google"Good6–27 tok/min
Gemini 2.5 / 3.1 TTS"gemini"Excellent41 tok/min
Azure Neural"azure"Good27 tok/min
Edge TTS (Microsoft)"edge"Goodfree
HuggingFace"hf"Basic14 tok/min
ElevenLabs"elevenlabs"Premium17 tok/min

Voices

Google ("google")

Locale is taken from account settings. Change it via: Settings → 🌍 Language.

tts_voiceDescription
Standard-AFemale, basic quality
Standard-BMale, basic quality
Wavenet-AFemale, neural quality
Wavenet-BMale, neural quality
Journey-FFemale, EN only, natural
Chirp3-HD-AoedeFemale, multilingual, HD
Chirp3-HD-PuckMale, 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_voiceCharacter
ZephyrBright 🌤
PuckUpbeat 🎉
CharonInformative 📚
KoreFirm 💪
FenrirExcitable ⚡
LedaYouthful 🌱
AoedeBreezy 🍃
CallirrhoeEasy-going 😌
SadachbiaLively 🎵
SulafatWarm 🔥
AchirdFriendly 🤝
EnceladusBreathy 🌬
GacruxMature 🍷

Edge TTS ("edge") — unlimited

tts_voiceLanguage
uk-UA-OstapNeuralUkrainian, male
uk-UA-PolinaNeuralUkrainian, female
en-US-GuyNeuralEnglish US, male
en-US-JennyNeuralEnglish US, female
en-GB-RyanNeuralEnglish GB, male
de-DE-ConradNeuralGerman, male
fr-FR-HenriNeuralFrench, male
es-ES-AlvaroNeuralSpanish, male
pl-PL-MarekNeuralPolish, male
it-IT-DiegoNeuralItalian, male
tr-TR-AhmetNeuralTurkish, male
cs-CZ-AntoninNeuralCzech, male
ru-RU-DmitryNeuralRussian, male

ElevenLabs ("elevenlabs") — 17 jetons par minute

tts_voice (ID)Name
pNInz6obpgDQGcFmaJgBAdam (male, multilingual)
21m00Tcm4TlvDq8ikWAMRachel (female, multilingual)
AZnzlk1XvdvUeBnXmlldDomi (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.mp3Lofi chill
chill_background-the-weekend-117427.mp3Lofi weekend
bodleasons-lofi-chill-smooth-chill-lofi-for-vlogs-and-background-music-159456.mp3Lofi smooth
alexgrohl-phonk-505963.mp3Phonk
white_records-neon-drift-phonk-house-background-music-for-video-27-second-496492.mp3Phonk house (27s)
white_records-toxic-drift-slap-house-background-music-for-video-stories-37-second-503887.mp3Slap house (37s)
diamond_tunes-majestic-tides-60sec-286729.mp3Cinematic majestic (60s)
raspberrymusic-relic-of-honor-cinematic-video-game-epic-478243.mp3Cinematic epic
raspberrymusic-be-the-change-epic-documentary-corporate-394293.mp3Documentary
raspberrymusic-triumph-adventure-news-cinematic-394333.mp3News cinematic
Under_the_Clock.mp3Dramatic
The_Approaching_Hour.mp3Dramatic ambient

bgm_volume: 0.1 (quiet background) → 1.0 (full volume). Default is 0.2.

Subtitle Styles

sub_styleDescription
yellow_basicMrBeast style — bold yellow words
purple_greenNeon — purple + green highlight
minimal_whiteMinimal white, clean
news_styleNews rolling ticker line style
fire_orangeFiery orange highlight
pop_greenBright green
word_box_orangeOrange bounding box around word
karaoke_cyanKaraoke cyan
cursor_selectionCursor selection style
single_green_boxGreen bounding box on a single word
business_newsBusiness news style
dynamic_colorsDynamic colors
elegant_whiteElegant white — bold karaoke, ultra-transparent bar
dual_duetDuet — two paired lines (yellow + white)

Video Formats

formatAspect RatioPlatforms
9_169:16 (vertical)TikTok, Instagram Reels, YouTube Shorts
16_916:9 (horizontal)YouTube, Desktop
1_11:1 (square)Instagram Feed, Facebook
originaloriginalKeep source dimensions

Coût en jetons

Il n'y a pas de forfaits ou abonnements — l'API dépense des jetons du même solde que le bot. 1 000 jetons = 1 $. Les jetons ne sont déduits que pour une tâche réussie.

Type de tâcheCoûtUnité
video30 tokpar minute de sortie
transcription40 tokpar minute
subtitles50 tokpar minute
subtitles + translate_to60 tokpar minute
pause_removal50 tokpar minute
smart_clip80 tokpar minute de vidéo d'entrée
dubbing100–141 tokpar minute, selon le fournisseur de voix
audio (TTS) — edgegratuit—
audio (TTS) — google (Standard)6 tokpar minute de parole
audio (TTS) — elevenlabs17 tokpar minute de parole
audio (TTS) — google (Wavenet/Chirp), azure27 tokpar minute de parole
audio (TTS) — gemini41 tokpar minute de parole
auto_text50 tokpar rendu
AI cards30 tokpar élément
frame overlays30 tokpar rendu
📋Votre solde actuel et utilisation sont dans GET /v1/me. Si le solde est insuffisant, la tâche retourne 402.

Error Codes

HTTPReason
401Missing or invalid X-API-Key
403Feature unavailable on the current plan
404Task or file not found (upload_id might have expired after 2h)
413File exceeds 500 MB
415Unsupported file type
402Not enough tokens on your balance
42930 requests/min rate limit hit
500Internal 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