Complete guide to using the FFMPEG Video Processing API
The FFMPEG Video Merger API provides three powerful video processing capabilities:
Create videos by combining static images with audio files
Concatenate multiple videos from URLs into one seamless video
Overlay one video on top of another with customizable positioning
https://ffmpegapi.net/api/
All API endpoints require authentication using API keys. You can provide your API key in three ways:
X-API-Key: your_api_key_here
?api_key=your_api_key_here
api_key=your_api_key_here
For long-running video processing tasks that may take several minutes, you can use async processing to avoid timeouts and improve user experience.
"async": true
to your request JSON to process jobs in the background. You'll receive a job_id
immediately and can check progress using the job status endpoint.
Status | Description |
---|---|
pending | Job is queued and waiting to be processed |
processing | Job is currently being processed |
completed | Job finished successfully, download URL available |
failed | Job failed, error message available |
/api/merge_image_audio
Create a video by combining a static image with an audio file from URLs. The image will be displayed for the duration of the audio. Supports async processing for large files.
Content-Type: application/json
Parameter | Type | Required | Description |
---|---|---|---|
image |
String | Yes | URL to image file (PNG, JPG, JPEG) |
audio |
String | Yes | URL to audio file (MP3, WAV, M4A) |
async |
Boolean | No | Process job asynchronously (default: false) |
{
"image": "https://example.com/image.jpg",
"audio": "https://example.com/audio.mp3",
"async": true
}
{
"success": true,
"message": "Video created successfully",
"download_url": "https://ffmpegapi.net/download/filename.mp4",
"filename": "unique_filename.mp4"
}
{
"success": true,
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"message": "Job submitted for async processing. Use /api/job/{job_id}/status to check progress.",
"status_url": "https://ffmpegapi.net/api/job/550e8400-e29b-41d4-a716-446655440000/status"
}
/api/merge_videos
Concatenate multiple videos from URLs into a single video. All videos should have the same aspect ratio for best results.
Content-Type: application/json
Parameter | Type | Required | Description |
---|---|---|---|
video_urls |
Array | Yes | Array of video URLs (minimum 2 required) |
audio_url |
String | No | Optional audio URL to replace original audio |
async |
Boolean | No | Process job asynchronously (default: false) |
{
"video_urls": [
"https://example.com/video1.mp4",
"https://example.com/video2.mp4",
"https://example.com/video3.mp4"
],
"audio_url": "https://example.com/audio.mp3",
"async": true
}
{
"success": true,
"message": "Videos merged successfully",
"download_url": "https://ffmpegapi.net/download/merged_filename.mp4",
"filename": "unique_merged_filename.mp4"
}
{
"success": true,
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"message": "Job submitted for async processing. Use /api/job/{job_id}/status to check progress.",
"status_url": "https://ffmpegapi.net/api/job/550e8400-e29b-41d4-a716-446655440000/status"
}
/api/picture_in_picture
Create a picture-in-picture video by overlaying one video on top of another with customizable positioning and scaling.
Content-Type: application/json
Parameter | Type | Required | Description |
---|---|---|---|
main_video_url |
String | Yes | URL of the main background video |
pip_video_url |
String | Yes | URL of the video to overlay (picture-in-picture) |
position |
String | No | Position of overlay. Options: top-left, top-center, top-right, middle-left, middle, middle-right, bottom-left, bottom-center, bottom-right. Default: bottom-right |
scale |
String | No | Scale of overlay video. Options: iw/4:ih/4 (quarter), iw/3:ih/3 (third), iw/2:ih/2 (half). Default: iw/4:ih/4 |
audio_option |
String | No | Audio source for final video. Options: video1 (main video audio), video2 (overlay video audio), mute (no audio). Default: video1 |
async |
Boolean | No | Process job asynchronously (default: false) |
{
"main_video_url": "https://example.com/main-video.mp4",
"pip_video_url": "https://example.com/overlay-video.mp4",
"position": "top-right",
"scale": "iw/3:ih/3",
"audio_option": "video2",
"async": true
}
{
"success": true,
"message": "Picture-in-picture video created successfully",
"download_url": "https://ffmpegapi.net/download/pip_filename.mp4",
"filename": "unique_pip_filename.mp4"
}
{
"success": true,
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"message": "Job submitted for async processing. Use /api/job/{job_id}/status to check progress.",
"status_url": "https://ffmpegapi.net/api/job/550e8400-e29b-41d4-a716-446655440000/status"
}
/api/job/{job_id}/status
Check the status of an asynchronous job. Use this endpoint to monitor the progress of jobs submitted with async: true
.
Parameter | Type | Required | Description |
---|---|---|---|
job_id |
String | Yes | Job ID returned when submitting async request |
curl -X GET "https://ffmpegapi.net/api/job/550e8400-e29b-41d4-a716-446655440000/status" \
-H "X-API-Key: your_api_key_here"
{
"success": true,
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"job_type": "merge_image_audio",
"status": "pending",
"created_at": "2025-08-19T22:00:00.000Z",
"updated_at": "2025-08-19T22:00:00.000Z"
}
{
"success": true,
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"job_type": "merge_image_audio",
"status": "processing",
"created_at": "2025-08-19T22:00:00.000Z",
"updated_at": "2025-08-19T22:01:30.000Z"
}
{
"success": true,
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"job_type": "merge_image_audio",
"status": "completed",
"created_at": "2025-08-19T22:00:00.000Z",
"updated_at": "2025-08-19T22:03:45.000Z",
"message": "Video created successfully",
"download_url": "https://ffmpegapi.net/download/filename.mp4",
"filename": "unique_filename.mp4"
}
{
"success": true,
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"job_type": "merge_image_audio",
"status": "failed",
"created_at": "2025-08-19T22:00:00.000Z",
"updated_at": "2025-08-19T22:02:15.000Z",
"error": "Failed to download image: Invalid URL"
}
All endpoints return consistent error responses with appropriate HTTP status codes.
{
"success": false,
"error": "API key is required"
}
{
"success": false,
"error": "Both image and audio files are required"
}
{
"success": false,
"error": "File too large. Maximum file size is 100MB."
}
{
"success": false,
"error": "FFMPEG processing failed: [details]"
}
curl -X POST "https://ffmpegapi.net/api/merge_image_audio" \
-H "X-API-Key: your_api_key_here" \
-F "image=@/path/to/image.jpg" \
-F "audio=@/path/to/audio.mp3"
curl -X POST "https://ffmpegapi.net/api/merge_videos" \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key_here" \
-d '{
"video_urls": [
"https://example.com/video1.mp4",
"https://example.com/video2.mp4"
]
}'
curl -X POST "https://ffmpegapi.net/api/picture_in_picture" \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key_here" \
-d '{
"main_video_url": "https://example.com/main.mp4",
"pip_video_url": "https://example.com/overlay.mp4",
"position": "top-right",
"scale": "iw/4:ih/4"
}'
import requests
url = "https://ffmpegapi.net/api/merge_image_audio"
headers = {"X-API-Key": "your_api_key_here"}
with open("image.jpg", "rb") as img, open("audio.mp3", "rb") as aud:
files = {
"image": img,
"audio": aud
}
response = requests.post(url, headers=headers, files=files)
if response.status_code == 200:
result = response.json()
download_url = result["download_url"]
print(f"Video created: {download_url}")
else:
print(f"Error: {response.json()['error']}")
import requests
import json
url = "https://ffmpegapi.net/api/merge_videos"
headers = {
"Content-Type": "application/json",
"X-API-Key": "your_api_key_here"
}
data = {
"video_urls": [
"https://example.com/video1.mp4",
"https://example.com/video2.mp4"
]
}
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
result = response.json()
download_url = result["download_url"]
print(f"Videos merged: {download_url}")
else:
print(f"Error: {response.json()['error']}")
import requests
url = "https://ffmpegapi.net/api/picture_in_picture"
headers = {
"Content-Type": "application/json",
"X-API-Key": "your_api_key_here"
}
data = {
"main_video_url": "https://example.com/main.mp4",
"pip_video_url": "https://example.com/overlay.mp4",
"position": "top-right",
"scale": "iw/4:ih/4"
}
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
result = response.json()
download_url = result["download_url"]
print(f"PiP video created: {download_url}")
else:
print(f"Error: {response.json()['error']}")
const formData = new FormData();
formData.append('image', imageFile);
formData.append('audio', audioFile);
const response = await fetch('https://ffmpegapi.net/api/merge_image_audio', {
method: 'POST',
headers: {
'X-API-Key': 'your_api_key_here'
},
body: formData
});
const result = await response.json();
if (result.success) {
console.log('Video created:', result.download_url);
} else {
console.error('Error:', result.error);
}
const data = {
video_urls: [
'https://example.com/video1.mp4',
'https://example.com/video2.mp4'
]
};
const response = await fetch('https://ffmpegapi.net/api/merge_videos', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your_api_key_here'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
console.log('Videos merged:', result.download_url);
} else {
console.error('Error:', result.error);
}
const data = {
main_video_url: 'https://example.com/main.mp4',
pip_video_url: 'https://example.com/overlay.mp4',
position: 'top-right',
scale: 'iw/4:ih/4',
audio_option: 'video1' // Options: 'video1', 'video2', 'mute'
};
const response = await fetch('https://ffmpegapi.net/api/picture_in_picture', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your_api_key_here'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
console.log('PiP video created:', result.download_url);
} else {
console.error('Error:', result.error);
}
Need help? Questions about the API? try the web interface first.