Run Chained Commands
Submit up to 20 FFmpeg commands on the Business plan. They execute sequentially, and outputs from earlier steps are available as inputs to later steps.
Run Chained Commands
POST /api/v1/run-chained-ffmpeg-commandsSubmit multiple FFmpeg commands that execute sequentially in a single sandbox. Each command runs after the previous one completes, and outputs from earlier steps are available as inputs to later steps. This is useful for multi-pass encoding, extracting frames then compositing, or any workflow that requires ordered processing.
Authentication
Requires API key via X-API-KEY header.
Request
Headers
| Header | Type | Required | Description |
|---|---|---|---|
Content-Type | string | Yes | Must be application/json |
X-API-KEY | string | Yes | Your API key with ffsk_ prefix |
Body
interface RunChainedCommandsRequest {
input_files: Record<string, string>; // in_* aliases mapped to URLs
output_files: Record<string, string>; // out_* aliases mapped to filenames
ffmpeg_commands: string[]; // Up to 20 per plan, executed sequentially
metadata?: Record<string, string | number | boolean>; // Max 10 keys
webhook_url?: string; // Per-command webhook override
storage_destination_id?: string; // Business: send outputs to your S3-compatible bucket
}| Field | Type | Required | Description |
|---|---|---|---|
input_files | Record<string, string> | Yes | Map of alias names (must start with in_) to file URLs. |
output_files | Record<string, string> | Yes | Map of alias names (must start with out_) to output filenames. |
ffmpeg_commands | string[] | Yes | Array of FFmpeg commands to execute in order. Maximum 20 commands (Business plan; lower plans enforce a smaller per-plan limit). Use {{alias}} placeholders to reference files. |
metadata | Record<string, string | number | boolean> | No | Arbitrary key-value metadata attached to the command. Maximum 10 keys. |
webhook_url | string | No | URL to receive a POST request when all commands complete. Overrides any account-level webhook configuration. Requires the Business plan. |
storage_destination_id | string | No | Send final outputs to this S3-compatible storage destination. Requires the Business plan. |
Response
200 OK
{
command_id: string;
}| Field | Type | Description |
|---|---|---|
command_id | string | Unique identifier for the chained command. Use this to poll for status. |
Retrieve the outputs
Poll GET /api/v1/commands/:commandId until status is SUCCESS or FAILED. Managed outputs provide storage_url. BYOB outputs also provide the persistent external_uri and external_object_key; a private bucket has storage_url: null. See Bring Your Own Bucket.
Error responses
| Status | Error | Description |
|---|---|---|
400 | INVALID_REQUEST | Missing required fields, invalid aliases, or malformed FFmpeg commands. |
401 | UNAUTHORIZED | Missing or invalid API key. |
403 | FORBIDDEN | The request exceeds the plan's chained-command limit, or a Business-only webhook or storage destination was requested by an ineligible account. |
404 | NOT_FOUND | The supplied storage destination does not exist or belongs to another account. |
409 | CONFLICT | The supplied storage destination is disabled. |
422 | VALIDATION_ERROR | Validation failed, such as excessive metadata or a malformed storage_destination_id. |
429 | RATE_LIMITED | Too many requests. Retry after the period indicated in the Retry-After header. |
Examples
curl -X POST https://renderio.dev/api/v1/run-chained-ffmpeg-commands \
-H "Content-Type: application/json" \
-H "X-API-KEY: ffsk_your_api_key_here" \
-d '{
"input_files": {
"in_video": "https://example.com/sample.mp4"
},
"output_files": {
"out_video": "final.mp4"
},
"ffmpeg_commands": [
"ffmpeg -i {{in_video}} -vf scale=1280:720 -c:v libx264 -preset fast intermediate.mp4",
"ffmpeg -i intermediate.mp4 -af loudnorm -c:v copy {{out_video}}"
]
}'curl -X POST https://renderio.dev/api/v1/run-chained-ffmpeg-commands \
-H "Content-Type: application/json" \
-H "X-API-KEY: ffsk_your_api_key_here" \
-d '{
"input_files": {
"in_video": "https://example.com/sample.mp4"
},
"output_files": {
"out_video": "final.mp4"
},
"ffmpeg_commands": [
"ffmpeg -i <<in_video>> -vf scale=1280:720 -c:v libx264 -preset fast intermediate.mp4",
"ffmpeg -i intermediate.mp4 -af loudnorm -c:v copy <<out_video>>"
]
}'import requests
response = requests.post(
"https://renderio.dev/api/v1/run-chained-ffmpeg-commands",
headers={
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
json={
"input_files": {
"in_video": "https://example.com/sample.mp4",
},
"output_files": {
"out_video": "final.mp4",
},
"ffmpeg_commands": [
"ffmpeg -i {{in_video}} -vf scale=1280:720 -c:v libx264 -preset fast intermediate.mp4",
"ffmpeg -i intermediate.mp4 -af loudnorm -c:v copy {{out_video}}",
],
},
)
data = response.json()
print("Command ID:", data["command_id"])import requests
response = requests.post(
"https://renderio.dev/api/v1/run-chained-ffmpeg-commands",
headers={
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
json={
"input_files": {
"in_video": "https://example.com/sample.mp4",
},
"output_files": {
"out_video": "final.mp4",
},
"ffmpeg_commands": [
"ffmpeg -i <<in_video>> -vf scale=1280:720 -c:v libx264 -preset fast intermediate.mp4",
"ffmpeg -i intermediate.mp4 -af loudnorm -c:v copy <<out_video>>",
],
},
)
data = response.json()
print("Command ID:", data["command_id"])interface ChainedCommandRequest {
input_files: Record<string, string>;
output_files: Record<string, string>;
ffmpeg_commands: string[];
}
interface ChainedCommandResponse {
command_id: string;
}
const body: ChainedCommandRequest = {
input_files: {
in_video: "https://example.com/sample.mp4",
},
output_files: {
out_video: "final.mp4",
},
ffmpeg_commands: [
"ffmpeg -i {{in_video}} -vf scale=1280:720 -c:v libx264 -preset fast intermediate.mp4",
"ffmpeg -i intermediate.mp4 -af loudnorm -c:v copy {{out_video}}",
],
};
const response = await fetch(
"https://renderio.dev/api/v1/run-chained-ffmpeg-commands",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
body: JSON.stringify(body),
},
);
const { command_id } = (await response.json()) as ChainedCommandResponse;
console.log("Command ID:", command_id);interface ChainedCommandRequest {
input_files: Record<string, string>;
output_files: Record<string, string>;
ffmpeg_commands: string[];
}
interface ChainedCommandResponse {
command_id: string;
}
const body: ChainedCommandRequest = {
input_files: {
in_video: "https://example.com/sample.mp4",
},
output_files: {
out_video: "final.mp4",
},
ffmpeg_commands: [
"ffmpeg -i <<in_video>> -vf scale=1280:720 -c:v libx264 -preset fast intermediate.mp4",
"ffmpeg -i intermediate.mp4 -af loudnorm -c:v copy <<out_video>>",
],
};
const response = await fetch(
"https://renderio.dev/api/v1/run-chained-ffmpeg-commands",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
body: JSON.stringify(body),
},
);
const { command_id } = (await response.json()) as ChainedCommandResponse;
console.log("Command ID:", command_id);const response = await fetch(
"https://renderio.dev/api/v1/run-chained-ffmpeg-commands",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
body: JSON.stringify({
input_files: {
in_video: "https://example.com/sample.mp4",
},
output_files: {
out_video: "final.mp4",
},
ffmpeg_commands: [
"ffmpeg -i {{in_video}} -vf scale=1280:720 -c:v libx264 -preset fast intermediate.mp4",
"ffmpeg -i intermediate.mp4 -af loudnorm -c:v copy {{out_video}}",
],
}),
},
);
const { command_id } = await response.json();
console.log("Command ID:", command_id);const response = await fetch(
"https://renderio.dev/api/v1/run-chained-ffmpeg-commands",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
body: JSON.stringify({
input_files: {
in_video: "https://example.com/sample.mp4",
},
output_files: {
out_video: "final.mp4",
},
ffmpeg_commands: [
"ffmpeg -i <<in_video>> -vf scale=1280:720 -c:v libx264 -preset fast intermediate.mp4",
"ffmpeg -i intermediate.mp4 -af loudnorm -c:v copy <<out_video>>",
],
}),
},
);
const { command_id } = await response.json();
console.log("Command ID:", command_id);<?php
$ch = curl_init("https://renderio.dev/api/v1/run-chained-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([
"input_files" => [
"in_video" => "https://example.com/sample.mp4",
],
"output_files" => [
"out_video" => "final.mp4",
],
"ffmpeg_commands" => [
"ffmpeg -i {{in_video}} -vf scale=1280:720 -c:v libx264 -preset fast intermediate.mp4",
"ffmpeg -i intermediate.mp4 -af loudnorm -c:v copy {{out_video}}",
],
]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo "Command ID: " . $data["command_id"] . "\n";<?php
$ch = curl_init("https://renderio.dev/api/v1/run-chained-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([
"input_files" => [
"in_video" => "https://example.com/sample.mp4",
],
"output_files" => [
"out_video" => "final.mp4",
],
"ffmpeg_commands" => [
"ffmpeg -i <<in_video>> -vf scale=1280:720 -c:v libx264 -preset fast intermediate.mp4",
"ffmpeg -i intermediate.mp4 -af loudnorm -c:v copy <<out_video>>",
],
]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo "Command ID: " . $data["command_id"] . "\n";