Retrieve a job

October 7, 2026 (October 22, 2026)

Table of contents

  1. Request Headers
  2. Responses
  3. Model
  4. Examples
  5. Try It

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

  • jobid is URL-encoded in the path (it contains : and @), for example user%3A12345-user%40example.com-job%3A4aa24347-8099-4624-80ec-fb758db74419.
Request Headers
Authorization: Bearer {API token}
Responses
  • 200 OK

    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."
      }
    }
    
  • 400 Bad Request

    The path value is not a Google Vids jobid.

    {
      "error": "Path parameter jobid (…) is not a valid job id",
      "code": 400
    }
    
  • 401 Unauthorized

    Invalid API token.

    {
      "error": "useapi.net ⁝ Unauthorized",
      "code": 401
    }
    
  • 403 Forbidden

    {
      "error": "This job does not belong to this API token",
      "code": 403
    }
    
  • 404 Not Found

    No such job.

    {
      "error": "Job not found",
      "code": 404
    }
    
  • 410 Gone

    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)
    
Try It