Guides

Talking actor ads

Make the voice first, then the video that lip-syncs to it.

Read as Markdown

A talking actor ad is two generations, in order:

  1. tts turns your script into audio.
  2. actor_ultra animates the actor to that audio. It needs the finished voice's generation_id.

Have your own recording? Skip the voice. Jump down.

Pick an actor and a voice

List them with GET /actors and GET /voices (MCP: list_actors, list_voices). Actor ids start act_, voice ids voc_. If the actor has a default voice, you can leave out voice_id.

Make the voice, then the video

Terminal
BASE=https://app.riffads.com/api/v1
AUTH="Authorization: Bearer $RIFFADS_API_KEY"
SCRIPT="Two weeks of battery, in a case this small."

# 1. The voice
VOICE=$(curl -s -X POST "$BASE/generations" -H "$AUTH" -H "Content-Type: application/json" -d "{
  \"capability_id\": \"tts\",
  \"config\": { \"script\": \"$SCRIPT\" },
  \"actor_id\": \"act_0193c8f0a1b24e7f9d3c5a6b7e8f0011\",
  \"voice_id\": \"voc_0193c8f0a1b24e7f9d3c5a6b7e8f0022\",
  \"max_credits\": 10
}" | jq -r .generation_id)

# 2. Call until still_running is false and status is completed
curl -s "$BASE/generations/$VOICE/wait" -H "$AUTH"

# 3. The video, driven by that voice
curl -s -X POST "$BASE/generations" -H "$AUTH" -H "Content-Type: application/json" -d "{
  \"capability_id\": \"actor_ultra\",
  \"config\": { \"script\": \"$SCRIPT\" },
  \"actor_id\": \"act_0193c8f0a1b24e7f9d3c5a6b7e8f0011\",
  \"voice_id\": \"voc_0193c8f0a1b24e7f9d3c5a6b7e8f0022\",
  \"approved_voice_generation_id\": \"$VOICE\",
  \"max_credits\": 700
}"

max_credits values above are placeholders. Get the real number from the estimate endpoint (estimate_generation) for each step, then send at least ceil(estimate * 1.1).

Both calls must match

Same script, same actor_id, same voice_id. Build the script once and reuse the variable. Any change: invalid_config, The approved voice no longer matches this generation.

What actor_ultra takes

FieldWhereNotes
actor_id or actor_image_asset_idbodyOne is required. An uploaded image works as the face
voice_idbodyOptional if the actor has a default voice. Config spells it voiceId
approved_voice_generation_idbodyThe completed tts generation
scriptconfigSame words as the voice
voice_audioconfigYour own recording instead of a voice
  • No aspect_ratio. Refused. The video takes the actor image's shape.
  • No duration. Audio sets the length. It must be under 60 seconds.
  • No variants. Want 3 takes? Run the pair 3 times.
  • The id is actor_ultra. talking_actor is refused.

Use your own audio

One generation. No tts, no script, no voice. Upload the file first and wait for usable: true.

Request body
{
  "capability_id": "actor_ultra",
  "config": { "voice_audio": ["ast_0193c8f0a1b24e7f9d3c5a6b7e8f0044"] },
  "actor_id": "act_0193c8f0a1b24e7f9d3c5a6b7e8f0011",
  "max_credits": 700
}

Send it with submit_generation on MCP, not generate_talking_actor. If both a recording and a script arrive, the recording wins.

Common refusals

All are invalid_config, and nothing is charged.

MessageFix
Generate and approve the voice before creating the video.Make the tts step first
The approved voice no longer matches this generation.Send the same script, actor and voice
Select a voice first.Send voice_id

Video sent while the voice still runs: submission_in_flight. Wait, then resend.

Getting the file: results.

On this page