Skip to content

DocsGuides

AI upscale

Raise a video to 1080p, 1440p or 4K with AI, see what it reserves first, and read how it was enhanced.

POST /v1/ai-upscale raises one video to 1080p, 1440p or 4k with AI. It can also double a frame rate of 30 fps or less for smoother motion. The input must be at most 1920 by 1080 and smaller than the target. Only purchased credits pay for it, and each plan has its own targets and longest clip.

The request#

bash
curl "$VIDEXO_API_URL/v1/ai-upscale" \
  -H "Authorization: Bearer $VIDEXO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "input": "https://example.com/talk.mp4",
  "resolution": "1080p",
  "trim": {
    "start": 0,
    "duration": 5
  },
  "filename": "talk-1080p.mp4"
}'
FieldWhat it does
inputThe video: a public https URL or a videxo://uploads/<id> upload.
resolutionThe target: 1080p, 1440p or 4k.
frame_ratesource (default) keeps the input's rate, at most 60 fps: a faster input comes out at 60. smooth doubles a rate of 30 fps or less, so 24 fps becomes 48 and 30 becomes 60; a faster input keeps its rate, at most 60 fps.
trimThe part to upscale: start in seconds (0 by default) and duration, at least 1 second and at most your plan's longest clip. Without duration the job runs to the end of the input, up to that limit.
audiokeep (default) puts the input's own sound back in sync; remove leaves the output silent.
filenameThe stored file name, .mp4 only; upscaled.mp4 by default.
webhook_url, metadataAs on every job.

The same upscale can be one output of POST /v1/jobs: "type": "ai_upscale" with the fields above and input naming one of the job's inputs. An AI upscale job has that one output only.

The answer is the Job, queued, as for any job. It has no ffmpeg command: its command, input_files, output_files and ffmpeg_command are null, and steps is empty.

Estimate first#

POST /v1/ai-upscale/estimate takes the same body and answers what the job would reserve under your plan, and how long its processing is expected to take. It makes no job, fetches nothing and uses no credits.

bash
curl "$VIDEXO_API_URL/v1/ai-upscale/estimate" \
  -H "Authorization: Bearer $VIDEXO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "input": "https://videxo.io/samples/talk.mp4",
  "resolution": "1080p",
  "trim": {
    "start": 0,
    "duration": 8
  }
}'

On Pay as you go:

JSON
{
  "operation": "ai_upscale",
  "max_seconds": 8,
  "credits_base": 75,
  "credits_per_second": 64,
  "credits_max": 587,
  "expected_wait_seconds": {
    "low": 146,
    "high": 446
  },
  "frame_rate_bands": {
    "up_to_30_fps": {
      "credits_per_second": 32,
      "credits_max": 331,
      "expected_wait_seconds": {
        "low": 73,
        "high": 373
      }
    },
    "above_30_fps": {
      "credits_per_second": 64,
      "credits_max": 587,
      "expected_wait_seconds": {
        "low": 146,
        "high": 446
      }
    }
  }
}

The input is not read, so the clip is trim.duration, or your plan's longest clip without one, and both frame-rate bands are given. credits_max is the higher band: 587 credits for this 8 second clip, against 331 if it turns out to be 30 fps or less. expected_wait_seconds is the time the AI processing is expected to take, a usual case (low) and a slow one (high); the slow one includes the time to start a GPU.

How the input's size decides#

The upscale always runs the AI model, then corrects its colour and keeps blur the input meant to have. How much of the model's own detail stays depends on how small the input is next to the frame the result fills: the target's frame fitted to the input's shape, turned for a portrait input. A 16:9 input fills the whole frame; a 4:3 input at 1080p fills 1440 by 1080.

  • full: an input under half that frame on both sides. The model adds detail the input does not have.
  • faithful: an input of half that frame or more on either side. The result is a faithful enhancement, close to a sharp resize: the model's detail is kept only above the input's own resolution.
resolutionTarget frameA 16:9 input is full when under
1080p1920 by 1080960 by 540
1440p2560 by 14401280 by 720
4k3840 by 21601920 by 1080

So 960 by 540 to 1080p is faithful, 958 by 538 to 1080p is full, and a 1280 by 720 input is faithful at 1080p and 1440p and full at 4k. Each job's output shows which way it ran in its enhancement, once the job has read the input. The estimate cannot say, since it does not read the input.

What it costs#

An upscale is billed per second of output, by its target and its output's frame rate, plus 75 credits a job and the data used, as for every job:

TargetUp to 30 fpsAbove 30 fps
1080p32 credits per output second64 credits per output second
1440p55 credits per output second110 credits per output second
4K119 credits per output second238 credits per output second
  • The rate follows the output's frame rate. smooth doubles a rate of 30 fps or less, up to 60: a 24 or 30 fps input made smooth is billed above 30 fps, a 15 fps one (30 fps out) up to it.
  • Seconds are the output's length, rounded up to the whole second as for every job, and at least 1.
  • Only purchased credits pay for it, from a plan or a top-up. Free credits never do: a job they would have to pay for is refused with 402 out_of_credits (purchased_credits_only) before it is made.
  • Creating the job reserves the estimate's credits_max. When it succeeds, it pays the rate of the clip it made and the 75 credits. A job you cancel while it is being processed pays for the seconds already processed and the 75 credits. A job that fails pays at most the data it fetched.

The pricing page has the same table in dollars.

Limits per plan#

The longest clip each plan upscales, after trim:

Plan1080p1440p4KAI jobs at once
Pay as you go10 s10 snot included1
Starter10 s10 snot included1
Pro20 s20 s10 s3
Scale20 s20 s20 s5

A target your plan does not include is refused with 413 limit_exceeded (media_resolution), and a trim.duration over its longest clip with 413 limit_exceeded (media_duration), both before any job is made. AI jobs also count toward your plan's jobs at once.

The wait#

expected_wait_seconds is a planning figure, not a promise. When there is no free GPU capacity, the job waits for it. If processing cannot start in time, which can happen up to about 90 minutes after the job took one of your plan's jobs at once (time queued for a free one comes on top), the job ends failed with service_unavailable (temporary) and nothing is charged. Send it again later.

The job#

Once the job has read the input, it shows what the clip will cost and how long it should take:

JSON
{
  "ai": {
    "seconds": 5,
    "credits": 235,
    "expected_wait_seconds": { "low": 46, "high": 346 }
  },
  "outputs": [
    {
      "name": "video",
      "filename": "talk-1080p.mp4",
      "enhancement": "faithful"
    }
  ]
}
  • ai.seconds: the clip's billed seconds.
  • ai.credits: what a success costs at the clip's frame rate, with the 75 credits, before the data used.
  • ai.expected_wait_seconds: the planning wait of this clip.
  • outputs[].enhancement: full or faithful, as above. It is null on every other output.

ai is null until the input is read, and on every job that is not AI. The job's progress and its webhook work as for every job. The output is an H.264 MP4 that fills the frame above. It says in its metadata that it was enhanced with AI, and it carries our signed C2PA manifest.

Errors#

AnswerWhenCharged
400 invalid_requestA field is missing, unknown or out of range, with errors naming it.Nothing: no job.
402 out_of_credits (purchased_credits_only)Only free credits are left to pay for it.Nothing: no job.
413 limit_exceeded (media_resolution, media_duration)Your plan does not include the target, or trim.duration is over its longest clip.Nothing: no job.
503 service_unavailable (temporary)AI upscale is not available right now.Nothing: no job. Send it again later.
Job failed, limit_exceeded (media_resolution)The input is larger than 1920 by 1080, or not smaller than the target.The data fetched.
Job failed, limit_exceeded (media_duration)The clip after trim is shorter than 1 second, or longer than allowed.The data fetched.
Job failed, processing_failed (media_unsupported)The input could not be read as a video.The data fetched.
Job failed, service_unavailable (temporary, processing_timeout)No capacity in time, or the processing did not finish in time.Nothing.
Job failed, internal_errorOur side failed.Nothing.

Every code is on the errors page.

With MCP#

An AI assistant connected to the MCP server has the same two calls as the tools estimate_ai_upscale and ai_upscale, with the same body.