Upscale a video to 1080p
October 7, 2026
Table of contents
Turn a 720p clip made by this API into 1080p: 1280×720 becomes 1920×1080 and 720×1280 becomes 1080×1920. The clip keeps its length and aspect ratio, and the result has a new mediaId. The job runs on the account that made the clip.
The source is a video mediaId from POST /videos, POST /videos/extend or POST /videos/edit. A clip that is already 1080p is refused with 400.
Cost
An upscale uses the clip’s full length in seconds again from the account’s monthly Vids video allowance: upscaling an 8-second clip uses 8 seconds. Since 720p and 1080p cost the same when you generate, set resolution: "1080p" on POST /videos when you know you want it. An extend can also return a 720p clip at 1080p and is charged only the seconds it adds.
Sync, async and webhooks
- Every generation runs as a job on our side, with up to 15 minutes for Google’s answer, so a slow answer is never lost.
- Sync (the default): the POST waits for the job and answers
200with the finished job record, or the job’s error code. A video usually takes 20 to 100 seconds, an image about 10. If the job is still running after about 100 seconds, the POST answers202with the job as it stands: fetch the result with GET /jobs/jobid. Always checkstatus: onlycompletedhas aresult. - Async: pass
async: trueor areplyUrl. The POST answers202at once with the job instatus: "pending". Poll GET /jobs/jobidor wait for the webhook. replyUrlreceives onePOSTof the final job record, as JSON, when the job completes or fails.- Each account runs at most
maxJobsjobs at a time (default3, range1to10, set with POST /accounts). GET /jobs shows what is running. Job records are kept for 30 days.
https://api.useapi.net/v1/google-vids/videos/upscale
Request Headers
Authorization: Bearer {API token}
Content-Type: application/json
# Alternatively you can use multipart/form-data
# Content-Type: multipart/form-data
API tokenis required, see Setup useapi.net for details.
Request Body
{
"mediaId": "user:[email protected]:eyJ1IjoiaHR0…",
"async": true,
"replyUrl": "https://your-domain.com/webhook",
"replyRef": "boat-1080p"
}
mediaIdis required, the videomediaIdof a720pclip, from a finished job’sresult.asyncis optional,trueto answer202at once and run the job in the background. Default:false.replyUrlis optional, a publichttp(s)URL that receives onePOSTof the job record when the job completes or fails. Setting it also makes the request async.
Callback body has the same JSON shape as GET /jobs/jobidresponse.
Maximum length:1024characters.replyRefis optional, your own reference echoed back in the job record.
Maximum length:1024characters.
Responses
-
200 OK — sync mode, a 3-second
720pclip upscaled to1080p, charged 3 seconds.{ "jobid": "user:[email protected]:3fe9115f-a433-40f5-b7c0-60ad390a124e", "type": "video", "mode": "upscale", "email": "[email protected]", "status": "completed", "created": "2026-10-07T06:27:55.554Z", "request": { "mediaId": "user:[email protected]:eyJ1IjoiaHR0…" }, "updated": "2026-10-07T06:28:19.945Z", "completed": "2026-10-07T06:28:19.945Z", "result": { "mediaId": "user:[email protected]:eyJ1IjoiaHR0…", "width": 1920, "height": 1080, "duration": 3, "resolution": "1080p", "aspectRatio": "landscape", "model": "/flix/upsample_video/v1", "quota": { "video": { "limit": 10000, "left": 9624, "resetAt": "2026-11-01T07:00:00.000Z" } }, "elapsedMs": 24339 } } -
202 Accepted — the job is running: with
async: trueorreplyUrlat once, in sync mode after about 100 seconds of waiting. Fetch the result with GET /jobs/jobid(or wait for the webhook). -
400 Bad Request —
mediaIdis missing or invalid, or the clip is already1080p.{ "error": "This clip is already 1080p", "code": 400 }{ "error": "Parameter mediaId is required", "code": 400 } -
Invalid API token.
{ "error": "useapi.net ⁝ Unauthorized", "code": 401 } -
403 Forbidden — the
mediaIdwas issued to a different API token.{ "error": "video id does not belong to this API token", "code": 403 } -
404 Not Found — the account that made the clip is no longer connected.
{ "error": "Account [email protected] (from the video id) is not configured", "code": 404 } -
429 Too Many Requests — the account is running
maxJobsjobs, the month’s video allowance is used up (error.retryAtis the reset time), or Google is limiting the account for a minute.{ "error": "Account [email protected] is running 3 of 3 jobs (maxJobs). Wait for one to finish, or raise maxJobs with POST /accounts", "code": 429 } -
504 Gateway Timeout — Google did not answer within 15 minutes, or the connection to Google was cut. Google may still finish the job and charge it, but the result cannot be retrieved: run it again.
-
596 Account Error
Google reported the account as signed out. While we re-check it, the answer is the first message below. Retry in about a minute. If it stays signed out, the account is paused, you receive an email, and the answer becomes the second message until you re-add it via Setup Google Vids.
{ "error": "Google reported this account as signed out. We are re-checking it — please retry in about a minute. If it stays signed out, you will receive a re-add email.", "code": 596 }{ "error": "Account [email protected]: Google signed this account out. Re-add it at https://useapi.net/docs/start-here/setup-google-vids", "code": 596 }
Model
The job record, mode: "upscale". GET /jobs/jobid and the replyUrl webhook return the same shape.
{ // TypeScript, all fields are optional
jobid: string // user:<id>-<email>-job:<uuid>
type: 'video' | 'image'
mode?: 'text' | 'image' | 'ingredients' | 'extend' | 'upscale' | 'edit' // video jobs only
email: string // the account the job runs on
status: 'pending' | 'processing' | 'completed' | 'failed'
created: string // ISO 8601, when the job was accepted
updated?: string // ISO 8601, the last status change
completed?: string // ISO 8601, when the job completed or failed
request: Record<string, unknown> // your request body as sent (ids as strings)
replyUrl?: string
replyRef?: string
error?: { // status 'failed'
code: number // 400 | 403 | 404 | 422 | 429 | 500 | 502 | 503 | 504 | 596, see GET /jobs/{jobid}
message: string
retryAt?: string // code 429: ISO 8601, when to try again
}
result?: { // status 'completed'
mediaId: string // download it with GET /media/{mediaId}. A video: extend / upscale / edit it. An image: use it as startImage, referenceImage_N or avatar image
width: number
height: number
duration?: number // video: length of the whole clip in seconds
resolution?: '720p' | '1080p' // video
aspectRatio?: 'landscape' | 'portrait' // video
model: string | null // Google's backend path, e.g. /flix/generate_videos_omni_t2v_psq/v1
quota: { // what the account has left after this job
video?: { limit: number, left: number, resetAt: string } // seconds, video jobs
image?: { limit: number, left: number, resetAt: string } // images, image jobs
}
elapsedMs: number // how long Google took
}
}
Examples
-
curl -X POST "https://api.useapi.net/v1/google-vids/videos/upscale" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer …" \ -d '{ "mediaId": "user:[email protected]:eyJ1IjoiaHR0…" }' -
const token = "API token"; const mediaId = "mediaId of a 720p clip made by this API"; const apiUrl = "https://api.useapi.net/v1/google-vids/videos/upscale"; const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}`, }, body: JSON.stringify({ mediaId }) }); const job = await response.json(); console.log("response", response.status, job.result ?? job.error ?? job); -
import requests token = "API token" mediaId = "mediaId of a 720p clip made by this API" apiUrl = "https://api.useapi.net/v1/google-vids/videos/upscale" headers = { "Content-Type": "application/json", "Authorization" : f"Bearer {token}" } response = requests.post(apiUrl, headers=headers, json={"mediaId": mediaId}) print(response, response.json())