RenderIO
Guides

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:

  1. Each command is independent with its own input_files, output_files, and ffmpeg_command
  2. Commands run in parallel in separate sandboxes
  3. Each command gets its own command_id
  4. The response returns an array of command_ids to poll individually
  5. 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 metadata object, making it easy to track which result corresponds to which job in your system.
  • Webhooks: Configure a webhook_url on 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.

Further reading

On this page