Requests overview
Most operations use JSON requests and Basic Auth. The typical flow is:
- Create a file to obtain an upload URL
- Upload the file bytes
- Submit a processing task referencing
file_path
See also: Quick Start, File Management, and Processing.
Input Object
options
: Array of FFmpeg input options applied before the input file- Format:
["-option", "value", "-another_option", "value"]
- Examples:
["-ss", "00:00:10"]
(seek to 10 seconds),["-t", "30"]
(duration of 30 seconds)
- Format:
file
: Filename that exactly matches the uploaded file parameter name
Output Object
options
: Array of FFmpeg output options applied to the output file- Format:
["-option", "value", "-another_option", "value"]
- Examples:
["-c:v", "libx264", "-crf", "23"]
(H.264 codec with quality 23)
- Format:
file
: Desired output filename (will be available for download)maps
: (Optional) Array of stream mapping specifiers- Format:
["input_index:stream_type:stream_index"]
- Examples:
["0:v"]
(video from first input),["1:a:2"]
(third audio track from second input) - Can also reference filter outputs:
["[filter_label]"]
- Format:
Filter Complex
filter_complex
: (Optional) FFmpeg filter graph for advanced video/audio processing- Used for operations like scaling, overlay, concatenation, side-by-side videos
- Filter outputs can be referenced in output
maps
using labels like[out]
- Example:
"[0:v]scale=1920:1080[v1];[1:v]scale=1920:1080[v2];[v1][v2]hstack[out]"
Example Requests (JSON workflow)
Basic GIF to MP4 Conversion
Request Data:
- File:
input.gif
(your GIF file) - Command:
{"inputs":[{"options":[],"file":"input.gif"}],"outputs":[{"options":[],"file":"output.mp4"}]}
Examples:
- curl
# 1) Get an upload URL
curl -sS -X POST https://api.ffmpeg-api.com/file \
-H 'Authorization: Basic YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"file_name":"input.gif"}'
# (capture $UPLOAD_URL and $FILE_PATH from the response)
# 2) Upload the bytes
curl -X PUT "$UPLOAD_URL" --data-binary @./input.gif
# 3) Process with file_path
curl -sS -X POST https://api.ffmpeg-api.com/ffmpeg/process \
-H 'Authorization: Basic YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"task":{"inputs":[{"file_path":"'$FILE_PATH'"}],"outputs":[{"file":"output.mp4"}]}}'
- JavaScript (Node)
const res = await fetch('https://api.ffmpeg-api.com/file', {
method: 'POST',
headers: { Authorization: `Basic ${API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ file_name: 'input.gif' })
});
const { file, upload } = await res.json();
await fetch(upload.url, { method: 'PUT', body: fs.readFileSync('./input.gif') });
await fetch('https://api.ffmpeg-api.com/ffmpeg/process', {
method: 'POST',
headers: { Authorization: `Basic ${API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ task: { inputs: [{ file_path: file.file_path }], outputs: [{ file: 'output.mp4' }] } })
});
Video with Custom Options
Request Data:
- File:
video.mp4
(your video file) - Command:
{"inputs":[{"options":["-ss","00:00:10","-t","30"],"file":"video.mp4"}],"outputs":[{"options":["-c:v","libx264","-crf","23"],"file":"output.mp4"}]}
Examples:
- curl
# 1) Get an upload URL
curl -sS -X POST https://api.ffmpeg-api.com/file \
-H 'Authorization: Basic YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"file_name":"video.mp4"}'
# 2) Upload
curl -X PUT "$UPLOAD_URL" --data-binary @./video.mp4
# 3) Process with input trimming and quality options
curl -sS -X POST https://api.ffmpeg-api.com/ffmpeg/process \
-H 'Authorization: Basic YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"task":{"inputs":[{"file_path":"'$FILE_PATH'","options":["-ss","00:00:10","-t","30"]}],"outputs":[{"file":"output.mp4","options":["-c:v","libx264","-crf","23"]}]}}'
- JavaScript (Node)
const fileRes = await fetch('https://api.ffmpeg-api.com/file', {
method: 'POST',
headers: { Authorization: `Basic ${API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ file_name: 'video.mp4' })
});
const { file, upload } = await fileRes.json();
await fetch(upload.url, { method: 'PUT', body: fs.readFileSync('./video.mp4') });
await fetch('https://api.ffmpeg-api.com/ffmpeg/process', {
method: 'POST',
headers: { Authorization: `Basic ${API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ task: { inputs: [{ file_path: file.file_path, options: ['-ss','00:00:10','-t','30'] }], outputs: [{ file: 'output.mp4', options: ['-c:v','libx264','-crf','23'] }] } })
});
Multiple Input Files
Request Data:
- Files:
video.mp4
,audio.mp3
- Command:
{"inputs":[{"options":[],"file":"video.mp4"},{"options":[],"file":"audio.mp3"}],"outputs":[{"options":["-c:v","copy","-c:a","aac"],"file":"output.mp4"}]}
Examples:
- curl
# 1) Get upload URLs for both files
curl -sS -X POST https://api.ffmpeg-api.com/file -H 'Authorization: Basic YOUR_API_KEY' -H 'Content-Type: application/json' -d '{"file_name":"video.mp4"}'
curl -sS -X POST https://api.ffmpeg-api.com/file -H 'Authorization: Basic YOUR_API_KEY' -H 'Content-Type: application/json' -d '{"file_name":"audio.mp3"}'
# 2) Upload each file
curl -X PUT "$UPLOAD_URL_VIDEO" --data-binary @./video.mp4
curl -X PUT "$UPLOAD_URL_AUDIO" --data-binary @./audio.mp3
# 3) Process by referencing both file_paths from step 1
curl -sS -X POST https://api.ffmpeg-api.com/ffmpeg/process \
-H 'Authorization: Basic YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"task":{"inputs":[{"file_path":"'$FILE_PATH_VIDEO'"},{"file_path":"'$FILE_PATH_AUDIO'"}],"outputs":[{"file":"output.mp4","options":["-c:v","copy","-c:a","aac"]}]}}'
- JavaScript (Node)
const v = await fetch('https://api.ffmpeg-api.com/file', { method:'POST', headers:{ Authorization:`Basic ${API_KEY}`, 'Content-Type':'application/json' }, body: JSON.stringify({ file_name:'video.mp4' }) }).then(r=>r.json());
const a = await fetch('https://api.ffmpeg-api.com/file', { method:'POST', headers:{ Authorization:`Basic ${API_KEY}`, 'Content-Type':'application/json' }, body: JSON.stringify({ file_name:'audio.mp3' }) }).then(r=>r.json());
await fetch(v.upload.url, { method:'PUT', body: fs.readFileSync('./video.mp4') });
await fetch(a.upload.url, { method:'PUT', body: fs.readFileSync('./audio.mp3') });
await fetch('https://api.ffmpeg-api.com/ffmpeg/process', {
method:'POST',
headers:{ Authorization:`Basic ${API_KEY}`, 'Content-Type':'application/json' },
body: JSON.stringify({ task: { inputs: [ { file_path: v.file.file_path }, { file_path: a.file.file_path } ], outputs: [ { file:'output.mp4', options:['-c:v','copy','-c:a','aac'] } ] } })
});
Stream Mapping with Maps
Extract specific streams from inputs into separate output files:
Request Data:
- File:
movie.mkv
(contains multiple video and audio tracks) - Command: Extract video-only and specific audio track
{
"inputs": [{"file": "movie.mkv", "options": []}],
"outputs": [
{
"options": ["-c:v", "libx264", "-crf", "23"],
"file": "video_only.mp4",
"maps": ["0:v:0"]
},
{
"options": ["-c:a", "aac", "-b:a", "128k"],
"file": "audio_track2.m4a",
"maps": ["0:a:1"]
}
]
}
Filter Complex for Side-by-Side Video
Combine two videos side by side using filter_complex:
Request Data:
- Files:
left_video.mp4
,right_video.mp4
- Command: Scale both videos and place them side by side
{
"task": {
"inputs": [
{"file_path": "<file_path_left>", "options": []},
{"file_path": "<file_path_right>", "options": []}
],
"filter_complex": "[0:v]scale=960:540[left];[1:v]scale=960:540[right];[left][right]hstack[out]",
"outputs": [
{
"file": "side_by_side.mp4",
"options": ["-c:v", "libx264", "-preset", "medium"],
"maps": ["[out]"]
}
]
}
}
Advanced Options Usage
Trimming and Quality Control:
{
"inputs": [
{
"file": "input.mp4",
"options": ["-ss", "00:01:30", "-t", "00:02:00"]
}
],
"outputs": [
{
"file": "trimmed_high_quality.mp4",
"options": [
"-c:v", "libx264",
"-crf", "18",
"-preset", "slow",
"-c:a", "aac",
"-b:a", "192k"
]
}
]
}
Multiple Output Formats:
{
"inputs": [{"file": "source.mp4", "options": []}],
"outputs": [
{
"file": "compressed.mp4",
"options": ["-c:v", "libx264", "-crf", "28", "-c:a", "aac"]
},
{
"file": "thumbnail.jpg",
"options": ["-vf", "scale=320:240", "-vframes", "1", "-ss", "00:00:05"]
}
]
}
File Upload Guidelines
File parameter names in the request must exactly match the file
field in your command’s inputs.
File Upload Requirements
- Parameter names: Must match the
file
field in your command inputs - File paths: Any accessible file path (implementation depends on your tool/language)
- Multiple files: Upload all files referenced in your command’s inputs
File Size Limits
- Maximum file size: 100MB per file (will be increased in the future)
Response Format
Success Response
{
"ok": true,
"result": [
{
"file_name": "output.mp4",
"size_bytes": 104897,
"download_url": "https://.../output.mp4?..."
}
],
"usage": { "time_sec": 12.5, "input_size_gb": 0.098, "output_size_gb": 0.015, "gb_sec": 1.4125 }
}
Response Fields:
ok
: Boolean indicating request successresult
: Array of output filesresult[].file
: Signed URL to download the processed file (valid for 1 hour)result[].size
: File size in bytes
Error Response
{
"ok": false,
"error": "Error message describing what went wrong"
}
Best Practices
Always validate your FFmpeg command locally before sending it to the API to avoid unnecessary usage charges.
Error Prevention
- Check file formats: Ensure input files are in supported formats
- Validate paths: Use absolute paths for file uploads
- Test commands: Validate FFmpeg syntax before API calls
- Handle timeouts: Implement retry logic for large file processing
Language-Specific Examples
Python (requests)
Basic conversion:
import requests
import json
files = {
'input.gif': open('/path/to/file.gif', 'rb'),
'command': (None, json.dumps({
"inputs": [{"options": [], "file": "input.gif"}],
"outputs": [{"options": [], "file": "output.mp4"}]
}))
}
headers = {
'Authorization': 'Basic YOUR_AUTH_KEY_HERE'
}
response = requests.post(
'https://api.ffmpeg-api.com/ffmpeg/run',
files=files,
headers=headers
)
result = response.json()
if result['ok']:
output_url = result['result'][0]['file']
print(f"Download your file: {output_url}")
Advanced example with stream mapping:
import requests
import json
# Extract audio track and create thumbnail
command = {
"inputs": [
{
"file": "movie.mp4",
"options": []
}
],
"outputs": [
{
"file": "audio_only.m4a",
"options": ["-c:a", "aac", "-b:a", "128k"],
"maps": ["0:a:0"]
},
{
"file": "thumbnail.jpg",
"options": ["-vf", "scale=320:240", "-vframes", "1", "-ss", "00:00:10"],
"maps": ["0:v:0"]
}
]
}
files = {
'movie.mp4': open('/path/to/movie.mp4', 'rb'),
'command': (None, json.dumps(command))
}
response = requests.post(
'https://api.ffmpeg-api.com/ffmpeg/run',
files=files,
headers={'Authorization': 'Basic YOUR_AUTH_KEY_HERE'}
)
result = response.json()
if result['ok']:
for output in result['result']:
print(f"Download: {output['file']} ({output['size']} bytes)")
JavaScript (Node.js)
Basic conversion:
const FormData = require('form-data');
const fs = require('fs');
const fetch = require('node-fetch');
const form = new FormData();
form.append('input.gif', fs.createReadStream('/path/to/file.gif'));
form.append('command', JSON.stringify({
inputs: [{ options: [], file: 'input.gif' }],
outputs: [{ options: [], file: 'output.mp4' }]
}));
const response = await fetch('https://api.ffmpeg-api.com/ffmpeg/run', {
method: 'POST',
headers: {
'Authorization': 'Basic YOUR_AUTH_KEY_HERE',
...form.getHeaders()
},
body: form
});
const result = await response.json();
if (result.ok) {
const outputUrl = result.result[0].file;
console.log(`Download your file: ${outputUrl}`);
}
Side-by-side video with filter_complex:
const FormData = require('form-data');
const fs = require('fs');
const fetch = require('node-fetch');
// Create side-by-side video using filter_complex
const command = {
inputs: [
{ file: 'video1.mp4', options: [] },
{ file: 'video2.mp4', options: [] }
],
filter_complex: '[0:v]scale=640:360[left];[1:v]scale=640:360[right];[left][right]hstack[out]',
outputs: [
{
file: 'combined.mp4',
options: ['-c:v', 'libx264', '-preset', 'medium', '-crf', '23'],
maps: ['[out]']
}
]
};
const form = new FormData();
form.append('video1.mp4', fs.createReadStream('/path/to/video1.mp4'));
form.append('video2.mp4', fs.createReadStream('/path/to/video2.mp4'));
form.append('command', JSON.stringify(command));
const response = await fetch('https://api.ffmpeg-api.com/ffmpeg/run', {
method: 'POST',
headers: {
'Authorization': 'Basic YOUR_AUTH_KEY_HERE',
...form.getHeaders()
},
body: form
});
const result = await response.json();
if (result.ok) {
console.log(`Combined video: ${result.result[0].file}`);
}
PHP
Basic conversion:
<?php
$ch = curl_init();
$postFields = [
'input.gif' => new CURLFile('/path/to/file.gif'),
'command' => json_encode([
'inputs' => [['options' => [], 'file' => 'input.gif']],
'outputs' => [['options' => [], 'file' => 'output.mp4']]
])
];
curl_setopt($ch, CURLOPT_URL, 'https://api.ffmpeg-api.com/ffmpeg/run');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Basic YOUR_AUTH_KEY_HERE'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$result = json_decode($response, true);
if ($result['ok']) {
$outputUrl = $result['result'][0]['file'];
echo "Download your file: " . $outputUrl;
}
curl_close($ch);
?>
Advanced example with stream mapping:
<?php
// Extract specific audio and video streams
$command = [
'inputs' => [
['file' => 'movie.mkv', 'options' => []]
],
'outputs' => [
[
'file' => 'video_only.mp4',
'options' => ['-c:v', 'libx264', '-crf', '23'],
'maps' => ['0:v:0']
],
[
'file' => 'audio_only.aac',
'options' => ['-c:a', 'aac', '-b:a', '128k'],
'maps' => ['0:a:1']
]
]
];
$ch = curl_init();
$postFields = [
'movie.mkv' => new CURLFile('/path/to/movie.mkv'),
'command' => json_encode($command)
];
curl_setopt($ch, CURLOPT_URL, 'https://api.ffmpeg-api.com/ffmpeg/run');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Basic YOUR_AUTH_KEY_HERE'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$result = json_decode($response, true);
if ($result['ok']) {
foreach ($result['result'] as $output) {
echo "Download: " . $output['file'] . " (" . $output['size'] . " bytes)\n";
}
}
curl_close($ch);
?>
Other Tools
HTTPie:
Basic conversion:
http --form POST https://api.ffmpeg-api.com/ffmpeg/run \
'Authorization:Basic YOUR_AUTH_KEY_HERE' \
input.gif@/path/to/file.gif \
command='{"inputs":[{"options":[],"file":"input.gif"}],"outputs":[{"options":[],"file":"output.mp4"}]}'
Video overlay with filter_complex:
http --form POST https://api.ffmpeg-api.com/ffmpeg/run \
'Authorization:Basic YOUR_AUTH_KEY_HERE' \
background.mp4@/path/to/background.mp4 \
overlay.png@/path/to/overlay.png \
command='{"inputs":[{"file":"background.mp4","options":[]},{"file":"overlay.png","options":["-loop","1"]}],"filter_complex":"[1:v]scale=200:100[ovrl];[0:v][ovrl]overlay=10:10[out]","outputs":[{"file":"result.mp4","options":["-c:v","libx264","-t","10"],"maps":["[out]"]}]}'
Postman:
- Method: POST
- URL:
https://api.ffmpeg-api.com/ffmpeg/run
- Headers:
Authorization: Basic YOUR_AUTH_KEY_HERE
- Body: form-data with file upload and command field
For more examples and use cases, check out our FFmpeg recipes section.