Voiceover
A video post (postType: "VIDEO") can be narrated, as a video is with the editor’s voiceover. Ask for one with videoSettings.voiceover on Generate, Import or Edit. You pick the voice and the tone, and the AI does the rest:
- It writes one spoken line per slide, from the slides, in your tone.
- It records each line in your voice.
- Each slide lasts as long as its narration needs, and the narration’s words show as captions.
You don’t send a script or a recording: the AI writes and records it. A script field is refused.
Example
An imported video in the Bold style, with music under it at a quarter of its volume, narrated in the Nova voice:
curl --location 'https://embed-api.postnitro.ai/post/initiate/import' \
--header 'Content-Type: application/json' \
--header 'embed-api-key: pn-your-api-key' \
--data '{
"postType": "VIDEO",
"templateId": "your-template-id",
"brandId": "your-brand-id",
"responseType": "MP4",
"slides": [
{
"type": "starting_slide",
"sub_heading": "Remote work",
"heading": "3 habits of fast teams",
"description": "The ones that actually stick."
},
{
"type": "body_slide",
"heading": "Write things down",
"description": "Decisions live in docs, not in calls."
},
{
"type": "ending_slide",
"heading": "Try one this week",
"cta_button": "Follow for more"
}
],
"videoSettings": {
"motionStyle": "bold",
"backgroundMusicId": "your-audio-id",
"backgroundMusicVolume": 25,
"voiceover": { "voice": "nova", "tone": "Hype and punchy" }
}
}'{} gives a voiceover with every default: the Coral voice, an upbeat tone, and captions.
"videoSettings": {
"voiceover": {}
}Fields
All of them are optional.
| Field | Type | Default | Description |
|---|---|---|---|
voice | string | "coral" | Who reads it: one of the voices |
tone | string | "upbeat" | How it’s written and read: "upbeat", "calm", "professional", "storyteller", or your own words, up to 80 characters, such as "Hype and punchy" |
captions | boolean | true | true shows the narration’s words as captions on the video; false hides them |
Any other field returns a 422. On an edit, "voiceover": false takes the video’s narration off: see Editing a narrated video.
Voices
The voices are OpenAI’s, the same as the editor’s:
alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer, verse
To hear them first, play them in the editor: see Pick a voice and a tone.
Tones
The tone sets both how the AI writes the script and how the voice reads it. upbeat, calm, professional and storyteller are the editor’s. Anything else is your own words, up to 80 characters, such as "Hype and punchy" or "breathless, like a sports commentator".
Length
Each slide lasts as long as its narration needs, and the video runs as long as all its slides take (Length). The AI keeps the whole narration within the video’s 2:00 limit. Post Output’s duration includes it.
With music
Music from backgroundMusicId plays under the voiceover. It’s lowered to 30% while the narration plays, so the voice is easy to hear.
What it costs
A voiceover is charged as the editor’s is, from your plan’s AI tokens, not from your API credits, as AI images bill against their own quota:
- The script costs the tokens the AI used to write it.
- The recording costs 5,000 tokens per minute of audio.
For example, a 5-slide video with 27.1 seconds of narration took 2,866 AI tokens. The VOICEOVER step says what each one took.
The post’s API credits don’t change: 1 per slide for import, 2 per slide for AI generation, with a voiceover or without.
When it can’t be made
A voiceover is best-effort, as AI images are. If the plan’s AI tokens are used up, or the narration fails, the video is still made, without narration, and the post completes. The VOICEOVER step says why. A slide that couldn’t be recorded has no narration, and the step says how many.
The VOICEOVER step
A video that asks for a voiceover has a VOICEOVER step in Check Post Status’s logs. It comes after SAVE_JSON (and GENERATE_IMAGES, when the request asks for images) and before COMPOSE_MOTION.
| Status | Message |
|---|---|
COMPLETED | Narrated 5 slides in nova, Hype and punchy: 27.1s, 2,866 AI tokens |
COMPLETED | The same, ending ; 1 slide couldn't be recorded when some slides got no narration |
FAILED | Skipped the voiceover: the plan's AI tokens are used up |
FAILED | Skipped the voiceover: voiceovers are part of paid plans |
FAILED | Skipped the voiceover: <reason>, for any other failure |
A FAILED step doesn’t fail the post.
Editing a narrated video
An edit of a narrated video narrates its new slides again, in its own voice and tone, and is charged again in AI tokens.
- Send no
voiceoverand it keeps its voice, tone and captions. - Send some fields, such as only
tone, and just those change. - Send
"voiceover": falseand the narration is taken off.
An edit can also narrate a video that has no voiceover yet: send voiceover, or {} for the defaults.
{
"embedPostId": "post123",
"responseType": "MP4",
"slides": [
{
"type": "starting_slide",
"heading": "Two habits, done well"
},
{
"type": "body_slide",
"heading": "Write it down",
"description": "In one place everyone reads."
},
{
"type": "ending_slide",
"heading": "Start today",
"cta_button": "Follow for more"
}
],
"videoSettings": {
"voiceover": { "tone": "calm" }
}
}Reading it back
Read a Post gives a narrated video’s voice, tone and captions in videoSettings.voiceover. It doesn’t give the script.
"videoSettings": {
"motionStyle": "bold",
"backgroundMusicId": "cmqi7jyir0003v0m91hxnyyaq",
"backgroundMusicVolume": 25,
"voiceover": { "voice": "nova", "tone": "Hype and punchy", "captions": true }
}Errors
Refused with a 422 when you make the request, before anything is made or charged:
| Message | When |
|---|---|
videoSettings.voiceover must be an object: { voice, tone, captions }, all optional, or false for none | voiceover is a string, a list, true or null |
videoSettings.voiceover has invalid field 'script'. Allowed fields are: voice, tone, captions. The AI writes the script | A script, or any other field it doesn’t take |
videoSettings.voiceover.voice must be one of: alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer, verse | Not one of the voices |
videoSettings.voiceover.tone must be upbeat, calm, professional, storyteller, or your own words, up to 80 characters | An empty tone, not a string, or longer than 80 characters |
videoSettings.voiceover.captions must be true or false | captions isn’t a boolean |
videoSettings on a CAROUSEL or IMAGE post returns a 422 too.