Documentation menu

Guides

Video

Compress and convert video through jobs, with a choice of codec, quality tier and resolution.

Video runs as a job

Encoding video takes from seconds to many minutes, so it never runs as a direct request. A video sent to POST /v1/compress or POST /v1/convert is refused with 415 use_async_job, whatever its size. Use the job flow instead: get the file to us, create a job, wait, download. Large files and jobs explains each step. This page covers what is specific to video.

There are two ways to get a video to a job. Upload it: a file of up to 95 MB goes in one request, and a larger one is sent in parts of 64 MB, up to the file limit of your plan. Or pass input.url: an https link, such as a presigned download URL from your own bucket, that the job fetches the file from. See uploading in parts. The SDKs split a large file into parts for you.

Compress a video

This job re-encodes a video as H.264 in an MP4 at the balanced tier, no wider than 1920 pixels:

bash
curl -X POST "https://api.smolmac.com/v1/jobs" \
  -H "Authorization: Bearer $SMOL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "compress",
    "input": { "url": "https://files.example.com/uploads/talk.mov?token=..." },
    "options": {
      "video": {
        "format": "mp4",
        "codec": "h264",
        "quality": "balanced",
        "resolution": "1920"
      }
    },
    "webhook_url": "https://example.com/smol/webhook"
  }'

The response is the job object with the status queued. When the job has succeeded, its result describes the output:

result of the finished job
{
  "kind": "video",
  "input_format": "mov",
  "output_format": "mp4",
  "original_size": 734003200,
  "output_size": 96468992,
  "savings_percent": 86.9,
  "kept_original": false,
  "increased": false,
  "width": 1920,
  "height": 1080,
  "pages": null,
  "duration_seconds": 184.6,
  "video_codec": "h264",
  "warnings": [],
  "download_url": "https://api.smolmac.com/v1/jobs/job_Gd2Wn6TqY0bXs4LhC8vK/output?expires=1790853305&signature=7a0c3e6b9d2f5a8c1e4b7d09c1f4a7e2b5d8036f1a4c7e0b3d6f9a2c5e8b1d4f",
  "download_expires_at": "2026-10-01T11:15:05.220Z"
}

width and height are those of the output. Together with duration_seconds and video_codec they decide the price. Every option can be left out. With none, the output is H.265 in an MP4 at the high tier and the original resolution, which are the defaults of the Smol Mac app.

Containers and codecs

Input can be MP4, MOV, AVI, MKV, WebM, FLV, WMV, M4V, MPG or 3GP. The output is set by two options: video.format is the container (the file type), and video.codec is how the picture is encoded inside it.

video.codecEncoderNotes
h265 (default)x265, 10-bitSmaller files than H.264 at the same quality. Plays on Apple devices and current hardware. Not supported by every browser. Slower to encode.
h264x264, 8-bitPlays almost everywhere. The safe choice for the web and for files of unknown destination. Faster to encode and cheaper.
vp9libvpx-vp9, 8-bitAn open codec. Used for WebM.
video.formatPictureAudio
mp4 (default)The codec you choseAAC
movThe codec you choseAAC
mkvThe codec you choseAAC
webmAlways VP9Opus

WebM only holds VP9 here: with video.format=webm the output is VP9 with Opus audio, and video.codec is ignored. MP4 and MOV files are written so that playback can start before the whole file has downloaded.

Quality tiers and CRF

video.quality picks a CRF value for the encoder. CRF (constant rate factor) is a target for visual quality: the encoder spends as many bits as each scene needs to reach it. A lower CRF means higher quality and a larger file. The numbers are on a different scale for each encoder, so compare within a column, not across.

video.qualityH.265H.264VP9
tiny343141
low302636
balanced262231
high (default)241926
maximum181416
web282426

high is hard to tell from the source at normal viewing size. balanced and web suit video that is streamed or embedded in a page. tiny shows clear artefacts and is for previews. How the tiers relate to the image quality number is covered in The quality scale.

Three more options give direct control over the encoder:

OptionEffect
video.crfA whole number from 0 to 63. Used as the CRF in place of the value from the tier.
video.slowtrue uses the encoder preset slow instead of medium. The file is somewhat smaller at the same quality, and the job takes longer.
video.presetNames the encoder preset directly, from ultrafast to veryslow. Takes precedence over video.slow.

Processing time does not change the price. A slower preset costs you waiting time only.

Resolution

video.resolution sets the largest frame the output may have. The value is a width; each width has a matching height.

video.resolutionFits withinCommon name
original (default)The size of the input
38403840 by 21604K
19201920 by 10801080p
12801280 by 720720p
854854 by 480480p
  • Video is only scaled down. A 720p input with resolution 1920 stays 720p.
  • The aspect ratio is kept. The frame is scaled until it fits inside the box, and nothing is cropped.
  • Width and height are rounded to even numbers, which the encoders require.
  • In JSON the value can be written as a string ("1920") or as a number (1920).

Lowering the resolution is the most effective way to shrink a video, and it also moves the job into a cheaper price band.

The audio track

The audio is re-encoded along with the picture. video.audio_quality sets its bitrate with the same tiers as audio files: tiny 64, low 96, balanced 128, high 192 (the default) and maximum 320 kbit/s.

To drop the sound altogether, for a background loop or a silent screen recording, set video.strip_audio to true.

a silent 720p WebM
"options": {
  "video": { "format": "webm", "quality": "web", "resolution": "1280", "strip_audio": true }
}

When the original is kept

A video that is already well compressed can come out larger. When the first encode is larger than the input, the job encodes once more with the CRF raised by 4 (to at most 35 for H.264 and 40 for the others) and the audio at a lower bitrate (192 becomes 160 kbit/s, for example). If you set video.crf yourself, that value is used for the second attempt too.

If the output is still larger than the input, the job succeeds and returns the input file, as its own type, with kept_original: true. Such a job is not billed. Check result.kept_original and result.output_format before you assume the output is in the format you asked for. See Kept original.

Convert a video

To change the container without choosing encoder settings, use the operation convert with options.convert.to:

bash
curl -X POST "https://api.smolmac.com/v1/jobs" \
  -H "Authorization: Bearer $SMOL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "convert",
    "input": { "url": "https://files.example.com/uploads/screen-recording.mov?token=..." },
    "options": { "convert": { "to": "mp4" } }
  }'
convert.toPictureAudio
mp4, mov, mkvH.264 at CRF 18AAC at 192 kbit/s
webmVP9 at CRF 18Opus at 160 kbit/s

Conversion re-encodes at a high quality setting and keeps the resolution. The video options do not apply to it, and the output can be larger than the input. If the aim is a smaller file, use compress with video.format.

Limits

PlanLongest videoLargest file
Pay as you go10 minutes500 MB
Starter60 minutes2 GB
Growth, Scale, Enterprise3 hours5 GB
  • A video that is longer than the plan allows, or whose frame is larger than 100 megapixels, fails with the error code limit_exceeded. A file larger than the plan allows fails with input_fetch_failed when it comes from a URL, and is refused with 413 file_too_large when you create an upload for it.
  • A file with no video track fails with processing_failed. To compress sound only, see Audio.
  • Failed jobs are not billed.

All limits are in Limits.

Billing

Video is billed per started minute of the video. The rate depends on the resolution of the output and on the codec. The resolution band is decided by the shorter side of the output frame, so a portrait video of 1080 by 1920 is in the 1080p band.

Shorter side of the outputH.264, per minuteH.265 or VP9, per minute
Up to 720 pixels$0.02$0.03
Up to 1080 pixels$0.035$0.0525
Above 1080 pixels$0.07$0.105

H.265 and VP9 cost 1.5 times the H.264 rate. The default codec is H.265, so a job with no video.codec is billed at the higher rate.

The example job above ran for 184.6 seconds of video, which is 4 started minutes, at 1080p in H.264: 4 times $0.035 is $0.14. The same job in H.265 would cost 4 times $0.0525, which is $0.21. Scaled down to 720p in H.264 it would cost $0.08.

Jobs that fail and jobs that return the original are free. The billed field of the job says which it was. More in Billing.