Video transcoding API for uploads

Upload an MP4, MOV or WebM file up to 500 MB, then request MP4, WebM, MOV, animated GIF or HLS by adding parameters to its CDN URL. Thumbnails, trimming and audio extraction use the same URL. Heavy jobs return 202 Accepted while they run: request the same URL again until it returns 200, after which the rendition is served from cache.

How video processing works

  1. Upload

    MP4, MOV or WebM, up to 500 MB

  2. Request a rendition URL

    ?format=webm&width=1280

  3. 202 Accepted

    Re-encode, HLS or GIF queued

  4. Poll the same URL

    Back off between attempts

  5. 200 OK

    Served from cache from then on

Light jobs such as a MOV to MP4 remux return 200 straight away. There are no completion webhooks; readiness is the URL returning 200.

Upload a video

Videos are usually too large to proxy through your own API, so use the presigned flow: your backend asks for a single-use upload URL, the client PUTs the file, your backend confirms. The Go SDK wraps all three steps in UploadPresigned.

import { Dreep } from "dreep";

const dreep = new Dreep({ apiKey: process.env.DREEP_API_KEY });

// Server-side: get a single-use upload URL
const upload = await dreep.presignUpload({
  filename: "launch.mov",
  contentType: "video/quicktime",
  sizeBytes: 184_000_000,
  folder: "videos/2026",
});

// Browser or worker: PUT the raw bytes, then confirm server-side
await fetch(upload.uploadUrl, { method: "PUT", body: file });
const asset = await dreep.confirmUpload({ id: upload.id });

const hls = dreep.url(asset, { format: "m3u8" });
const webm = dreep.url(asset, { format: "webm", videoCodec: "vp9", width: 1280 });
const poster = dreep.url(asset, { format: "webp", width: 1280 });

What one upload gives you

HLS for longer videos

The player fetches small segments as needed instead of downloading one large file, so playback starts sooner and seeking does not re-download the video.

MP4 and WebM fallbacks

H.264 MP4 for the widest playback support, VP9 WebM where you want smaller files, both from the same source and the same URL pattern.

Posters, previews and clips

A thumbnail at any second, a short GIF for hover previews, or a trimmed highlight, without running a separate FFmpeg pipeline.

Audio on its own

Request mp3, wav or aac to strip the video track, for podcast feeds or as input to your own transcription step.

Common renditions as URLs

  • 720p MP4, H.264

    https://cdn.dreep.cloud/api/v1/fetch/2f928a3f.mp4?width=1280&height=720&fit=contain&videoCodec=h264&quality=80
  • WebM, VP9

    https://cdn.dreep.cloud/api/v1/fetch/2f928a3f.mp4?format=webm&videoCodec=vp9&width=1280
  • HLS manifest and segments

    https://cdn.dreep.cloud/api/v1/fetch/2f928a3f.m3u8
  • 15-second clip from 0:10

    https://cdn.dreep.cloud/api/v1/fetch/2f928a3f.mp4?trimStart=10&trimEnd=25
  • 3-second GIF preview at 12 fps

    https://cdn.dreep.cloud/api/v1/fetch/2f928a3f.gif?trimStart=0&trimEnd=3&fps=12&width=480
  • Thumbnail at 5 seconds

    https://cdn.dreep.cloud/api/v1/fetch/2f928a3f.mp4?format=webp&time=5&width=640
  • Audio track as MP3

    https://cdn.dreep.cloud/api/v1/fetch/2f928a3f.mp4?format=mp3

Video parameters

ParameterValuesWhat it does
formatmp4, webm, mov, gif, hls or m3u8Output container. An image format (jpeg, png, webp) returns a thumbnail; mp3, wav or aac returns the audio track.
width, heightPixelsTarget resolution.
fitcover, contain, fillScaling when both width and height are set.
quality1 to 100 (default 80)Encoding quality.
videoCodech264, vp9, hevcVideo codec. H.264 is the default for broad playback support.
fps1 to 120Output frame rate. Lower it for GIFs to keep them small.
trimStart, trimEndSecondsCut a clip from the source.
timeSecondsFrame to capture for a thumbnail. Values past the end use the last frame.
pA preset keyApplies a saved video preset, e.g. a 720p HLS recipe.
Inputs: MP4, MOV and WebM. Conversions stay within video, HLS, GIF, thumbnail and audio outputs.

The async model, in detail

A remux, such as MOV to MP4 without re-encoding, is handled inline and returns 200. Re-encodes, HLS packaging and GIF conversion run in the background. The first request returns 202 Accepted. A browser that sends Accept: text/html gets a processing page that refreshes itself. An API client gets a JSON body, { "error": "Asset is processing" }. Once the job finishes, the same URL returns 200 and the rendition is served from cache.

There are no completion webhooks or job callbacks today, so readiness is something you poll for. Good practice: warm the renditions you need from a background job straight after confirm, so viewers rarely meet a 202. Start polling at around 2 seconds, double the delay each time up to about 30 seconds, add a little jitter, and stop after a bounded number of attempts and try again later rather than polling forever. Treat any status other than 200 or 202 as a failure and surface it. Once a URL returns 200, store it and stop polling.

Polling a rendition until it is ready

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Resolves when the rendition is ready; does not download the body
const waitForRendition = async (url, { maxAttempts = 15 } = {}) => {
  let delay = 2000;

  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const res = await fetch(url, { headers: { Accept: "application/json" } });
    await res.body?.cancel();

    if (res.status === 200) return url;
    if (res.status !== 202) throw new Error(`Transform failed: ${res.status}`);

    await sleep(delay + Math.random() * 500); // jitter
    delay = Math.min(delay * 2, 30_000);
  }

  throw new Error("Still processing; try again later");
};

const ready = await waitForRendition(dreep.url(asset, { format: "m3u8" }));

HLS playback with hls.js

Use the .m3u8 URL as the source. Safari plays HLS natively; Chrome and Firefox need a library such as hls.js. Request the manifest once after upload to warm it, so viewers get a 200 rather than a 202.

import Hls from "hls.js";

const video = document.querySelector("video");
const src = "https://cdn.dreep.cloud/api/v1/fetch/2f928a3f.m3u8";

if (Hls.isSupported()) {
  const hls = new Hls();
  hls.loadSource(src);
  hls.attachMedia(video);
} else if (video.canPlayType("application/vnd.apple.mpegurl")) {
  // Safari plays HLS natively
  video.src = src;
}

Video transformation quotas and add-ons

When you reach a limit the API returns LIMIT_EXCEEDED (a DreepLimitError in the JavaScript SDK). Nothing is billed automatically: you buy a pack or upgrade. Size your plan around the renditions you need per upload. HLS, an MP4 fallback and a GIF preview are three different transformations of the same video.

PlanPriceVideo transformations / monthStorage
Free$0201 GB
Starter$2.99/mo or $29/yr1,00010 GB
Pro$5.99/mo or $59/yr4,00050 GB
Extra video transformations are one-time packs: +10,000 for $29, +50,000 for $119, +100,000 for $199. Prices in USD.

Who this is for

  • Apps that accept user video uploads and need web-friendly MP4, WebM or HLS renditions.
  • Teams that want thumbnails, GIF previews and clips without running FFmpeg workers.
  • Products where a short processing delay after upload is acceptable.

When Dreep is not the right fit

  • You need job completion webhooks or callbacks. Dreep has none today; you poll the URL.
  • You need live streaming. Dreep processes uploaded files only.
  • You need DRM for premium content. Signed URLs limit access, but they are not DRM.
  • You want a hosted video player. Dreep delivers files and HLS manifests; you bring the player.
  • Your source files are larger than 500 MB.

Frequently asked questions

How do I know when a video transcode has finished?

Request the rendition URL. 202 Accepted means it is still processing; 200 means it is ready and cached. Poll with exponential backoff. There are no completion webhooks today.

Which input and output formats are supported?

Inputs are MP4, MOV and WebM up to 500 MB. Outputs are MP4, WebM, MOV, animated GIF and HLS (m3u8 manifest and segments), plus thumbnails in JPEG, PNG or WebP and audio in MP3, WAV or AAC.

How do I play HLS from Dreep?

Request the asset with a .m3u8 extension or format=hls. Safari plays it natively; in other browsers use a library such as hls.js and attach it to a video element.

How do I generate a video thumbnail?

Request an image format on the video with the time parameter, for example ?format=webp&time=5. If time is past the end of the video, the last frame is used.

What counts as a video transformation?

Requesting a transformed rendition of a video, such as an HLS package, a WebM encode, a GIF or a thumbnail, uses your monthly video transformation quota: 20 on Free, 1,000 on Starter and 4,000 on Pro. Image transformations have a separate quota.

Can I keep videos private?

Yes. Upload into a Signed folder and serve renditions through time-limited signed URLs. Transform parameters can still vary on a signed URL.

Related

Turn one upload into MP4, HLS and a poster frame

The Free plan includes 20 video transformations a month. Upload a clip and request its HLS manifest.