Skip to main content
This guide is the end-to-end flow for creating avatar video clips over the REST API. Creating a take generates audio. When audio_url is set, you can download it, edit pronunciation or video instructions, then start the video render. Audio and video are separate on purpose. Video takes a long time and a lot of credits. Audio is relatively quick and cheap, so we recommend you refine pronunciation, timing, and the face / upper-body instructions where you want them before you start the video job. Approximate times and costs for a full job are in Overview.

Flow

1. Create a clip

POST /api/clips/create/
Returns the clip, including id (use this in later URLs). Now that we’ve created our first clip, we need to generate the first take within that clip.

2. Generate audio

POST /api/clips/<clip_id>/takes/ creates a take and starts TTS. Send avatar_id and exactly one of text or phonemes. Optional name (defaults to Take N where N is number of existing takes + 1). If you send text, we convert it to phonemes internally, then synthesize audio from that string. Pass phonemes yourself when you want tighter control over how words are pronounced. Do not send both.
Or pass phonemes directly:
Returns the take: id, status (starting_tts), text, phonemes (the converted string if you sent text), and audio_url / video_url as null. Also credits_charged and estimated_seconds. Listen to the audio once audio_url is set (next step). If a pronunciation is off, edit the phonemes string and send it as phonemes on a new generate-audio request. If there are not enough credits, the request fails and no take is created.

3. Poll until audio is ready

GET /api/clips/<clip_id>/takes/<take_id>/ to poll the status of the audio creation job. Watch status and audio_url. audio_url stays null until the audio is ready. When the status is ready_to_render, the audio_url will be a download link and chunk_prompts will have the face / upper-body instructions per each 2.5-3 second audio chunk.

Audio status fields

Video instructions

From the generated audio we cut the take into chunks of about 2.5–3 seconds and attach two video instructions to each chunk:
  • face_prompt — head and face (expression, eyebrows, gaze, emotion)
  • upper_body_prompt — shoulders, arms, and hands
We generate these automatically from the spoken line. These instructions steer look, emotion, and leftover body motion. Leave them as generated unless you want a very specific behavior on a given chunk. Assume each chunk is about 60 to 75 frames. Frame 0 is locked (the still, or the end of the previous chunk), so a gesture cannot start already fully extended. Put the hands down before the last ~10 frames so a raised pose does not carry into the next chunk. Time a move with *frames start~end* on the same line:
Defaults (what we write on most chunks): Face:
Upper body:
A few chunks get a real gesture (greeting, thanks, emphasis). The rest stay on those defaults. Changing phonemes rebuilds audio and regenerates the chunks; editing instructions does not change how many chunks there are or when they start. Example: one take, three chunks. Chunk 0 is a greeting; 1 is the default; 2 is a small fidget:

How to prompt

Only edit a chunk if you need a specific look or gesture there. Otherwise keep the defaults. Face. Expression, eyebrows, gaze. Do not mention hands. Upper body. Name each starting, intermediate, and ending state. Use *frames start~end* so the move sits on the spoken beat.

4. Edit phonemes or video instructions (optional)

Phonemes and video instructions can be changed before render starts. After render has started, those edits fail with Take video has already started.

Phonemes

POST /api/clips/<clip_id>/takes/<take_id>/phonemes/ with a phonemes string. Optional text relabels the line; omit it to keep the existing text. See Phonemes for the alphabet. This regenerates audio (and the video instructions that go with it). If there are not enough credits, the request fails and the take is left unchanged. It also fails if audio is still in progress. Poll again until audio_url is set. Returns id, text, phonemes, estimated_seconds, and credits_charged.

Video instructions

POST /api/clips/<clip_id>/takes/<take_id>/prompts/ with chunk_prompts. Each object needs index, upper_body_prompt, and face_prompt. Prompt edits are free and do not regenerate audio. Window count and timing stay locked. Returns id and the updated chunk_prompts.

5. Render video

When status is ready_to_render and audio_url is set, POST /api/clips/<clip_id>/takes/<take_id>/render/ starts video. This locks phonemes and prompts on that take. If there are not enough credits, the request fails and the take is left unchanged. Optional body (both default true):
show_ai_label overlays This is AI in the corner of the video. show_logo overlays Made by plus the Akapulu Labs logo. Both default to true. show_logo: false requires Starter plan or higher. Free plans will get an error if you turn the logo off. show_ai_label can be false on any plan. We recommend setting it to true so people watching can tell the clip is AI-generated. Some places, including the EU, have rules about disclosing AI-generated media. Invisible watermarks and Content Credentials still go on every take if the overlays are off. Details are in AI content disclosure. Poll the same GET until status is complete, then download video_url.

Video status

Credits

Clip audio and video use the same credit pool as live conversations and llm test sessions. Credits are charged when generate-audio, a phoneme rebuild, or render succeeds. If the pool cannot cover that charge, the request fails and nothing on the take changes. Approximate credits by spoken length are on Overview. Also: Phonemes · AI content disclosure · Python example