Reels
Several testimonials cut into one captioned, branded video, rendered in 9:16, 1:1 and 16:9, ready to post.
What a reel guarantees
- Every frame is a real recording, and every word was really said. A reel is made of spans of testimonials' processed videos. A language model may suggest where to cut. It returns timestamps, never words, and every span it returns is checked against the testimonial's transcript before it is used. The span must lie inside the recording, and it must start exactly where a word starts and end exactly where a word ends. An answer that fails is refused and asked for once more, and then a deterministic rule takes over.
- Captions are the transcript's own words, in order, character for character.
- Nobody is cut off mid-word. A clip starts and ends on a word boundary. The cut adds up to 120 ms of silence either side, and never takes a sliver of the neighbouring word.
- Every clip sits at the same loudness, whatever phone it was recorded on.
This is how the FTC's rule on fake and AI-generated testimonials is met by construction, not by policy (ADR 0006).
Making a reel
1. Create it from a brand's testimonials. Each one must be a processed video with a transcript, since the spans are chosen from its words and captioned with them.
curl -H "$AUTH" -H 'content-type: application/json' \
-d '{ "brand_id": "brd_…", "submission_ids": ["sub_…", "sub_…", "sub_…"], "mode": "auto" }' \
https://api.akteora.com/v1/reels
mode: "auto"suggests the strongest few seconds of each testimonial and the order to play them in."manual"keeps the order you give and suggests only where to cut.configis optional. Anything left out takes its default:
| Setting | Default | |
|---|---|---|
aspect_ratios |
["9:16", "1:1", "16:9"] |
Which sizes to render. Each costs render time |
caption_style |
"bold" |
bold, boxed or minimal |
intro |
null |
{ "title": "…" }: a card with the brand's logo before the first clip. Up to 60 characters |
outro |
null |
{ "call_to_action": "…" }: a card after the last clip. Up to 80 characters |
music |
null |
{ "track_id": "warm" }, one of GET /v1/reels/music. Ducked under the speech |
target_duration_ms |
45000 |
Roughly how long the reel should run (15–120 s). It steers how long each suggested clip is |
A testimonial that cannot go in returns 422, naming it and the reason: not a video, still processing, rejected, another brand's, or not transcribed yet.
The answer is the reel. Each clip carries its text, the exact words it contains, which is
what its captions will say. It also has a source: model, heuristic (the deterministic
rule) or operator. For a model clip, reason is the model's note on why it chose the span.
It is shown in the editor and never in the video.
2. Trim and reorder. Save every clip, in play order:
curl -X PUT -H "$AUTH" -H 'content-type: application/json' \
-d '{ "clips": [ { "submission_id": "sub_…", "start_ms": 4000, "end_ms": 7450 }, … ] }' \
https://api.akteora.com/v1/reels/rel_…/clips
start_ms must equal a word's start_ms in the testimonial's transcript
(GET /v1/submissions/{id}/transcript), and end_ms a word's end_ms. A clip is 1.5 to 30
seconds, and a reel holds up to 12. POST /v1/reels/{id}/clips with { "submission_id" }
adds a testimonial at the end, with a suggested span. PATCH /v1/reels/{id} changes the
title or any setting.
3. Render it.
curl -X POST -H "$AUTH" https://api.akteora.com/v1/reels/rel_…/render
# 202 { "render_id": "job_…" }
Rendering is a job. Poll GET /v1/reels/{id}, and render says where it has got to:
render.stage |
|
|---|---|
queued |
Waiting for a slot. New testimonials are always processed before reels |
cutting |
Cutting clip done + 1 of total |
cards |
Making the intro and outro cards |
music |
Laying the music bed |
captions |
Writing the captions |
rendering |
Encoding aspect_ratio, done + 1 of total |
uploading, finishing |
Nearly there |
render.label says the same for a person ("Cutting clip 3 of 8"). render.paused is true
while the reel waits for a newly arrived testimonial to be processed. A render that runs past
30 minutes is stopped and fails, with a reason in render.error_message. Whoever started the
render is emailed when it is ready.
A render must fit in what is left of the plan's monthly render minutes. Otherwise it
returns 402 plan_limit_exceeded, naming the limit and the plan that raises it. What a
render would cost, and whether it can start, is in estimate before you ask. A reel already
rendering returns 409.
The finished files
Once a render succeeds, output holds its files until a new render replaces them:
variants: one per size, each withurlfor playing in a page anddownload_url, saved as a file named after the reel (customer-stories-9x16.mp4). Both are signed and valid for an hour; fetch the reel again for fresh ones.poster_url: a still from the first clip.captions_download_url: the captions as a WebVTT file, for platforms that take one beside the video.
changed_since_render turns true when the clips, title or settings change after the last
successful render.
Sharing
POST /v1/reels/{id}/share makes a public copy of the last render on the CDN.
DELETE /v1/reels/{id}/share removes it.
"share": {
"enabled": true,
"status": "live",
"urls": {
"variants": [{ "aspect_ratio": "9:16", "url": "https://cdn.akteora.com/r/p8k2m4q7x9/9x16.mp4" }],
"poster_url": "https://cdn.akteora.com/r/p8k2m4q7x9/poster.jpg",
"captions_url": "https://cdn.akteora.com/r/p8k2m4q7x9/captions.vtt"
}
}
statusispublishingfor the few seconds the copy takes, thenlive.urlsisnulluntil then.- The address names nothing but a random id. It stays the same across renders: rendering a shared reel again replaces the files at the same addresses.
- Turning sharing off deletes the copy, and the addresses stop working within seconds. They also stop working when the reel is deleted, and when anyone who appears in it has their testimonial erased.
When a testimonial is erased
A respondent who withdraws consent is removed from every reel they appear in. Their clips go,
every rendered file and public copy of those reels is deleted, and each reel is left as a
draft whose error_message says why. Rendering it again makes a new version without them.
Music
GET /v1/reels/music lists the beds. Every track is original to Akteora or licensed for use in
any reel; there is no upload.
Errors
| Status | When |
|---|---|
| 402 | The render would go over the plan's render minutes |
| 404 | No such reel, or not yours |
| 409 | The reel is already rendering |
| 422 | A testimonial that cannot go in, a span off the word boundaries, an unknown music track, or sharing a reel that has never been rendered |
Coming
reel.ready and reel.failed webhooks, with the public API release.