The FFmpeg API lets you transcode, trim, convert, and otherwise process video and audio files entirely on the server. You provide a source URL and an FFmpeg command; MADIAD Hub fetches the file, runs the job, and makes the output available to download.
There is no binary upload — input files must be reachable over HTTPS. The API returns a job_id immediately; processing is asynchronous, so you poll for status and then download the result.
FFmpeg jobs require a paid plan. The Trial plan includes 0 FFmpeg minutes per month. Upgrade to Starter or higher to unlock the feature.
How a job works
Submit
POST to /v1/ffmpeg/jobs with one or more source URLs and an FFmpeg command. The API validates the command, reserves quota, and queues the job. You receive a job_id.
Poll
GET /v1/ffmpeg/jobs/:id until status is finished.
Download
GET /v1/ffmpeg/jobs/:id/result to stream the processed file.
Submit a job
POST /v1/ffmpeg/jobs
Authorization: Bearer $MADIAD_API_KEY
Content-Type: application/json
Request body
| Field | Type | Required | Description |
|---|
file_url | string | One of file_url / file_urls | A single HTTPS source URL |
file_urls | string[] | One of file_url / file_urls | Multiple HTTPS source URLs (e.g. for mixing tracks) |
full_command | string | Yes | The complete FFmpeg command string (see Command rules) |
output_extension | string | Yes | Container/format for the output (see Allowed extensions) |
Response
{
"job_id": "ffj_01HZX9G4P6R8S0T2V4W6X8Y0Z2",
"status": "queued"
}
Poll status
GET /v1/ffmpeg/jobs/:id
Authorization: Bearer $MADIAD_API_KEY
Response
{
"job_id": "ffj_01HZX9G4P6R8S0T2V4W6X8Y0Z2",
"status": "processing",
"duration_sec": null
}
duration_sec is null until the job finishes; it is populated with the actual output duration once complete.
status value | Meaning |
|---|
queued | Job is waiting to run |
processing | Job is running |
finished | Output is ready to download |
failed | Job failed; retry with a corrected command |
Download the result
Once status is finished, stream the output file:
GET /v1/ffmpeg/jobs/:id/result
Authorization: Bearer $MADIAD_API_KEY
The response is a binary stream with Content-Disposition: attachment. Pipe it to a file or buffer it in memory.
Command rules
The full_command field must satisfy all of the following rules. Requests that fail validation return 400 invalid_request before any quota is consumed.
| Rule | Detail |
|---|
Starts with ffmpeg | The command must begin with the literal word ffmpeg |
Contains {input} placeholder | Use {input} for a single source, or {input0}, {input1}, … for multiple sources |
Contains {output} placeholder | MADIAD Hub substitutes the output path at run time |
| Maximum length | 4,000 characters |
| No shell metacharacters | Characters ;, |, &, $, `, <, > are blocked |
| No destructive tokens | $(, rm, rmdir, mkfs, dd are blocked |
Newlines in the command are converted to spaces automatically, so you can paste multi-line commands directly.
Allowed output extensions
output_extension must be one of the following values (without a leading dot):
| Category | Values |
|---|
| Video | mp4, mov, webm, mkv, gif |
| Audio | mp3, wav, m4a, aac, ogg |
| Image | jpg, png |
Any other value returns 400 invalid_request.
Quota and billing
FFmpeg usage is measured in FFmpeg minutes. In v1, every job costs a flat 1 minute, regardless of the actual output duration. The quota is reserved at submit time and refunded automatically if the job fails to queue.
Monthly limits by plan:
| Plan | FFmpeg minutes / month |
|---|
| Trial | 0 (not available) |
| Starter | 30 |
| Growth | 150 |
| Business | 500 |
| Custom | Unlimited |
When you exhaust your monthly allowance, the API returns 429 quota_exceeded. Usage resets on the first day of each calendar month (UTC).
Authentication and rate limits
All FFmpeg endpoints use the same API-key Bearer authentication as the rest of MADIAD Hub — see Authentication.
The rate limit is 120 requests per minute per account across all FFmpeg endpoints. Exceeding this returns 429 with a Retry-After header indicating how long to wait.
Job ownership
Jobs are private to the account that created them. Polling or downloading a job that belongs to another account returns 404 not_found — there is no cross-account access.
Errors
| HTTP status | Code | When |
|---|
400 | invalid_request | Missing or non-HTTPS URL, command fails validation, unsupported output_extension |
404 | not_found | Unknown job ID, or the job belongs to a different account |
429 | quota_exceeded | Monthly FFmpeg minutes exhausted |
429 | rate_limited | More than 120 requests/minute; back off and retry after Retry-After seconds |
502 | upstream_error | Result not available yet, or processing failed |
Worked example
1. Submit: convert an MP4 to a web-optimized WebM
curl -X POST https://api.madiad.com/v1/ffmpeg/jobs \
-H "Authorization: Bearer $MADIAD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_url": "https://cdn.example.com/raw/interview.mp4",
"full_command": "ffmpeg -i {input} -c:v libvpx-vp9 -crf 33 -b:v 0 -c:a libopus {output}",
"output_extension": "webm"
}'
2. Poll until finished
curl https://api.madiad.com/v1/ffmpeg/jobs/ffj_01HZX9G4P6R8S0T2V4W6X8Y0Z2 \
-H "Authorization: Bearer $MADIAD_API_KEY"
# Keep polling until "status": "finished"
3. Download the result
curl https://api.madiad.com/v1/ffmpeg/jobs/ffj_01HZX9G4P6R8S0T2V4W6X8Y0Z2/result \
-H "Authorization: Bearer $MADIAD_API_KEY" \
--output interview.webm