Retrieve a job
October 7, 2026 (October 22, 2026)
Table of contents
Fetch a job record by its jobid. Every generation is a job: POST /videos, POST /videos/extend, POST /videos/upscale, POST /videos/edit and POST /images all return one. After an async request, poll this endpoint until status is completed or failed.
A video takes about 20 to 100 seconds and an image about 10, so polling every 10 seconds is enough. A job may run for up to 15 minutes, and a sync POST that answered 202 hands you a job that is still running. A job still not finished about 16 minutes after it was created is failed with 504 when it is read.
Instead of polling, pass replyUrl (and optionally replyRef) with the POST: when the job completes or fails, the API sends one POST of this same job record, as JSON, to that URL. See Model.
Job records are kept for 7 days. After that the job answers 410.
https://api.useapi.net/v1/google-vids/jobs/
jobid
jobidis URL-encoded in the path (it contains:and@), for exampleuser%3A12345-user%40example.com-job%3A4aa24347-8099-4624-80ec-fb758db74419.
Request Headers
Authorization: Bearer {API token}
API tokenis required, see Setup useapi.net for details.
Responses
-
Completed (an async text-to-video job):
{ "jobid": "j1007155127045518215v-u12345-email:[email protected]:google-vids", "type": "video", "mode": "text", "email": "[email protected]", "status": "completed", "created": "2026-10-07T06:29:01.204Z", "request": { "prompt": "A hot air balloon rising over a misty valley at sunrise", "duration": 3, "async": true }, "updated": "2026-10-07T06:29:27.207Z", "completed": "2026-10-07T06:29:27.207Z", "result": { "mediaId": "user:[email protected]:eyJ1IjoiaHR0…", "width": 1280, "height": 720, "duration": 3, "resolution": "720p", "aspectRatio": "landscape", "model": "/flix/generate_videos_omni_t2v_psq/v1", "quota": { "video": { "limit": 10000, "left": 9615, "resetAt": "2026-11-01T07:00:00.000Z" } }, "elapsedMs": 24611 } }Running:
{ "jobid": "j1007155127045518215v-u12345-email:[email protected]:google-vids", "type": "video", "mode": "text", "email": "[email protected]", "status": "processing", "created": "2026-10-07T06:29:01.204Z", "request": { "prompt": "A hot air balloon rising over a misty valley at sunrise", "duration": 3, "async": true }, "updated": "2026-10-07T06:29:02.461Z" }Failed (Google refused an edit of an uploaded video):
{ "jobid": "j1007123831345945676v-u12345-email:[email protected]:google-vids", "type": "video", "mode": "edit", "email": "[email protected]", "status": "failed", "created": "2026-10-07T06:36:31.478Z", "request": { "video": "user:[email protected]:…", "duration": 4, "prompt": "Make the sky stormy and dark" }, "updated": "2026-10-07T06:36:41.176Z", "completed": "2026-10-07T06:36:41.176Z", "error": { "code": 422, "message": "Google refused this request (\"That request looks like it goes against our terms. Try asking something else.\"). Change the prompt or the inputs and try again." } } -
The path value is not a Google Vids
jobid.{ "error": "Path parameter jobid (…) is not a valid job id", "code": 400 } -
Invalid API token.
{ "error": "useapi.net ⁝ Unauthorized", "code": 401 } -
{ "error": "This job does not belong to this API token", "code": 403 } -
No such job.
{ "error": "Job not found", "code": 404 } -
The job has expired: job records are kept for 7 days.
{ "error": "Job has expired", "code": 410 }
Model
The job record. POST /videos, POST /videos/extend, POST /videos/upscale, POST /videos/edit and POST /images return it too, and it is the body of the replyUrl webhook.
{ // TypeScript, all fields are optional
jobid: string // j<time><random><v|i>-u<id>-email:<email>-bot:google-vids
type: 'video' | 'image'
mode?: 'text' | 'image' | 'ingredients' | 'extend' | 'upscale' | 'edit' // video jobs only
email: string // the account the job runs on
status: '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
quota?: { // code 429 for allowance: Google's counter for this kind of job when it refused it
limit: number // monthly limit (seconds of video, or images)
left: number // what was left, 0 when used up
resetAt: string // ISO 8601, when the allowance resets
}
}
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
}
}
status | Meaning |
|---|---|
processing | Google is generating. Every job starts here. |
completed | Done. result.mediaId downloads the file with GET /media/mediaId. |
failed | Done without a file. error says why. |
A job sent without email and without input ids can change email while it runs: when Google refuses it because that account’s allowance is used up or its smart features are off, it moves to another of your accounts, never to one whose allowance for that kind of job is used up.
error.code | Meaning |
|---|---|
400 | Google rejected the request as invalid. message has Google’s reason. |
403 | The account’s Google plan has no Vids allowance for this kind of job (a monthly limit of 0), or the account has Google Workspace smart features turned off. |
404 | The account was removed with DELETE /accounts/email before the async job ran. |
422 | Google refused the prompt or the inputs (“That request looks like it goes against our terms”). Nothing was charged. Change the prompt or the inputs. In our tests every edit of an uploaded video ended here. |
429 | The account’s monthly allowance is used up or too low for this job: retryAt is the reset time and quota shows what was left (limit, left, resetAt). A used-up account then gets no jobs of that kind until that time, see GET /accounts. Or Google is limiting the account for a short while, and retryAt is about a minute away. |
500 | An unexpected error on our side. |
502 | Google answered, but without a file the API could read, or with an unexpected error. Google may have made and charged the file, so running it again is not free: report the jobid to support. |
503 | Google answered with a server error or could not be reached, or the async job could not be queued. Retry. |
504 | Google did not answer within 5 minutes, or Google’s answer never reached us within 15 minutes. In the second case Google may have made and charged the file, but it cannot be retrieved. |
596 | Google reported the account as signed out. While we re-check it, retry in about a minute. If it stays signed out, re-add it via Setup Google Vids. |
A sync POST whose job fails answers with the HTTP status in error.code and the failed job record as the body.
The replyUrl webhook is one POST with Content-Type: application/json and this record as the body, sent once when the job completes or fails (a 10-second timeout, no retries, redirects are not followed). Use replyRef to match the callback to your own records.
Examples
-
JOBID="j1007155127045518215v-u12345-email:[email protected]:google-vids" curl -H "Authorization: Bearer …" \ "https://api.useapi.net/v1/google-vids/jobs/$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=''))" "$JOBID")" -
const token = "API token"; const jobid = "j1007155127045518215v-u12345-email:[email protected]:google-vids"; const apiUrl = `https://api.useapi.net/v1/google-vids/jobs/${encodeURIComponent(jobid)}`; let job; do { await new Promise(resolve => setTimeout(resolve, 10000)); const response = await fetch(apiUrl, { headers: { "Authorization": `Bearer ${token}`, }, }); job = await response.json(); console.log(job.status); } while (job.status === "processing"); console.log("job", job); -
import requests, time, urllib.parse token = "API token" jobid = "j1007155127045518215v-u12345-email:[email protected]:google-vids" apiUrl = "https://api.useapi.net/v1/google-vids/jobs/" + urllib.parse.quote(jobid, safe="") headers = { "Authorization" : f"Bearer {token}" } while True: time.sleep(10) job = requests.get(apiUrl, headers=headers).json() print(job.get("status")) if job.get("status") != "processing": break print(job)