Overview
The renderer is asynchronous. A successful submission returns immediately with a job ID while a background worker downloads the approved inputs and renders the video.
Submit
POST a validated task and retain the returned job ID.
Poll
GET job status every five seconds until it completes or fails.
Download
Use the signed URL returned in the completed result.
Authentication
Every API endpoint except signed downloads requires the service key in the Authorization header. Both Basic and Bearer prefixes are accepted.
Authorization: Basic YOUR_API_KEY
Content-Type: application/jsonSubmit a render
/submit.phpThe body contains one task with 2–40 HTTPS inputs, a filter graph, and exactly one MP4 output.
curl -X POST "https://ffmpeg.apex27.co.uk/submit.php" \
-H "Authorization: Basic YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"task": {
"inputs": [
{
"file_path": "https://fs-06.apex27.co.uk/example/photo.jpg",
"options": ["-loop", "1", "-framerate", "30", "-t", "3"]
},
{
"file_path": "https://forms.apex27.co.uk/music/1.mp3",
"options": ["-stream_loop", "-1"]
}
],
"filter_complex": "[0:v]scale=1080:1920,fps=30,format=yuv420p[video];[1:a]atrim=duration=3,volume=0.18[audio]",
"outputs": [{
"file": "property-preview.mp4",
"maps": ["[video]", "[audio]"],
"options": [
"-c:v", "libx264", "-preset", "fast",
"-crf", "20", "-c:a", "aac", "-b:a", "192k",
"-pix_fmt", "yuv420p", "-movflags", "+faststart", "-shortest"
]
}]
}
}'Accepted response · HTTP 202
{
"ok": true,
"job_id": "f4d85a9d99ea40b8aa835c621843ed83",
"status": "pending"
}| Field | Type | Description |
|---|---|---|
task.inputs required | array | Direct HTTPS media URLs with optional allow-listed input options. |
task.filter_complex required | string | The FFmpeg filter graph. File-reading filters are rejected. |
task.outputs required | array | Exactly one output definition with a safe .mp4 name, maps and approved encoding options. |
Check job status
/status.php?job_id={job_id}curl "https://ffmpeg.apex27.co.uk/status.php?job_id=JOB_ID" \
-H "Authorization: Basic YOUR_API_KEY"Waiting
The task is queued for a worker.
Rendering
Inputs are downloading or FFmpeg is running.
Ready
The response contains the result and usage metadata.
Stopped
The response contains a concise error message.
Completed response
{
"ok": true,
"job_id": "f4d85a9d99ea40b8aa835c621843ed83",
"status": "completed",
"result": [{
"size_bytes": 18439220,
"download_url": "https://ffmpeg.apex27.co.uk/download.php?...",
"file_name": "property-preview.mp4"
}],
"usage": {
"time_sec": 72.14,
"input_size_gb": 0.0124,
"output_size_gb": 0.0172,
"gb_sec": 2.135
}
}Health check
/health.phpReturns runtime readiness, PHP version, FFmpeg availability, active jobs, and the configured parallel-job limit.
curl "https://ffmpeg.apex27.co.uk/health.php" \
-H "Authorization: Basic YOUR_API_KEY"Signed downloads
A completed job includes a signed download_url. It needs no Authorization header and supports byte ranges, so browsers can seek within the video.
Link lifetime
Signed URLs expire after approximately six hours.
File retention
Completed jobs and their media are retained for 48 hours.
Validation and limits
| Area | Limit |
|---|---|
| Parallel renders | 2 |
| Inputs per task | 2–40 |
| Maximum downloaded input | 750 MB per input |
| Filter graph | 200,000 characters; file-reading filters are blocked |
| Output | One safe .mp4 filename |
| Input protocols | Direct HTTPS URLs only |
| Input hosts | Any public internet host. Private, loopback, link-local, and reserved network addresses are blocked. |
| Input options | -loop 1, -stream_loop -1, -framerate 1…60, -t 0.1…3600 |
| Encoding | H.264 via libx264, CRF 18–22; AAC at 128, 192, or 256 kbps |
Errors
| HTTP | Meaning | Action |
|---|---|---|
400 | Invalid JSON, task, URL, filter, or FFmpeg option. | Correct the request; do not retry unchanged. |
401 | Missing or invalid API key. | Check the Authorization header. |
404 | Unknown job or expired/missing download. | Verify the ID or submit a new render. |
405 | Wrong HTTP method. | Use POST for submit and GET for status/health. |
429 | Both render slots are occupied. | Wait briefly, then retry with backoff. |
500 | Internal service or render failure. | Inspect the error and retry only if transient. |
{
"ok": false,
"error": "Renderer is busy; please retry shortly"
}Using the API from n8n
Submit workflow
HTTP Request · POSThttps://ffmpeg.apex27.co.uk/submit.php
JSON body: {{ $json.ffmpegRequest }}
Status workflow
HTTP Request · GEThttps://ffmpeg.apex27.co.uk/status.php
Query: job_id={{ $json.query.job_id }}
Add Authorization: Basic YOUR_API_KEY using an n8n credential. Poll about every five seconds and stop when the status is completed or failed.