Generate an image
October 7, 2026
Table of contents
Generate one image from a prompt with the image generator of Google Vids. Each call returns one JPEG in a fixed size:
aspectRatio | Size |
|---|---|
16:9 (default) | 1376×768 |
1:1 | 1024×1024 |
9:16 | 768×1376 |
Vids image generation is basic: one prompt in, one small image out (about 1 megapixel in every style, no larger size or upscale), and it takes no reference images. It works well for quick video references, avatar pictures and storyboards. For anything better, use the Google Flow API: Nano Banana with reference images, at up to 4K.
How to use the result:
- As an avatar picture: pass its
mediaIdasimageto POST /avatars. - As a
startImageorreferenceImage_Nof POST /videos: pass itsmediaId.
Images carry no visible watermark.
Cost
Each image uses 1 of the account’s monthly Vids images, which are counted per account even on a family plan. A request Google refuses uses nothing. See Plans and monthly allowances.
Sync, async and webhooks
An image normally takes about 10 seconds, and now and then Google takes much longer (in our tests 3 of about 70 images took over 2 minutes). A sync request then answers 202 with the job still running, so nothing is lost: fetch the result with GET /jobs/jobid.
- 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/images
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
{
"prompt": "A red vintage bicycle leaning on a sunny brick wall",
"aspectRatio": "16:9",
"style": "photography",
"async": true,
"replyUrl": "https://your-domain.com/webhook",
"replyRef": "bicycle-1"
}
promptis required, what the image shows.
Maximum length:5000characters.aspectRatiois optional.
Supported values:16:9,1:1,9:16. Default:16:9.styleis optional, one of the style presets of the Vids image panel.
Supported values:none,photography,sketch,background,watercolor,vector-art,cyberpunk. Default:none.emailis optional, the account to run on. When omitted, a healthy account with a freemaxJobsslot and an image allowance is used.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, the image is ready.
{ "jobid": "user:[email protected]:e16a974f-c4ff-4b5a-ba2a-5d6c5c076c82", "type": "image", "email": "[email protected]", "status": "completed", "created": "2026-10-07T06:20:21.951Z", "request": { "prompt": "A red vintage bicycle leaning on a sunny brick wall", "style": "photography" }, "updated": "2026-10-07T06:20:32.213Z", "completed": "2026-10-07T06:20:32.213Z", "result": { "mediaId": "user:[email protected]:eyJ1IjoiaHR0…", "width": 1376, "height": 768, "model": "/flix/edit_image/v1", "quota": { "image": { "limit": 1000, "left": 945, "resetAt": "2026-11-01T07:00:00.000Z" } }, "elapsedMs": 10204 } } -
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).{ "jobid": "user:[email protected]:f8e8da27-d86e-4f89-bcb3-cabf783945cb", "type": "image", "email": "[email protected]", "status": "pending", "created": "2026-10-07T06:29:29.018Z", "request": { "prompt": "A cup of coffee with latte art, top view", "async": true } } -
400 Bad Request — a parameter is missing or invalid, or Google rejected the request.
{ "error": "Parameter style (oil-painting) valid values: none,photography,sketch,background,watercolor,vector-art,cyberpunk", "code": 400 } -
Invalid API token.
{ "error": "useapi.net ⁝ Unauthorized", "code": 401 } -
403 Forbidden — the account’s Google plan has no Vids image allowance. The body is the failed job record with
error.code: 403. -
404 Not Found — the account named by
emailis not connected.{ "error": "Account [email protected] is not configured", "code": 404 } -
422 Unprocessable Content — Google refused the prompt. Nothing was charged. The body is the failed job record, see POST /videos.
-
429 Too Many Requests — the account is running
maxJobsjobs, every account is busy, the month’s images are used up (error.retryAtis the reset time), or Google is limiting the account for a minute.{ "error": "All 2 healthy accounts are running their maximum number of jobs (maxJobs), please retry shortly", "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.
{ "jobid": "user:[email protected]:874b371d-b6a2-43c9-88d5-5989bfe5a951", "type": "image", "email": "[email protected]", "status": "failed", "created": "2026-10-07T05:49:12.411Z", "request": { "prompt": "A red ceramic coffee mug on a plain background" }, "updated": "2026-10-07T05:51:12.469Z", "completed": "2026-10-07T05:51:12.469Z", "error": { "code": 504, "message": "Google did not answer in time (Google did not answer within 900 s). Google may still finish it 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 }Without
email, the same code means no connected account is healthy and has an image allowance:{ "error": "No healthy Google Vids account with an image allowance configured. Check GET /accounts", "code": 596 }
Model
The job record, type: "image". GET /jobs/jobid and the replyUrl webhook return the same shape. An image result has no duration, resolution or aspectRatio.
{ // 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/images" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer …" \ -d '{ "prompt": "A small lighthouse on a rocky island at dusk", "aspectRatio": "9:16", "style": "watercolor" }' -
const token = "API token"; const apiUrl = "https://api.useapi.net/v1/google-vids"; const headers = { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }; const response = await fetch(`${apiUrl}/images`, { method: "POST", headers, body: JSON.stringify({ prompt: "A small lighthouse on a rocky island at dusk", aspectRatio: "9:16", style: "watercolor" }) }); const job = await response.json(); if (job.status === "completed") { const image = await fetch(`${apiUrl}/media/${encodeURIComponent(job.result.mediaId)}`, { headers }); console.log("image bytes", (await image.arrayBuffer()).byteLength); } else console.log("response", response.status, job); -
import requests from urllib.parse import quote token = "API token" apiUrl = "https://api.useapi.net/v1/google-vids" headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"} data = {"prompt": "A small lighthouse on a rocky island at dusk", "aspectRatio": "9:16", "style": "watercolor"} job = requests.post(f"{apiUrl}/images", headers=headers, json=data).json() if job.get("status") == "completed": image = requests.get(f"{apiUrl}/media/{quote(job['result']['mediaId'], safe='')}", headers=headers) with open("image.jpg", "wb") as f: f.write(image.content) else: print(job)