Batch Processing
Process multiple files in parallel with the multiple commands endpoint.
Batch Processing
When you need to process several files independently, RenderIO's multiple commands endpoint lets you submit up to 10 commands in a single request. Each command runs in its own sandbox in parallel, making it much faster than submitting them one at a time.
How batch processing works
When you submit multiple commands:
- Each command is independent with its own
input_files,output_files, andffmpeg_command - Commands run in parallel in separate sandboxes
- Each command gets its own
command_id - The response returns an array of
command_idsto poll individually - Commands succeed or fail independently of each other
Use POST /api/v1/run-multiple-ffmpeg-commands with a commands array containing individual command objects.
Example: Convert videos to multiple formats
Convert the same source video to three different formats simultaneously.
curl -X POST https://renderio.dev/api/v1/run-multiple-ffmpeg-commands \
-H "Content-Type: application/json" \
-H "X-API-KEY: ffsk_your_api_key_here" \
-d '{
"commands": [
{
"input_files": {
"in_video": "https://example.com/source.mp4"
},
"output_files": {
"out_video": "output.webm"
},
"ffmpeg_command": "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}"
},
{
"input_files": {
"in_video": "https://example.com/source.mp4"
},
"output_files": {
"out_video": "output.mov"
},
"ffmpeg_command": "ffmpeg -i {{in_video}} -c:v libx264 -c:a aac {{out_video}}"
},
{
"input_files": {
"in_video": "https://example.com/source.mp4"
},
"output_files": {
"out_video": "output_720p.mp4"
},
"ffmpeg_command": "ffmpeg -i {{in_video}} -vf \"scale=1280:720\" -c:v libx264 -c:a aac {{out_video}}"
}
]
}'import requests
response = requests.post(
"https://renderio.dev/api/v1/run-multiple-ffmpeg-commands",
headers={
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
json={
"commands": [
{
"input_files": {"in_video": "https://example.com/source.mp4"},
"output_files": {"out_video": "output.webm"},
"ffmpeg_command": "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}",
},
{
"input_files": {"in_video": "https://example.com/source.mp4"},
"output_files": {"out_video": "output.mov"},
"ffmpeg_command": "ffmpeg -i {{in_video}} -c:v libx264 -c:a aac {{out_video}}",
},
{
"input_files": {"in_video": "https://example.com/source.mp4"},
"output_files": {"out_video": "output_720p.mp4"},
"ffmpeg_command": 'ffmpeg -i {{in_video}} -vf "scale=1280:720" -c:v libx264 -c:a aac {{out_video}}',
},
],
},
)
data = response.json()
print("Command IDs:", data["command_ids"])interface MultipleCommandsResponse {
command_ids: string[];
}
const response = await fetch(
"https://renderio.dev/api/v1/run-multiple-ffmpeg-commands",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
body: JSON.stringify({
commands: [
{
input_files: { in_video: "https://example.com/source.mp4" },
output_files: { out_video: "output.webm" },
ffmpeg_command:
"ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}",
},
{
input_files: { in_video: "https://example.com/source.mp4" },
output_files: { out_video: "output.mov" },
ffmpeg_command:
"ffmpeg -i {{in_video}} -c:v libx264 -c:a aac {{out_video}}",
},
{
input_files: { in_video: "https://example.com/source.mp4" },
output_files: { out_video: "output_720p.mp4" },
ffmpeg_command:
'ffmpeg -i {{in_video}} -vf "scale=1280:720" -c:v libx264 -c:a aac {{out_video}}',
},
],
}),
},
);
const { command_ids } = (await response.json()) as MultipleCommandsResponse;
console.log("Command IDs:", command_ids);const response = await fetch(
"https://renderio.dev/api/v1/run-multiple-ffmpeg-commands",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
body: JSON.stringify({
commands: [
{
input_files: { in_video: "https://example.com/source.mp4" },
output_files: { out_video: "output.webm" },
ffmpeg_command:
"ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}",
},
{
input_files: { in_video: "https://example.com/source.mp4" },
output_files: { out_video: "output.mov" },
ffmpeg_command:
"ffmpeg -i {{in_video}} -c:v libx264 -c:a aac {{out_video}}",
},
{
input_files: { in_video: "https://example.com/source.mp4" },
output_files: { out_video: "output_720p.mp4" },
ffmpeg_command:
'ffmpeg -i {{in_video}} -vf "scale=1280:720" -c:v libx264 -c:a aac {{out_video}}',
},
],
}),
},
);
const { command_ids } = await response.json();
console.log("Command IDs:", command_ids);<?php
$ch = curl_init("https://renderio.dev/api/v1/run-multiple-ffmpeg-commands");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Content-Type: application/json",
"X-API-KEY: ffsk_your_api_key_here",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"commands" => [
[
"input_files" => ["in_video" => "https://example.com/source.mp4"],
"output_files" => ["out_video" => "output.webm"],
"ffmpeg_command" => "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}",
],
[
"input_files" => ["in_video" => "https://example.com/source.mp4"],
"output_files" => ["out_video" => "output.mov"],
"ffmpeg_command" => "ffmpeg -i {{in_video}} -c:v libx264 -c:a aac {{out_video}}",
],
[
"input_files" => ["in_video" => "https://example.com/source.mp4"],
"output_files" => ["out_video" => "output_720p.mp4"],
"ffmpeg_command" => 'ffmpeg -i {{in_video}} -vf "scale=1280:720" -c:v libx264 -c:a aac {{out_video}}',
],
],
]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo "Command IDs: " . implode(", ", $data["command_ids"]) . "\n";Response
The API returns an array of command IDs, one for each command in the batch:
{
"command_ids": [
"a1b2c3d4-0000-0000-0000-000000000001",
"a1b2c3d4-0000-0000-0000-000000000002",
"a1b2c3d4-0000-0000-0000-000000000003"
]
}Polling for results
Each command in the batch has its own command_id and must be polled individually. Commands complete independently, so some may finish before others.
# Poll each command separately
curl https://renderio.dev/api/v1/commands/a1b2c3d4-0000-0000-0000-000000000001 \
-H "X-API-KEY: ffsk_your_api_key_here"
curl https://renderio.dev/api/v1/commands/a1b2c3d4-0000-0000-0000-000000000002 \
-H "X-API-KEY: ffsk_your_api_key_here"
curl https://renderio.dev/api/v1/commands/a1b2c3d4-0000-0000-0000-000000000003 \
-H "X-API-KEY: ffsk_your_api_key_here"Example: Process different source files
Batch processing is not limited to the same source. Each command can have completely different inputs and operations.
curl -X POST https://renderio.dev/api/v1/run-multiple-ffmpeg-commands \
-H "Content-Type: application/json" \
-H "X-API-KEY: ffsk_your_api_key_here" \
-d '{
"commands": [
{
"input_files": {
"in_video": "https://example.com/video-a.mp4"
},
"output_files": {
"out_thumbnail": "thumb-a.jpg"
},
"ffmpeg_command": "ffmpeg -ss 00:00:05 -i {{in_video}} -frames:v 1 {{out_thumbnail}}"
},
{
"input_files": {
"in_video": "https://example.com/video-b.mp4"
},
"output_files": {
"out_audio": "audio-b.mp3"
},
"ffmpeg_command": "ffmpeg -i {{in_video}} -vn -c:a libmp3lame -q:a 2 {{out_audio}}"
}
]
}'import requests
response = requests.post(
"https://renderio.dev/api/v1/run-multiple-ffmpeg-commands",
headers={
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
json={
"commands": [
{
"input_files": {"in_video": "https://example.com/video-a.mp4"},
"output_files": {"out_thumbnail": "thumb-a.jpg"},
"ffmpeg_command": "ffmpeg -ss 00:00:05 -i {{in_video}} -frames:v 1 {{out_thumbnail}}",
},
{
"input_files": {"in_video": "https://example.com/video-b.mp4"},
"output_files": {"out_audio": "audio-b.mp3"},
"ffmpeg_command": "ffmpeg -i {{in_video}} -vn -c:a libmp3lame -q:a 2 {{out_audio}}",
},
],
},
)
data = response.json()
print("Command IDs:", data["command_ids"])interface MultipleCommandsResponse {
command_ids: string[];
}
const response = await fetch(
"https://renderio.dev/api/v1/run-multiple-ffmpeg-commands",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
body: JSON.stringify({
commands: [
{
input_files: { in_video: "https://example.com/video-a.mp4" },
output_files: { out_thumbnail: "thumb-a.jpg" },
ffmpeg_command:
"ffmpeg -ss 00:00:05 -i {{in_video}} -frames:v 1 {{out_thumbnail}}",
},
{
input_files: { in_video: "https://example.com/video-b.mp4" },
output_files: { out_audio: "audio-b.mp3" },
ffmpeg_command:
"ffmpeg -i {{in_video}} -vn -c:a libmp3lame -q:a 2 {{out_audio}}",
},
],
}),
},
);
const { command_ids } = (await response.json()) as MultipleCommandsResponse;
console.log("Command IDs:", command_ids);const response = await fetch(
"https://renderio.dev/api/v1/run-multiple-ffmpeg-commands",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
body: JSON.stringify({
commands: [
{
input_files: { in_video: "https://example.com/video-a.mp4" },
output_files: { out_thumbnail: "thumb-a.jpg" },
ffmpeg_command:
"ffmpeg -ss 00:00:05 -i {{in_video}} -frames:v 1 {{out_thumbnail}}",
},
{
input_files: { in_video: "https://example.com/video-b.mp4" },
output_files: { out_audio: "audio-b.mp3" },
ffmpeg_command:
"ffmpeg -i {{in_video}} -vn -c:a libmp3lame -q:a 2 {{out_audio}}",
},
],
}),
},
);
const { command_ids } = await response.json();
console.log("Command IDs:", command_ids);<?php
$ch = curl_init("https://renderio.dev/api/v1/run-multiple-ffmpeg-commands");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Content-Type: application/json",
"X-API-KEY: ffsk_your_api_key_here",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"commands" => [
[
"input_files" => ["in_video" => "https://example.com/video-a.mp4"],
"output_files" => ["out_thumbnail" => "thumb-a.jpg"],
"ffmpeg_command" => "ffmpeg -ss 00:00:05 -i {{in_video}} -frames:v 1 {{out_thumbnail}}",
],
[
"input_files" => ["in_video" => "https://example.com/video-b.mp4"],
"output_files" => ["out_audio" => "audio-b.mp3"],
"ffmpeg_command" => "ffmpeg -i {{in_video}} -vn -c:a libmp3lame -q:a 2 {{out_audio}}",
],
],
]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo "Command IDs: " . implode(", ", $data["command_ids"]) . "\n";This batch extracts a thumbnail from one video and extracts audio from a completely different video, all in a single API call.
Tips and variations
- Maximum 10 commands: A single batch request can contain up to 10 commands. For larger batches, split them into multiple API calls.
- Independent execution: Each command runs in its own isolated sandbox. They do not share files or state. If one command fails, the others continue processing normally.
- Independent timeouts: Each command has its own timeout, determined by your subscription plan.
- Per-command metadata: Each command in the batch can have its own
metadataobject, making it easy to track which result corresponds to which job in your system. - Webhooks: Configure a
webhook_urlon individual commands within the batch to receive notifications as each one completes separately. - Batch vs. chained: Use batch (
run-multiple-ffmpeg-commands) when commands are independent and can run in parallel. Use chained (run-chained-ffmpeg-commands) when commands need to run sequentially and share intermediate files.
Related guides
- Chained Workflow -- run sequential commands that share intermediate files
- Command Types -- when to use single, chained, or multiple commands
Further reading
- FFmpeg as a Service -- how API-based batch processing compares to local scripts
- FFmpeg API Python Guide -- Python examples for batch video processing
- FFmpeg API Node.js Guide -- Node.js examples for batch processing