Video Audio
Mix voiceover, music, or sound effects into a video.
Mix workspace audio assets into an existing video and save a new MP4. Original assets are kept.
Generate speech with Audio generation, then use its audio.media_id below.
Render audio
POST /api/v1/videos/audio/render
Scope: videos:generate
Requires a prior credit purchase. Each render costs 1 credit, matching caption rendering. Failed renders refund the credits charged for that render; audio generation is charged separately.
curl -X POST https://powerpost.ai/api/v1/videos/audio/render \
-H "x-api-key: pp_live_sk_YOUR_KEY" \
-H "X-Workspace-Id: YOUR_WORKSPACE_ID" \
-H "Content-Type: application/json" \
-d '{
"media_id": "VIDEO_MEDIA_ID",
"original_audio_volume": 0.25,
"audio_tracks": [
{
"media_id": "VOICEOVER_MEDIA_ID",
"start": 0,
"volume": 1,
"overflow": "error"
}
]
}'This adds narration over quieter original sound. It also works with silent videos.
| Field | Default | Description |
|---|---|---|
media_id | Required | Video UUID in the current workspace |
original_audio_volume | 1 | Original sound level, 0–1; 0 mutes it |
audio_tracks | Required | 1–16 audio tracks |
audio_tracks[].media_id | Required | Audio UUID in the same workspace |
audio_tracks[].start | 0 | Placement in seconds, 0–86400, strictly before the video ends |
audio_tracks[].volume | 1 | Added track level, 0–1; 1 preserves the source level |
audio_tracks[].overflow | error | Reject audio extending past the video, or use trim to cut it at the end |
All tracks start from the beginning of their audio file. Overlapping tracks mix together. You can reuse an audio ID at different start times. Unknown fields are rejected; looping, fades, and source trimming are not supported.
The picture stream determines the video endpoint, with container duration used when stream duration is unavailable. Audio duration uses container metadata, matching audio generation. An overrun of up to 50 ms is accepted for codec padding and rounding and cut at the video endpoint, even with overflow: "error". Larger overruns require overflow: "trim".
Video duration stays unchanged. Short audio ends naturally, leaving the remaining original sound or silence. Mixing uses fixed levels, with peak limiting to prevent clipping; it does not automatically lower music during speech. Original speech and music already mixed into one track are controlled together. The first original audio stream is used, if present, with its timing preserved.
Background music under existing narration
{
"media_id": "VIDEO_WITH_NARRATION_ID",
"original_audio_volume": 1,
"audio_tracks": [
{ "media_id": "MUSIC_ID", "volume": 0.15, "overflow": "trim" }
]
}Replace sound with narration and a timed effect
{
"media_id": "VIDEO_ID",
"original_audio_volume": 0,
"audio_tracks": [
{ "media_id": "NARRATION_ID", "start": 0, "volume": 1 },
{ "media_id": "EFFECT_ID", "start": 8.5, "volume": 0.6, "overflow": "trim" }
]
}Start response
{
"audio_render_id": "22222222-2222-4222-8222-222222222222",
"status": "processing",
"source_media_id": "11111111-1111-4111-8111-111111111111",
"status_url": "/api/v1/videos/audio/renders/22222222-2222-4222-8222-222222222222",
"created_at": "2026-09-05T10:00:00Z",
"remaining_credits": 42
}Get render status
GET /api/v1/videos/audio/renders/{id}
Scope: videos:read
Poll the returned status_url every 2–5 seconds until completed or failed, using the same workspace and API key headers.
{
"audio_render_id": "22222222-2222-4222-8222-222222222222",
"status": "completed",
"source_media_id": "11111111-1111-4111-8111-111111111111",
"output_media_id": "33333333-3333-4333-8333-333333333333",
"error": null,
"created_at": "2026-09-05T10:00:00Z",
"updated_at": "2026-09-05T10:00:10Z",
"video": {
"media_id": "33333333-3333-4333-8333-333333333333",
"url": "https://temporary-signed-url.example/output.mp4",
"thumbnail_url": "https://temporary-signed-url.example/thumb.jpg",
"file_name": "video-audio-33333333-3333-4333-8333-333333333333.mp4",
"file_size": 123456,
"mime_type": "video/mp4",
"width": 1080,
"height": 1920,
"duration": 30,
"created_at": "2026-09-05T10:00:10Z"
}
}While processing, video, output_media_id, and error are null. Failed jobs return error with code VIDEO_AUDIO_RENDER_FAILED and a message. If the source video is deleted, source_media_id can be null. If the output is deleted, video and output_media_id become null.
Store video.media_id; URLs are temporary. Use the output ID to add captions or create a post. This operation does not generate caption timing.
Errors and limits
| HTTP status | Meaning |
|---|---|
400 | Invalid fields, missing or wrong media types, media outside the workspace, unavailable storage paths, or invalid timing |
401 | Invalid API key |
402 | Prior purchase required or insufficient credits |
403 | Missing API scope |
404 | Render not found in this workspace |
429 | Rate limit exceeded: 30 starts or 120 status requests per minute per key |
Timing is checked against stored metadata before charging where available, and checked again against actual files in the worker. Unsupported files, missing assets, and overflow detected by the worker fail the job and refund the render credit.
MCP
| Tool | Purpose |
|---|---|
powerpost_render_video_audio | Start a render with the same body as the REST endpoint |
powerpost_get_video_audio_render | Poll using the render id; use video.media_id on completion |