Endpoints
Slideshow API
POST /v1/slideshow turns 1 to 100 photos into an MP4 up to 15 minutes long. Add a voiceover from an audio file or from text read by one of 40 voices, background music that ducks under the voice, and word-by-word captions.
Pick a size, a transition and the motion, and the render comes back in the same call for most slideshows under a minute.
- Typical render
- 13 to 42 s
- 7 s to 42 s videos in our tests
- Price
- $0.02
- per output minute, voiceover $0.05 per 1,000 characters
- Length
- Up to 15 minutes
- 1 to 100 images
Example#
Three photos, a voice reading one line and karaoke captions. Paste it as is: the photo URLs are public, and the video is ready in about 13 seconds.
curl -sS "https://api.reelsdk.com/v1/slideshow" \
-H "Authorization: Bearer $REELSDK_KEY" \
-H "Content-Type: application/json" \
-d '{
"images": [
"https://picsum.photos/id/1015/1920/1080",
"https://picsum.photos/id/1018/1920/1080",
"https://picsum.photos/id/1036/1920/1080"
],
"size": "16:9",
"voiceover": {
"text": "Three days by the water. Mountains at sunrise, forests by noon, and a lake that held the whole sky.",
"voice": "luna"
},
"captions": "karaoke"
}'Parameters#
Send a JSON body. Only images is required. Fields we don't recognize are ignored.
| Parameter | Description |
|---|---|
imagesarrayRequired | The photos, in order. Each item is a public image URL, or 1 to 100 items |
images[].urlstring | JPEG, PNG, WebP, AVIF or any image ffmpeg reads, up to 100 megapixels and 500 MB. Public http(s) URL |
images[].secondsnumber | How long this image stays on screen. 0.5 to 60 |
sizestring | Output size, such as Default |
widthinteger | Output width in pixels, as an alternative to 240 to 2160, send with |
heightinteger | Output height in pixels. 240 to 2160, send with |
fpsinteger | Frame rate of the video. Default |
seconds_per_imagenumber | Length of every image without its own 0.5 to 60 |
transitionstring or object | A transition name, Default |
transition.typestring | One of 58 transition names, |
transition.secondsnumber | Length of each transition. Default |
fitstring |
coverdefaultcontain |
motionstring or boolean |
kenburnsdefaultnone |
voiceoverstring or object | Narration: an audio URL, |
voiceover.urlstring | An audio file, or a video with an audio track, up to 15 minutes. Public http(s) URL |
voiceover.textstring | Text to read aloud. Use this instead of 1 to 10,000 characters |
voiceover.voicestring | One of 40 English voices. Default Show all 40 voicesHide all 40 voicesamaltheaandromedaapolloarcasariesasteriaathenaatlasauroracallistacoracordeliadeliadracoelectraharmoniahelenaherahermeshyperionirisjanusjunojupiterlunamarsminervaneptuneodysseusopheliaorionorpheuspandoraphoebeplutosaturnthaliatheiavestazeus |
voiceover.volumenumber | Voice level, where Default |
musicstring or object | Background music: an audio URL, or |
music.urlstring | An audio file up to 15 minutes. Public http(s) URL |
music.volumenumber | Music level before ducking. Default |
captionsboolean, string or object | Word-by-word captions of the voiceover: |
languagestring | Language of the voiceover for captions. Detected when you leave it out. A code like |
qualitystring | H.264 encoder quality: CRF 26, 21 or 18. draftstandarddefaulthigh |
webhook_urlstring | We POST the finished job to this URL. See Webhooks. Public http(s) URL |
Sizes#
Set size to an aspect name or exact pixels like 1280x720. Without a size you get a vertical 1080x1920 video. Width and height must be 240 to 2160 pixels, and odd values are rounded to an even number.
| size | Pixels | Good for |
|---|---|---|
| 9:16, portrait, vertical | 1080x1920 | Reels, TikTok, YouTube Shorts |
| 16:9, landscape, horizontal | 1920x1080 | YouTube, websites |
| 1:1, square | 1080x1080 | Feeds |
| 4:5 | 1080x1350 | Instagram feed |
| 3:4 | 1080x1440 | Portrait feeds |
| 4:3 | 1440x1080 | Presentations |
Image timing#
Images play back to back. Transitions are centered on the boundary between two images, so the video runs exactly the sum of the image lengths.
- Without a voiceover, every image gets 3 seconds, or
seconds_per_imageif you set it. - With a voiceover, images without their own
secondsshare the voiceover length plus half a second, at least 1 second each. Three photos and a 6.7 s voiceover give 2.4 s per photo and a 7.2 s video. - An image with
secondsalways keeps that length. - The whole video can be up to 900 seconds. Longer timings return
400before the job starts.
{
"images": [
{ "url": "https://example.com/cover.jpg", "seconds": 4 },
"https://example.com/2.jpg",
"https://example.com/3.jpg"
],
"seconds_per_image": 2.5,
"transition": {
"type": "smoothleft",
"seconds": 0.8
},
"music": {
"url": "https://example.com/track.mp3",
"volume": 0.3
}
}Here the first photo stays for 4 seconds and the other two for 2.5 seconds each, so the video is 9 seconds long.
Voiceover and music#
A voiceover can be any public audio file, or a video with an audio track. Send text instead and we read it aloud with one of 40 English voices. A text voiceover adds $0.05 per 1,000 characters, counted in usage.tts_characters.
Music loops until the video ends, fades out over the last second, and ducks under the voice while someone speaks. The final mix is normalized to -14 LUFS, the level most platforms play at, and encoded as AAC at 192 kbps. If the voiceover runs longer than your images, it fades out when the video ends.
Transitions and motion#
The default is a 0.5 second fade. random picks from 12 smooth ones, such as slides, covers and fades through black, and never uses the same one twice in a row. none cuts straight from one image to the next. Each transition lasts at most half of the shortest image.
All 58 transition names
fadefadeblackfadewhitefadegraysfadefastfadeslowdissolvedistancepixelizeradialwipeleftwiperightwipeupwipedownwipetlwipetrwipeblwipebrslideleftsliderightslideupslidedownsmoothleftsmoothrightsmoothupsmoothdowncirclecroprectcropcircleclosecircleopenhorzclosehorzopenvertclosevertopendiagbldiagbrdiagtldiagtrhlslicehrslicevuslicevdslicehblursqueezehsqueezevzoominhlwindhrwindvuwindvdwindcoverleftcoverrightcoverupcoverdownrevealleftrevealrightrevealuprevealdownkenburns motion slowly zooms or pans every photo and changes the move from one photo to the next. Set motion to none for still photos.
Response#
A finished slideshow answers 200 with the job. outputs.video is your MP4. With captions on, you also get transcript, srt, vtt and ass, the same files as the Captions API. If the render outlasts your wait, you get 202 and a poll_url instead.
{
"job": {
"id": "job_2q9jwcnzk4c85tuil3p1",
"op": "slideshow",
"status": "succeeded",
"stage": null,
"created_at": "2026-10-26T01:15:30.646Z",
"finished_at": "2026-10-26T01:15:43.336Z",
"outputs": {
"video": "https://api.reelsdk.com/f/out/job_2q9jwcnzk4c85tuil3p1/video.mp4",
"transcript": "https://api.reelsdk.com/f/out/job_2q9jwcnzk4c85tuil3p1/transcript.json",
"srt": "https://api.reelsdk.com/f/out/job_2q9jwcnzk4c85tuil3p1/captions.srt",
"vtt": "https://api.reelsdk.com/f/out/job_2q9jwcnzk4c85tuil3p1/captions.vtt",
"ass": "https://api.reelsdk.com/f/out/job_2q9jwcnzk4c85tuil3p1/captions.ass"
},
"result": null,
"duration_s": 7.2,
"error": null,
"usage": {
"output_seconds": 7.2,
"audio_seconds": 6.696,
"tts_characters": 99,
"images": 0
},
"poll_url": "https://api.reelsdk.com/v1/jobs/job_2q9jwcnzk4c85tuil3p1"
}
}usage.output_seconds is the video length you pay for, usage.tts_characters the characters read aloud, and usage.audio_seconds the voiceover we transcribed for captions. Files stay up for 7 days.
Errors#
Bad fields return 400 before a job starts. Problems with your files fail the job with 422. The full list is in Errors.
| Code | HTTP | When it happens |
|---|---|---|
| INVALID_REQUEST | 400 | A field is invalid, for example captions: captions need a voiceover to transcribe |
| INPUT_FETCH_FAILED | 422 | We couldn't download a file, for example Could not fetch images[2]: HTTP 404 |
| INPUT_TOO_LARGE | 422 | A file is over 500 MB, or all files together are over 1,000 MB |
| INPUT_UNSUPPORTED | 422 | An image can't be decoded or is over 100 megapixels, or the audio has no sound or runs over 15 minutes |
| INVALID_SPEC | 422 | The voiceover would make the slideshow longer than 15 minutes |
| TTS_FAILED | 500 | Reading the text aloud failed after our automatic retry. Send the request again. |
Tips#
- Pick the size for where the video goes:
9:16for Reels, TikTok and Shorts,16:9for YouTube,1:1or4:5for feeds. - Render time grows with the video length, close to real time for long slideshows. Past about a minute of video, raise
?waitor use a webhook. - Image URLs must be public. For local files, upload them with POST /v1/uploads and pass the returned URLs.
- Use
quality: "draft"while you try out timings and transitions.
Last updated 26 October 2026