Create a job
POST /v1/jobsIdempotency-Key: 5f0c2a8e-…{ "input": { "upload_id": "0199a0e0-5f1c-7c3a-9d2e-1b4f6a8c2d10", "clip": { "start": 10, "duration": 60 } }, "outputs": { "streaming": { "formats": ["hls", "dash"], "variants": ["1080p", "720p", "480p", "360p", "240p"] }, "mp4": { "variants": ["720p", { "resolution": "1080p", "audio": false }] }, "mp3": { "bitrate": 192000 }, "posters": [{ "at": 5, "width": 1280 }], "storyboard": { "interval": 5 } }, "audio": { "tracks": [{ "language": "es" }, { "language": "en", "required": false }] }, "subtitles": { "tracks": "all" }, "on_upscale": "skip", "quality_metrics": true, "webhook_url": "https://your-server.example.com/hooks/iomza", "metadata": { "video_id": "123" }}The answer is the job (201), queued until your plan has room for it, then processing. See Follow a job.
Idempotency. Send an Idempotency-Key (any unique string up to 255 characters, a UUID for instance): if the request is repeated with the same key, after a timeout say, you get the same job back (200) instead of a second one. The same key with a different body is a 409.
The request
Section titled “The request”| Field | |
|---|---|
input |
The source: exactly one of upload_id (an upload of yours: a completed one, or a progressive one still arriving) or url (copied first: see Or give a URL). |
input.clip |
Process a stretch only: start in seconds (default 0) and duration (default: to the end). |
outputs |
At least one of streaming, mp4, mp3, posters, storyboard. |
outputs.streaming |
Adaptive streaming. formats: hls and/or dash (default both; they share their segments, so asking for both costs nothing extra). variants: the qualities. |
outputs.mp4 |
One MP4 file per variant, each carrying every chosen audio track. |
outputs.mp3 |
The audio alone. bitrate 32 000–320 000 (default 128 000). |
outputs.posters |
1–10 JPEG images: at (second), optional width/height (one alone keeps the shape). |
outputs.storyboard |
Thumbnail sprites and a WebVTT index, for previews over a player’s seek bar: interval (1–60 s), width/height (default 160×90 in the video’s shape), columns. |
audio.bitrate |
Forces re-encoding the audio as AAC at this bitrate. Without it, mono and stereo AAC is copied as is: faster, and no quality lost. |
audio.tracks, subtitles.tracks |
Which tracks of the source come out: see Languages and subtitles. |
on_upscale |
For qualities larger than the source: skip (default) leaves them out and lists them in the job’s skipped; fail rejects the job. |
quality_metrics |
true scores each variant’s perceived quality (VMAF): see Quality. Adds a few seconds. |
webhook_url |
Also send this job’s events here, besides your organization’s endpoints. https, public. |
metadata |
Up to 10 text pairs of yours (keys up to 40 characters, values up to 500), returned in the job and its webhooks. |
Variants
Section titled “Variants”Each variant is a quality. Write it as its name for the defaults, or as an object to control it:
"variants": [ "1080p", { "resolution": "720p", "codec": "hevc", "quality": 24 }, { "resolution": "480p", "bitrate": 1200000, "rate_control": "cbr" }]Up to 10 per output. The same quality asked in streaming and mp4 is encoded once and counted once.
| Field | Values | Default |
|---|---|---|
resolution |
240p 360p 480p 720p 1080p 1440p 2160p, or any other even height from 144 to 2160 ("540p", "576p", "900p") |
required |
codec |
h264 (plays everywhere), hevc (about 30 % smaller at the same quality; Apple devices, recent TVs and browsers), av1 (smallest; recent devices) |
h264 |
quality |
Constant quality, CRF 16–35: lower is better and heavier | 22 |
max_bitrate |
A ceiling, in bps (100 000–100 000 000) | per resolution |
bitrate |
A target bitrate, in bps (100 000–100 000 000), instead of a quality | — |
rate_control |
With bitrate: vbr or cbr |
vbr |
preset |
ultrafast … veryslow: speed against compression |
veryfast |
profile |
H.264 only: baseline, main, high |
per resolution |
fit |
How the picture fills the frame: see below | contain |
rotate |
0, 90, 180, 270 (clockwise, before scaling) | 0 |
flip |
horizontal, vertical |
— |
watermark |
{ "url": "https://…/logo.png", "position": "bottomright" }: topleft, topright, bottomleft, bottomright or center |
— |
audio |
MP4 only: whether the file has audio | true |
A quality names a 16:9 box: 1080p is 1920×1080, 540p is 960×540. With fit: "contain" (the default) the picture keeps its shape inside the box and the box turns with the video, so a vertical phone video at 720p comes out 720×1280, with no bars. pad keeps the 16:9 box and adds bars; crop fills it and cuts what overflows.
Custom heights ("540p", "900p"…) get a default ceiling interpolated between the standard qualities around them.
Quality or bitrate
Section titled “Quality or bitrate”There are two ways to control the bitrate. Use one per variant: quality and bitrate are exclusive.
Quality mode (the default): quality sets a constant perceived quality, and the encoder spends what each scene needs. A talking head takes a fraction of what a football match does. max_bitrate is a ceiling, not a target: simple scenes stay well under it, complex ones are held at it. The default ceilings are 400 Kbps at 240p up to 15 Mbps at 2160p. The output also never goes above the source’s own bitrate: re-encoding can’t add detail that isn’t there. This is the best choice for most uses, since you pay for bits only where they show.
Bitrate mode: bitrate asks for a bitrate, and it is honoured even when the source has less.
rate_control: "vbr"(default):bitrateis the average. Complex scenes may rise up tomax_bitrate(default 1.5 ×bitrate).rate_control: "cbr": constant, padded where the picture needs less. For broadcast, ad servers and CDNs that require it. Files are bigger for the same quality. Withcbr, givebitrateonly.- AV1 supports
vbronly, withoutmax_bitrate.
Languages and subtitles
Section titled “Languages and subtitles”By default every audio track of the source comes out, as do its text subtitles. To choose, list the tracks in order of preference: the first one is the default.
"audio": { "tracks": [{ "language": "es" }, { "language": "en", "name": "English (original)" }, { "index": 2, "required": false }] },"subtitles": { "tracks": [{ "language": "es" }] }- Pick by
language(es,spaandes-419all work: the first track in that language) or byindex(its position among the source’s tracks of that kind, from the tracks). nameis what players show. By default it is the language’s name in itself (“Español”, “English”), made unique if two share it (“English 2”). Untagged tracks are named by their title, or “Audio 1”…; names written by encoding tools are ignored.required: falsemeans “if it exists”: a missing track is listed in the job’sskipped_tracksinstead of failing the job.[]means none."all"is the default. At most 8 audio tracks come out.
Each audio track comes out as stereo AAC: surround (5.1, 7.1, Atmos) is mixed down to stereo, which every device plays. In HLS and DASH they are alternative audio tracks with their language, so players show a language menu; MP4s carry every track, labeled, with the default one enabled. Each streaming audio language counts as audio minutes.
Text subtitles (SRT, ASS, WebVTT, mov_text…) are converted to WebVTT, cut to the clip, delivered as files and inside the streaming. Forced subtitles are flagged (forced: true) and named so in their own language: “Español (forzados)”, “English (forced)”. Image subtitles (PGS, VobSub) can’t be converted and are listed in skipped_tracks.
When the request is wrong
Section titled “When the request is wrong”You get a 400 validation_error whose details lists every problem with its path, explained by the form you wrote, so you can fix them all at once:
{ "error": { "code": "validation_error", "message": "Invalid job request.", "details": [ "outputs.streaming.variants.1.bitrate: give quality or bitrate, not both", "outputs.mp4.variants.0: must be one of 240p, 360p, 480p, 720p, 1080p, 1440p, 2160p, or another even height from 144 to 2160 such as \"540p\"" ] }}