RenderIO
Getting started

Your First Command

Step-by-step guide to submitting an FFmpeg command, polling for results, and downloading output files.

Your First Command

This guide walks you through submitting an FFmpeg command, polling for results, and downloading output files. Before you begin, make sure you have your API key ready.

RenderIO processes FFmpeg commands in three steps:

  1. Submit -- POST your command with input and output file mappings
  2. Poll -- Check the command status until it completes
  3. Download -- Retrieve your output files from the storage URLs

Step 1: Submit a command

Send a POST request to the /api/v1/run-ffmpeg-command endpoint.

Request body

{
  "input_files": {
    "in_video": "https://example.com/sample.mp4"
  },
  "output_files": {
    "out_video": "converted.webm"
  },
  "ffmpeg_command": "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 {{out_video}}",
  "metadata": {
    "project": "marketing",
    "task": "web-optimization"
  },
  "webhook_url": "https://your-server.com/webhooks/renderio"
}

Field reference

FieldTypeRequiredDescription
input_filesobjectYesMap of aliases to source URLs. Each key must start with in_ (e.g. in_video, in_audio, in_watermark). Values are publicly accessible URLs to your source files.
output_filesobjectYesMap of aliases to output filenames. Each key must start with out_ (e.g. out_video, out_thumbnail). Values are the desired filenames for the output.
ffmpeg_commandstringYesThe FFmpeg command to execute. Use {{alias}} placeholders that match your input and output file keys. RenderIO replaces them with actual file paths at runtime.
metadataobjectNoArbitrary key-value pairs (up to 10 properties) attached to the command. Returned in poll responses and webhooks. Useful for tracking jobs in your system.
webhook_urlstringNoA URL to receive a POST request when this specific command completes. Overrides any account-level webhook configuration for this command.

Alias rules

  • Input file keys must start with in_ (e.g. in_video, in_audio)
  • Output file keys must start with out_ (e.g. out_video, out_thumb)
  • Keys must be alphanumeric with underscores only ([a-zA-Z0-9_])
  • Use the same alias names in your ffmpeg_command wrapped in double curly braces: {{in_video}}, {{out_video}}

Response

The API returns immediately with a command_id:

{
  "command_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

The FFmpeg processing runs asynchronously in the background. Your client does not need to keep the connection open.

Step 2: Poll for status

Send a GET request to /api/v1/commands/:commandId to check the status:

curl https://renderio.dev/api/v1/commands/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H "X-API-KEY: ffsk_your_api_key_here"

Command statuses

StatusDescription
QUEUEDCommand has been received and is waiting to be processed
PROCESSINGFFmpeg is currently running
SUCCESSCommand completed successfully, output files are available
FAILEDCommand failed, check error_status and error_message for details

Poll response (SUCCESS)

{
  "command_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "SUCCESS",
  "command_type": "FFMPEG_COMMAND",
  "total_processing_seconds": 4.21,
  "ffmpeg_command_run_seconds": 2.87,
  "metadata": {
    "project": "marketing",
    "task": "web-optimization"
  },
  "original_request": {
    "input_files": {
      "in_video": "https://example.com/sample.mp4"
    },
    "output_files": {
      "out_video": "converted.webm"
    },
    "ffmpeg_command": "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 {{out_video}}"
  },
  "output_files": {
    "out_video": {
      "file_id": "f1a2b3c4-d5e6-7890-abcd-ef1234567890",
      "storage_url": "https://storage.renderio.dev/files/f1a2b3c4...",
      "status": "STORED",
      "rendi_store_type": "OUTPUT",
      "is_deleted": false,
      "filename": "converted.webm",
      "size_mbytes": 2.34,
      "duration": 15.0,
      "file_type": "video",
      "file_format": "webm",
      "codec": "vp9",
      "mime_type": "video/webm",
      "width": 1920,
      "height": 1080,
      "frame_rate": 30,
      "bitrate_video_kb": 1280
    }
  }
}

Poll response (FAILED)

{
  "command_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "FAILED",
  "command_type": "FFMPEG_COMMAND",
  "error_status": "FFMPEG_ERROR",
  "error_message": "Invalid codec specified",
  "original_request": {
    "input_files": { "in_video": "https://example.com/sample.mp4" },
    "output_files": { "out_video": "converted.webm" },
    "ffmpeg_command": "ffmpeg -i {{in_video}} -c:v invalid_codec {{out_video}}"
  }
}

Step 3: Download output files

Each entry in output_files includes a storage_url. Use it to download the file directly:

curl -o converted.webm "https://storage.renderio.dev/files/f1a2b3c4..."

The storage_url is a pre-signed URL that provides temporary access to your file.

Full code examples

# Submit
COMMAND_ID=$(curl -s -X POST https://renderio.dev/api/v1/run-ffmpeg-command \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: $RENDERIO_API_KEY" \
  -d '{
    "input_files": { "in_video": "https://example.com/sample.mp4" },
    "output_files": { "out_video": "converted.webm" },
    "ffmpeg_command": "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 {{out_video}}"
  }' | jq -r '.command_id')

# Poll
while true; do
  RESULT=$(curl -s https://renderio.dev/api/v1/commands/$COMMAND_ID \
    -H "X-API-KEY: $RENDERIO_API_KEY")
  STATUS=$(echo $RESULT | jq -r '.status')
  echo "Status: $STATUS"
  if [ "$STATUS" = "SUCCESS" ] || [ "$STATUS" = "FAILED" ]; then break; fi
  sleep 2
done

# Download
DOWNLOAD_URL=$(echo $RESULT | jq -r '.output_files.out_video.storage_url')
curl -o converted.webm "$DOWNLOAD_URL"
import os
import time
import requests

API_KEY = os.environ["RENDERIO_API_KEY"]
BASE_URL = "https://api.renderio.dev"

# 1. Submit the command
submit_response = requests.post(
    f"{BASE_URL}/api/v1/run-ffmpeg-command",
    headers={
        "Content-Type": "application/json",
        "X-API-KEY": API_KEY,
    },
    json={
        "input_files": {"in_video": "https://example.com/sample.mp4"},
        "output_files": {"out_video": "converted.webm"},
        "ffmpeg_command": "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 {{out_video}}",
    },
)

command_id = submit_response.json()["command_id"]
print(f"Command ID: {command_id}")

# 2. Poll for results
while True:
    poll_response = requests.get(
        f"{BASE_URL}/api/v1/commands/{command_id}",
        headers={"X-API-KEY": API_KEY},
    )
    result = poll_response.json()
    print(f"Status: {result['status']}")

    if result["status"] in ("SUCCESS", "FAILED"):
        break
    time.sleep(2)

# 3. Download the output
if result["status"] == "SUCCESS":
    file_url = result["output_files"]["out_video"]["storage_url"]
    print(f"Download URL: {file_url}")

    download = requests.get(file_url)
    with open("converted.webm", "wb") as f:
        f.write(download.content)
    print("File saved to converted.webm")
const API_KEY: string = process.env.RENDERIO_API_KEY!;
const BASE_URL = "https://api.renderio.dev";

interface SubmitResponse {
  command_id: string;
}

interface OutputFile {
  file_id: string;
  storage_url: string;
  status: string;
  filename: string;
  size_mbytes: number;
}

interface CommandResult {
  command_id: string;
  status: "QUEUED" | "PROCESSING" | "SUCCESS" | "FAILED";
  output_files: Record<string, OutputFile>;
}

// 1. Submit the command
const submitResponse = await fetch(`${BASE_URL}/api/v1/run-ffmpeg-command`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-KEY": API_KEY,
  },
  body: JSON.stringify({
    input_files: { in_video: "https://example.com/sample.mp4" },
    output_files: { out_video: "converted.webm" },
    ffmpeg_command:
      "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 {{out_video}}",
  }),
});

const { command_id } = (await submitResponse.json()) as SubmitResponse;
console.log("Command ID:", command_id);

// 2. Poll for results
let result: CommandResult;
while (true) {
  const pollResponse = await fetch(
    `${BASE_URL}/api/v1/commands/${command_id}`,
    { headers: { "X-API-KEY": API_KEY } },
  );
  result = (await pollResponse.json()) as CommandResult;
  console.log("Status:", result.status);

  if (result.status === "SUCCESS" || result.status === "FAILED") break;
  await new Promise((resolve) => setTimeout(resolve, 2000));
}

// 3. Download the output
if (result.status === "SUCCESS") {
  const fileUrl = result.output_files.out_video.storage_url;
  console.log("Download URL:", fileUrl);
}
const API_KEY = process.env.RENDERIO_API_KEY;
const BASE_URL = "https://api.renderio.dev";

// 1. Submit the command
const submitResponse = await fetch(`${BASE_URL}/api/v1/run-ffmpeg-command`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-KEY": API_KEY,
  },
  body: JSON.stringify({
    input_files: { in_video: "https://example.com/sample.mp4" },
    output_files: { out_video: "converted.webm" },
    ffmpeg_command:
      "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 {{out_video}}",
  }),
});

const { command_id } = await submitResponse.json();
console.log("Command ID:", command_id);

// 2. Poll for results
let result;
while (true) {
  const pollResponse = await fetch(
    `${BASE_URL}/api/v1/commands/${command_id}`,
    { headers: { "X-API-KEY": API_KEY } },
  );
  result = await pollResponse.json();
  console.log("Status:", result.status);

  if (result.status === "SUCCESS" || result.status === "FAILED") break;
  await new Promise((resolve) => setTimeout(resolve, 2000));
}

// 3. Download the output
if (result.status === "SUCCESS") {
  const fileUrl = result.output_files.out_video.storage_url;
  console.log("Download URL:", fileUrl);
}
<?php
$apiKey = getenv("RENDERIO_API_KEY");
$baseUrl = "https://api.renderio.dev";

// 1. Submit the command
$ch = curl_init("$baseUrl/api/v1/run-ffmpeg-command");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Content-Type: application/json",
    "X-API-KEY: $apiKey",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    "input_files" => ["in_video" => "https://example.com/sample.mp4"],
    "output_files" => ["out_video" => "converted.webm"],
    "ffmpeg_command" => "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 {{out_video}}",
]));
$submitResult = json_decode(curl_exec($ch), true);
curl_close($ch);

$commandId = $submitResult["command_id"];
echo "Command ID: $commandId\n";

// 2. Poll for results
while (true) {
    $ch = curl_init("$baseUrl/api/v1/commands/$commandId");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-KEY: $apiKey"]);
    $result = json_decode(curl_exec($ch), true);
    curl_close($ch);

    echo "Status: " . $result["status"] . "\n";
    if (in_array($result["status"], ["SUCCESS", "FAILED"])) break;
    sleep(2);
}

// 3. Download the output
if ($result["status"] === "SUCCESS") {
    $fileUrl = $result["output_files"]["out_video"]["storage_url"];
    echo "Download URL: $fileUrl\n";

    file_put_contents("converted.webm", file_get_contents($fileUrl));
    echo "File saved to converted.webm\n";
}

Next steps

On this page