FFmpeg API: The Complete Guide to Processing Video via REST

February 13, 2026 · RenderIO

Your server shouldn't be encoding video

You have a web app. Users upload video. You need to convert it, resize it, extract a thumbnail. So you install FFmpeg on your server, shell out to it from your application code, and wait.

It works. Until it doesn't.

One user uploads a 2GB file. Your server's CPU pins at 100% for 8 minutes. Every other request queues up. Your monitoring fires. You scramble to add more RAM, bigger instances, autoscaling rules.

There's a simpler approach: send the FFmpeg command to an API. Let someone else run the compute. Get the result back. This is the core idea behind FFmpeg as a service.

What an FFmpeg API actually is

An FFmpeg API is a REST endpoint that accepts an FFmpeg command, runs it on remote infrastructure, and returns the processed file. You send a POST request with:

  1. The FFmpeg command (same syntax you'd use on the command line)

  2. URLs for input files

  3. Names for output files

The API downloads your inputs, runs FFmpeg, uploads the outputs to storage, and gives you a URL to download the result.

No servers to manage. No FFmpeg to install. No scaling to worry about.

Why use an API instead of self-hosting

Self-hosting FFmpeg means owning every problem (the hosted vs self-hosted comparison covers the full trade-off in detail):

  • Scaling: Video encoding is CPU-intensive. A single 1080p conversion can consume an entire core for minutes. You need to size for peak load, not average load.

  • Security: FFmpeg has a history of CVEs. CVE-2024-7055 (heap buffer overflow in the MP4 demuxer) dropped recently. Running user-supplied commands on your infrastructure means you own the patching cycle.

  • Maintenance: FFmpeg releases new versions constantly. Codec support varies by build. Keeping your installation current takes real time.

  • Cost: An idle server waiting for video jobs still costs money. You pay for 24/7 uptime even if jobs come in bursts.

An API shifts all of this to the provider. You pay per job instead of per hour. We break down the exact numbers in our FFmpeg API pricing comparison.

How RenderIO works

RenderIO runs FFmpeg inside Cloudflare Sandbox containers. Each command gets its own isolated environment. No shared state, no security risk from other users' commands.

Here's how a request flows:

  1. You POST an FFmpeg command to the API

  2. RenderIO spins up an isolated container

  3. Input files are downloaded from your URLs

  4. FFmpeg runs your command

  5. Output files are uploaded to storage

  6. You get back a command_id to check status

The whole process takes seconds for most operations. Larger files take longer, but you're never blocking your own server.

Your first API call

Let's convert a video from MOV to MP4. This is the most common operation and a good starting point.

curl -X POST https://renderio.dev/api/v1/run-ffmpeg-command \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your_api_key" \
  -d '{
    "ffmpeg_command": "-i {{input}} -c:v libx264 -c:a aac {{output}}",
    "input_files": {
      "input": "https://example.com/video.mov"
    },
    "output_files": {
      "output": "converted.mp4"
    }
  }'

The response comes back immediately:

{
  "command_id": "cmd_abc123",
  "status": "processing"
}

Poll for the result:

curl https://renderio.dev/api/v1/commands/cmd_abc123 \
  -H "X-API-KEY: your_api_key"

When it's done:

{
  "command_id": "cmd_abc123",
  "status": "SUCCESS",
  "output_files": {
    "out_output": "https://media.renderio.dev/converted.mp4"
  }
}

That's it. No FFmpeg installation. No server provisioning. No cleanup.

The command format

RenderIO uses placeholder syntax for files. You reference {name} in your FFmpeg command and map those names to URLs in input_files and filenames in output_files.

This works with any FFmpeg command. Trim a video:

curl -X POST https://renderio.dev/api/v1/run-ffmpeg-command \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your_api_key" \
  -d '{
    "ffmpeg_command": "-i {{in_video}} -ss 00:00:30 -t 00:01:00 -c copy {{out_video}}",
    "input_files": {
      "in_video": "https://example.com/long-video.mp4"
    },
    "output_files": {
      "out_video": "trimmed.mp4"
    }
  }'

Extract audio:

curl -X POST https://renderio.dev/api/v1/run-ffmpeg-command \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your_api_key" \
  -d '{
    "ffmpeg_command": "-i {{in_video}} -vn -acodec libmp3lame -q:a 2 {{out_audio}}",
    "input_files": {
      "in_video": "https://example.com/video.mp4"
    },
    "output_files": {
      "out_audio": "audio.mp3"
    }
  }'

To mute a video or replace its audio track entirely, see the FFmpeg remove audio guide, which covers all three use cases with CLI and API examples.

Overlay a watermark:

curl -X POST https://renderio.dev/api/v1/run-ffmpeg-command \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your_api_key" \
  -d '{
    "ffmpeg_command": "-i {{in_video}} -i {{watermark}} -filter_complex overlay=10:10 {{out_video}}",
    "input_files": {
      "in_video": "https://example.com/video.mp4",
      "watermark": "https://example.com/logo.png"
    },
    "output_files": {
      "out_video": "watermarked.mp4"
    }
  }'

The FFmpeg cheat sheet has 50+ commands you can plug directly into the API, and the curl examples post covers common patterns in more detail. For watermark-specific workflows — responsive scaling, text overlays, opacity control, and batch watermarking — the FFmpeg watermark guide covers every option. Speed changes are also a good fit for the API — if you need to batch-adjust playback speed across many clips, the FFmpeg speed up video guide has ready-to-use API examples with setpts and atempo.

Automating with webhooks

Polling works, but webhooks are better for production. Configure a webhook URL in your RenderIO dashboard and receive a POST when each command finishes.

{
    "command_id": "cmd_abc123",
  "status": "SUCCESS",
  "output_files": {
    "out_output": "https://media.renderio.dev/converted.mp4"
  }
}

No polling loop. No wasted requests. Your system reacts to completions in real time.

Chained and parallel commands

Most real pipelines need more than one operation per video. Generate a thumbnail, extract audio, transcode — all from the same input file.

RenderIO handles this with chained commands. One API call, up to 10 sequential FFmpeg operations:

curl -X POST https://renderio.dev/api/v1/run-chained-ffmpeg-commands \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your_api_key" \
  -d '{
    "input_files": {
      "in_video": "https://example.com/raw.mp4"
    },
    "output_files": {
      "out_720p": "video_720p.mp4",
      "out_thumb": "thumbnail.jpg",
      "out_audio": "extracted.mp3"
    },
    "ffmpeg_commands": [
      "ffmpeg -i {{in_video}} -vf scale=1280:720 -c:v libx264 -crf 23 {{out_720p}}",
      "ffmpeg -i {{in_video}} -ss 00:00:05 -vframes 1 {{out_thumb}}",
      "ffmpeg -i {{in_video}} -vn -c:a libmp3lame -q:a 2 {{out_audio}}"
    ]
  }'

If the operations don't depend on each other, use the parallel endpoint (/run-multiple-ffmpeg-commands) instead. Same idea, but everything runs at once. Generating multiple output sizes from one master file is a common pattern — the FFmpeg scale video guide has a full example using the parallel endpoint to produce 1080p, 720p, and 480p in a single request. You can also use the API to merge multiple video clips into a single file using FFmpeg's concat filter. For a breakdown of which concat method to use — demuxer, filter, or protocol — and how to run each via the API, see the FFmpeg concat guide.

Language-specific integration

While curl is fine for testing, you'll want to integrate the API into your app. We have full tutorials for:

  • Python — with polling, webhooks, and error handling

  • Node.js — async/await patterns and retry logic

Both cover the same operations shown here, but with proper error handling and production patterns.

If you use automation tools like n8n or Zapier, the API works through their HTTP Request nodes since it's just REST.

When to use an FFmpeg API

Use an API when:

  • You process fewer than 10,000 videos per month (above that, self-hosted may be cheaper — see the pricing comparison)

  • Your team doesn't include someone who wants to maintain FFmpeg infrastructure

  • You need to scale from 0 to 1,000 concurrent jobs without planning

  • Video processing isn't your core product

Self-host when:

  • You process very high volumes at predictable rates

  • You need custom FFmpeg builds with specific codecs

  • Latency requirements demand local processing

  • You have dedicated infrastructure engineers

For the full breakdown of managed vs DIY options, see our FFmpeg as a service deep dive or the 2026 comparison of every FFmpeg API.

For most teams, the API is the right call. You're building a product, not a video processing pipeline.

FAQ

What codecs does RenderIO support?

RenderIO runs a standard FFmpeg build with H.264 (libx264), H.265 (libx265), VP9 (libvpx-vp9), AV1, AAC, MP3 (libmp3lame), Opus, and others. Proprietary codecs like libfdk-aac aren't available.

How large can input files be?

Input files are referenced by URL (S3 pre-signed URLs, public URLs, etc.), so there's no upload size limit on the API itself. Processing time scales with file size and complexity.

Is FFmpeg API cheaper than running my own server?

For most workloads under 20,000 videos/month, yes. The pricing comparison breaks down costs at every volume level. The short version: a minimal self-hosted AWS setup costs 640+/monthincludingengineeringtime.RenderIOstartsat640+/month including engineering time. RenderIO starts at 9/month.

Can I use my existing FFmpeg commands?

Yes. The commands are identical to what you'd run locally. You swap file paths for {placeholders} and pass input URLs separately. The REST API tutorial walks through the syntax in detail.

Start processing video in 2 minutes

The Starter plan at $9/mo includes 500 commands — enough to follow this entire guide. See the full FFmpeg API feature overview or create your API key and send your first command.