API reference

FFmpeGo exposes two endpoints: the general encode endpoint and a YouTube clip endpoint. Authenticate with a Bearer API key. Copy the examples below as-is to verify your integration against public sample videos.

POST /v2/run

The general FFmpeg endpoint: send JSON, get the encoded file back — or PUT it to your own signed storage URL.

Base URL: https://ffmpego.com

Auth: Authorization: Bearer ffc_live_...

Billing header (success): X-Compute-Seconds

Request body

inputs and args are required. Everything else is optional.

FieldRequiredDescription
inputsrequiredArray of input files. inputs[i] is FFmpeg input i ([0:v], -map 1:a, …).
argsrequiredFFmpeg flags only. Do not include -i— inputs are prepended automatically. Placeholders like {input0} are not supported.
outputFilenameoptionalOutput file name, including extension. Default: output.
outputContentTypeoptionalOverride response Content-Type when you are not using upload. Otherwise inferred from the output extension.
uploadoptionalAfter a successful encode, PUT the file to a signed URL instead of returning the binary in the HTTP response.

Each inputs[] item

FieldRequiredDescription
urloptionalPublic HTTPS URL of the file. Provide either url or data.
dataoptionalBase64-encoded file bytes (alternative to url).
filenameoptionalHelps FFmpeg detect the format. If omitted, the extension is taken from the URL path (e.g. .mp4).

Each item must include exactly one of url or data.

upload (optional)

When upload is present, the API does not stream the encoded file back. After FFmpeg exits 0, it issues a single PUT to your URL (signed storage upload, S3 presigned PUT, and similar). Resumable/TUS uploads are not supported. URL lifetime is your responsibility.

FieldRequiredDescription
upload.urlrequiredSigned upload URL, used as-is. Do not rewrite the path.
upload.headersrequiredMust include Content-Type (for example video/mp4). Content-Length is added from the file size.
upload.methodoptionalIf provided, must be PUT.

Response

Without upload (default): 200 with the encoded file as the body. Content-Type comes from outputContentType or the output extension.

With upload: 200 JSON:

response.json
{
  "ok": true,
  "uploaded": true,
  "bytes": 21375689,
  "contentType": "video/mp4",
  "outputFilename": "export.mp4"
}

If storage returns HTTP 4xx/5xx after a successful encode, the API responds 502. FFmpeg failures return 500 and skip the upload. Invalid upload objects return 400.

Examples

Public Pixabay clips you can paste into a request to confirm your key and client work. Save the response body as the named output file.

Transcode to MP4

transcode.json
{
  "inputs": [
    {
      "url": "https://cdn.pixabay.com/video/2025/11/07/314643_tiny.mp4"
    }
  ],
  "args": [
    "-c:v",
    "libx264",
    "-c:a",
    "aac",
    "-f",
    "mp4"
  ],
  "outputFilename": "out.mp4",
  "outputContentType": "video/mp4"
}
curl
curl -X POST https://ffmpego.com/v2/run \
  -H "Authorization: Bearer ffc_live_..." \
  -H "Content-Type: application/json" \
  -d '{"inputs":[{"url":"https://cdn.pixabay.com/video/2025/11/07/314643_tiny.mp4"}],"args":["-c:v","libx264","-c:a","aac","-f","mp4"],"outputFilename":"out.mp4","outputContentType":"video/mp4"}' \
  --output out.mp4

Video to GIF

10 fps, 320px wide, Lanczos scaling. Save the response as output.gif.

gif.json
{
  "inputs": [
    {
      "url": "https://cdn.pixabay.com/video/2025/11/07/314643_tiny.mp4"
    }
  ],
  "args": [
    "-vf",
    "fps=10,scale=320:-1:flags=lanczos",
    "-c:v",
    "gif"
  ],
  "outputFilename": "output.gif"
}
curl
curl -X POST https://ffmpego.com/v2/run \
  -H "Authorization: Bearer ffc_live_..." \
  -H "Content-Type: application/json" \
  -d '{"inputs":[{"url":"https://cdn.pixabay.com/video/2025/11/07/314643_tiny.mp4"}],"args":["-vf","fps=10,scale=320:-1:flags=lanczos","-c:v","gif"],"outputFilename":"output.gif"}' \
  --output output.gif

Concatenate two videos

Video-only concat — works even when an input has no audio. If both clips have audio and you want to keep it, use [0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[outv][outa] and add -map [outa].

concat.json
{
  "inputs": [
    {
      "url": "https://cdn.pixabay.com/video/2025/06/24/287510_tiny.mp4",
      "filename": "video1.mp4"
    },
    {
      "url": "https://cdn.pixabay.com/video/2025/11/07/314643_tiny.mp4",
      "filename": "video2.mp4"
    }
  ],
  "args": [
    "-filter_complex",
    "[0:v][1:v]concat=n=2:v=1:a=0[outv]",
    "-map",
    "[outv]"
  ],
  "outputFilename": "concatenated.mp4"
}

Upload the result to storage

Replace upload.url with a one-shot signed PUT URL from your bucket. The HTTP response is JSON metadata, not the video bytes.

upload.json
{
  "inputs": [
    {
      "url": "https://cdn.pixabay.com/video/2025/11/07/314643_tiny.mp4"
    }
  ],
  "args": [
    "-c:v",
    "libx264",
    "-f",
    "mp4"
  ],
  "outputFilename": "export.mp4",
  "upload": {
    "url": "https://<project>.supabase.co/storage/v1/object/upload/sign/bucket/path?token=...",
    "method": "PUT",
    "headers": {
      "Content-Type": "video/mp4"
    }
  }
}

Clip a YouTube video

Downloads only the requested range with yt-dlp, then runs the same FFmpeg pipeline. There is a browser playground if you would rather click than curl.

youtube-clip.json
{
  "url": "https://www.youtube.com/watch?v=VIDEO_ID",
  "start": "1:30",
  "end": "2:00",
  "args": [
    "-c:v",
    "libx264",
    "-preset",
    "veryfast",
    "-crf",
    "24",
    "-c:a",
    "aac",
    "-vf",
    "scale=-2:720",
    "-f",
    "mp4"
  ],
  "outputFilename": "clip.mp4"
}
curl
curl -X POST https://ffmpego.com/v2/youtube-clip \
  -H "Authorization: Bearer ffc_live_..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://www.youtube.com/watch?v=VIDEO_ID","start":"1:30","end":"2:00","args":["-c:v","libx264","-preset","veryfast","-crf","24","-c:a","aac","-vf","scale=-2:720","-f","mp4"],"outputFilename":"clip.mp4"}' \
  --output clip.mp4

POST /v2/youtube-clip

Download a time range of a YouTube video and get the encoded clip back. Same auth, quotas, and compute-second billing as /v2/run.

FieldRequiredDescription
urlrequiredYouTube link to a single video: youtube.com, youtu.be, m.youtube.com, or music.youtube.com.
startrequiredStart time as 90, 1:30, or 0:01:30 (decimals allowed).
endrequiredEnd time, must be after start. Only this range is downloaded.
argsoptionalFFmpeg flags for the encode step (same rules as /v2/run). Defaults to H.264 + AAC MP4.
outputFilenameoptionalDefault clip.mp4.
outputContentTypeoptionalOverride the response Content-Type.
uploadoptionalSame signed-URL PUT contract as /v2/run; returns JSON metadata instead of bytes.

Response: 200 with the clip bytes (or upload JSON). X-Compute-Seconds covers the whole job — YouTube download plus encode.

400 invalid body · 401 invalid API key · 402 quota exceeded · 429 rate limited · 502 YouTube/yt-dlp failure (bot check, private/age-restricted video, download timeout) — not billed · 500 FFmpeg failure — not billed.

curl
curl -X POST https://ffmpego.com/v2/youtube-clip \
  -H "Authorization: Bearer ffc_live_..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://www.youtube.com/watch?v=VIDEO_ID","start":"1:30","end":"2:00","args":["-c:v","libx264","-preset","veryfast","-crf","24","-c:a","aac","-vf","scale=-2:720","-f","mp4"],"outputFilename":"clip.mp4"}' \
  --output clip.mp4

Limits (Free plan)

75 compute seconds / month

5 requests / month

1000 requests / hour

Errors

400 — invalid body (including upload)

401 — missing or invalid API key

402 — monthly quota exceeded

429 — rate limit exceeded

502 — encode succeeded but storage PUT failed

4xx/5xx from FFmpeg — not billed