Overlay user audio onto a video
Use this workflow when your customer has one video file and one audio file, and your product needs to publish a normal video with that audio already combined.
0.5.0 or later for this workflow. Starting in 0.5.0, the official SDKs no longer force callers to provide sizeBytes or size_bytes when reserving media uploads. Older SDK versions may still make your app calculate file size before calling POST/v1/media.When to use this guide
Use this guide when a user uploads a video plus a separate voiceover, music bed, narration, or other audio track. UniPost stores both inputs with POST/v1/media, creates an async processing job with POST/v1/media/audio-overlays, then publishes the returned output_media_id with POST/v1/posts.
The resulting asset is a normal video. That keeps the final publish flow predictable across platforms and avoids asking the user to understand platform-specific music-library restrictions.
Recommended product flow
| User-facing step | What your app should show | UniPost API work |
|---|---|---|
| Pick video and audio | Show two file slots: the base video and the audio to add. Make ownership or licensing expectations explicit before upload. | No API call yet. |
| Upload the video | Keep the UI in an upload state until the video is usable. File size is optional: provide it when your app already knows the byte length, or omit it when your app does not know it yet. | Reserve with POST/v1/media, upload bytes to the returned upload_url, then poll GET/v1/media/:media_id until the media is uploaded. The returned upload_url is not another UniPost JSON endpoint; it is the presigned file upload destination. |
| Upload the audio | Treat audio as an input file, not a publishable asset. Label it as the audio track for the generated video. | Use the same POST/v1/media upload flow with an audio MIME type such as audio/mpeg or audio/wav, then poll GET/v1/media/:media_id until the audio media is uploaded. |
| Choose audio behavior | Offer plain-language controls: keep original sound under the new audio, or replace the original sound entirely. | Send mode: "mix" or mode: "replace" to POST/v1/media/audio-overlays. |
| Generate processed video | Show a processing state with a retry-safe action. The user should not have to repeat uploads if processing is still running. | Poll the audio overlay job with GET /v1/media/audio-overlays/{id} until status is succeeded or failed. |
| Publish output | Use the generated video in the normal composer and make it clear this is the final video being posted. | Publish output_media_id through POST/v1/posts as a regular video media_id. |
Audio controls to expose
| User intent | API settings | UX copy |
|---|---|---|
| Add music or narration while keeping some original video sound | mode: "mix", lower video_volume, keep audio_volume near full volume. | Keep original sound |
| Replace the video's existing audio completely | mode: "replace". video_volume is ignored for the final output. | Replace original sound |
| Use only the beginning of a longer audio file | fit: "trim_to_video" | Stop audio at the end of the video |
| Repeat a short audio file until the video ends | fit: "loop_to_video" | Loop audio to match video length |
API steps
Step 1: Upload the video input
Reserve a video upload with POST/v1/media. File size is optional: provide it when your app already knows the byte length, or omit it when your app does not know it yet. UniPost hydrates size_bytes after the upload lands.
Upload the raw video bytes to the returned upload_url, then poll GET/v1/media/:media_id until the video is uploaded. The returned upload_url is not another UniPost JSON endpoint; it is the presigned destination for the actual file bytes.
Step 2: Upload the audio input
Reserve and upload the audio file with the same media upload flow and an audio MIME type such as audio/mpeg or audio/wav. Keep the returned audio media_id for processing only; do not publish the raw audio media as the post asset.
Step 3: Generate the overlay video
Create the audio overlay job with POST/v1/media/audio-overlays. Use mode: "mix" to keep some original video sound, or mode: "replace" to remove the original sound. Use an Idempotency-Key tied to the user's generate action so browser retries do not create duplicate jobs.
Poll GET /v1/media/audio-overlays/{id}. When status is succeeded, read output_media_id. That media ID points to the processed video that already contains the requested audio.
Step 4: Publish the processed video
Publish the final video by passing output_media_id in media_ids on POST/v1/posts. From the publish API's perspective, this is a regular video media asset.
Example workflow
Failure handling
Keep uploaded input media IDs so the user can retry processing without uploading the same files again. If the overlay job returns status: "failed", show the job error message, keep the selected audio settings visible, and let the user retry with the same video_media_id and audio_media_id.
If publishing fails after processing succeeds, do not rerun the overlay job. Reuse the same output_media_idand retry the publish flow according to the post error contract.