Create an upscale

POST /api/v1/upscale — charge credits for a video and start upscaling it to 1080p, 2K or 4K. Accepts MP4, MOV and WebM files up to 600 seconds long.

POST https://videoupscaler.co/api/v1/upscale

Starts an upscale and returns the new task. We download the video, read its real duration from the file and charge credits for it before the job starts. You never send the duration yourself.

Request

Headers

HeaderRequiredDescription
AuthorizationYesBearer <your API key>
Content-TypeYesapplication/json
Idempotency-KeyRecommendedAny string of 1–255 printable ASCII characters. Retrying with the same key never charges twice. See Idempotency.

Body

FieldTypeRequiredDescription
video_urlstringYesA public http(s) URL of the video, or the video_url returned by /uploads.
resolutionstringYes1080p, 2k or 4k.

Video requirements

  • Formats: MP4, MOV and WebM.
  • Length: up to 1200 seconds at 1080p, 600 seconds at 2k and 4k.
  • Size: up to 500MB for a remote video_url, 100MB through /uploads.
  • The server at video_url must answer a plain GET with the file and a Content-Length header. Signed links from S3, R2 or Google Cloud Storage work. Share pages such as YouTube or Google Drive previews do not.
  • Fragmented MP4 files without a total duration are rejected. Re-encode them into a regular MP4 first.
  • WebM files must store their duration in the header. Recordings made in a browser (MediaRecorder) often don't; re-encode them first.

Example

curl https://videoupscaler.co/api/v1/upscale \
  -H "Authorization: Bearer $VIDEOUPSCALER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1234" \
  -d '{"video_url": "https://example.com/clip.mp4", "resolution": "2k"}'
const res = await fetch('https://videoupscaler.co/api/v1/upscale', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.VIDEOUPSCALER_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'order-1234',
  },
  body: JSON.stringify({ video_url: 'https://example.com/clip.mp4', resolution: '2k' }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
const task = await res.json();
res = requests.post(
    "https://videoupscaler.co/api/v1/upscale",
    headers={
        "Authorization": f"Bearer {os.environ['VIDEOUPSCALER_API_KEY']}",
        "Idempotency-Key": "order-1234",
    },
    json={"video_url": "https://example.com/clip.mp4", "resolution": "2k"},
    timeout=300,
)
res.raise_for_status()
task = res.json()

Response

201 Created with the task:

{
  "id": "0b6f3c1e-8a52-5d1e-9c43-3f1d2e7a9b10",
  "status": "processing",
  "resolution": "2k",
  "video_url": "https://example.com/clip.mp4",
  "duration_seconds": 12.4,
  "processed_seconds": 12.4,
  "credits_charged": 26,
  "watermark": false,
  "output_url": null,
  "thumbnail_url": null,
  "error": null,
  "created_at": "2026-09-30T08:00:00.000Z",
  "updated_at": "2026-09-30T08:00:02.000Z"
}

Then poll the task until it is completed.

This request downloads the video before it answers, so a large remote file can take a while. Allow up to 5 minutes before timing out.

Idempotency

Send an Idempotency-Key with every request and reuse it when you retry after a timeout or network error:

  • The same key with the same video_url and resolution returns the original task with 200 OK. You are not charged again.
  • The same key with a different video_url or resolution returns 409 idempotency_conflict.
  • Without the header, every request creates and charges a new task.

Billing

The price is the video's length in whole seconds (rounded up) times the rate for the resolution. See Credits & pricing. A 12.4-second video at 2K costs 13 × 2 = 26 credits.

If the job fails, the credits are refunded automatically and the task becomes failed.

Errors

StatusCodeWhen
400invalid_requestMissing or invalid video_url, resolution or Idempotency-Key
401unauthorizedMissing or invalid API key
403paid_plan_requiredThe account has never bought credits or subscribed
402insufficient_creditsYour balance can't cover the video
409idempotency_conflictThe Idempotency-Key was used with different parameters
413file_too_largeThe video is larger than 500MB
422video_fetch_failedWe couldn't download video_url
422unsupported_videoNot a readable MP4, MOV or WebM, or its duration is missing
422video_too_longThe video is longer than the limit for its resolution (1200 seconds at 1080p, 600 at 2k and 4k)
422video_not_foundAn uploaded video_url has no file (the upload didn't finish)
504upstream_timeoutDownloading video_url took longer than 4 minutes

See Errors for the error format.