MOV to MP4 conversion API
Convert MOV to MP4 on the server with one HTTP call, instead of running ffmpeg with the right codecs yourself. Submit, poll, download. 50 free conversions a month, then pay per use.
Convert MOV to MP4 in three requests
Authenticate with a bearer key from your backend (never ship the key to the browser). Submit the conversion, upload the file to the presigned URL, poll until it is done, and download the result.
curl
# 1. Submit the conversion
curl -X POST https://hushvert.com/api/v1/conversions \
-H "Authorization: Bearer $HUSHVERT_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "pair": "mov-to-mp4", "bytes": '$(wc -c < input.mov)' }'
# -> { "jobId": "...", "uploadUrl": "...", "pollUrl": "/api/v1/conversions/..." }
# 2. Upload the file to the presigned uploadUrl
curl -X PUT "$UPLOAD_URL" --data-binary @input.mov
# 3. Poll until done, then download
curl https://hushvert.com/api/v1/conversions/$JOB_ID \
-H "Authorization: Bearer $HUSHVERT_KEY"
# -> { "status": "done", "downloadUrl": "...", "expiresAt": "..." }
curl -o output.mp4 "$DOWNLOAD_URL"Node.js
import { readFile, writeFile } from 'node:fs/promises'
const KEY = process.env.HUSHVERT_KEY
const bytes = await readFile('input.mov')
// 1. Submit
const submit = await fetch('https://hushvert.com/api/v1/conversions', {
method: 'POST',
headers: { authorization: `Bearer ${KEY}`, 'content-type': 'application/json' },
body: JSON.stringify({ pair: 'mov-to-mp4', bytes: bytes.byteLength }),
}).then((r) => r.json())
// 2. Upload to the presigned URL
await fetch(submit.uploadUrl, { method: 'PUT', body: bytes })
// 3. Poll until done
let job
do {
await new Promise((r) => setTimeout(r, 1500))
job = await fetch(`https://hushvert.com${submit.pollUrl}`, {
headers: { authorization: `Bearer ${KEY}` },
}).then((r) => r.json())
} while (job.status !== 'done' && job.status !== 'failed')
// 4. Download
const out = await fetch(job.downloadUrl).then((r) => r.arrayBuffer())
await writeFile('output.mp4', Buffer.from(out))Python
import os, time, requests
KEY = os.environ["HUSHVERT_KEY"]
data = open("input.mov", "rb").read()
# 1. Submit
submit = requests.post("https://hushvert.com/api/v1/conversions",
headers={"Authorization": f"Bearer {KEY}"},
json={"pair": "mov-to-mp4", "bytes": len(data)}).json()
# 2. Upload to the presigned URL
requests.put(submit["uploadUrl"], data=data)
# 3. Poll until done
job = {}
while job.get("status") not in ("done", "failed"):
time.sleep(1.5)
job = requests.get(f"https://hushvert.com{submit['pollUrl']}",
headers={"Authorization": f"Bearer {KEY}"}).json()
# 4. Download
out = requests.get(job["downloadUrl"]).content
open("output.mp4", "wb").write(out)Limits and pricing
| Free per month | 50 conversions per account, then pay per use from account credits. |
|---|---|
| Max file size | 500 MB |
| Privacy | Input deleted the moment the conversion finishes; output kept about an hour, then deleted. |
See the full request, error codes, and idempotency reference on the API keys page, and the plans on pricing.
Why an API for this?
Transcoding video is CPU-heavy and the files are large; it will time out a serverless function or pin a user-facing box. The API runs it on dedicated workers and hands back a download link.
Everything a browser can do (images, HEIC, audio, archives, PDF page operations) runs free and on-device in the open-source @hushvert/engine SDK - no upload, no key. This API is only for MOV to MP4 and the other server-only formats.
What is MOV?
MOV is the QuickTime container Apple has shipped since the early 1990s and still records on iPhone and Mac today. Structurally it is the direct ancestor of MP4, usually carrying H.264 or HEVC video, but the .mov wrapper itself is what trips up Windows apps, Android phones and many upload forms. Rewrapping or transcoding to MP4 keeps the picture and makes the file land everywhere.
What is MP4?
MP4 is the default container of modern video: phones record into it, cameras export it, and every browser, TV and editing tool plays it, usually carrying H.264 video and AAC audio. Being a container, an MP4 is really a box around separate video and audio tracks, which is why useful conversions include not just other video formats but also pulling the audio track out on its own.
MOV to MP4 API FAQ
How do I convert MOV to MP4 with an API?
Send a POST to /api/v1/conversions with the pair and the byte count, upload the file to the presigned URL it returns, then poll until the job is done and download the result. It is three short requests; full code is above in curl, Node, and Python.
Why not just convert MOV to MP4 myself?
You can, if you want to run and maintain ffmpeg with the right codecs. Transcoding video is CPU-heavy and the files are large; it will time out a serverless function or pin a user-facing box. The API runs it on dedicated workers and hands back a download link.
What does it cost?
Every account gets 50 free conversions per month across all of its keys. Beyond that, the API draws on account credits, billed per conversion. Everything a browser can do is free and keyless in the open-source SDK.
What happens to my file?
The file uploads over an encrypted connection. The input is deleted the moment the conversion finishes; the converted output is kept for about an hour so you can download it, then deleted too.
Can my AI agent do this conversion?
Yes. The @hushvert/mcp Model Context Protocol server gives Claude Code, Cursor, and other agents a convert_file tool over this same API, so an agent can run the conversion in one call.