=== useapi.net — universal note === Generated: 2026-10-07 19:51 UTC Authentication (applies to every useapi.net API). Header: Authorization: Bearer user:- Use the COMPLETE token, including the `user:` prefix and the alphanumeric suffix. Do not truncate. Do not URL-encode. A single token authorizes every API under the user's subscription. Service-specific patterns. Identifier names (jobid / taskId / musicId / etc.), job lifecycle, response shapes, webhook semantics, and synchronous-vs-async behavior vary PER API. Use ONLY the service-specific documentation below to determine the correct request body, response shape, polling endpoint, and status values for THIS API. Do not assume conventions from another useapi.net API carry over. For cross-service context (e.g. which APIs expose the same underlying model, billing tiers, model availability matrix), see https://useapi.net/llms.txt === END universal note === === URL: https://useapi.net/docs/start-here/setup-google-vids === Document URL: https://useapi.net/docs/start-here/setup-google-vids --- layout: default title: Setup Google Vids description: "How to connect a Google AI Pro or Ultra account to the useapi.net Google Vids API — automated browser setup, the setup script, or a docs.google.com cookie paste." parent: Start Here nav_order: 209 permalink: /docs/start-here/setup-google-vids --- # Setup Google Vids October 7, 2026 ## Table of contents Approximately 5 minutes to complete setup steps. --- > This is the setup guide for [Google Vids API](/docs/api-google-vids-v1). A [Google](https://accounts.google.com) account on a paid Google AI plan and a [useapi.net subscription](/docs/subscription) are required for the API to work. Free Google accounts get no Vids video or images and are refused. ⚠️ **After you add the account, never open that Google account in a browser again.** Google Vids needs a session cookie that a browser renews about every 10 minutes. If any browser uses the same Google sign-in, it renews that cookie and the copy the API holds stops working within minutes. Google Vids is stricter about this than [Google Flow](/docs/start-here/setup-google-flow) and [Gemini Notebook](/docs/start-here/setup-gemini-notebook). The automated setup and the setup script below both sign in once, in a browser that is closed and deleted afterwards, so only the API uses that session. ### Which Google plan you need Google Vids generates video with Gemini Omni and meters it by plan, as seconds of video and a number of images a month. A free Google account gets 0 seconds of video and 0 images, so [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts) refuses it. Use an account on [Google AI Pro or Ultra](https://one.google.com/ai). - On Google AI Ultra $199 (Google calls it Ultra 20x) the account gets 10,000 seconds of video and 1,000 images a month. - Video seconds are shared by everyone on a Google family plan, and images are counted per account. Adding more family members' accounts adds images but no video seconds. - Allowances reset on the 1st of each month. Google's figures for every plan are on its [Gemini in Google Vids](https://support.google.com/docs/answer/15609411) help page and the [Google Vids API](/docs/api-google-vids-v1) overview. Google Vids does not use [Google Flow](/docs/api-google-flow-v1) credits, so the same Google AI plan gives you both allowances. ### Automated setup (recommended) Use our guided browser setup to connect your account automatically — no DevTools or cookie copying needed. Enter your API token, sign in with Google in the remote browser, and your account is verified and added. The remote browser is closed right after, so that sign-in is never opened again. [Open automated setup](/assets/setup-browser/google-vids.html) Prefer manual setup? Continue with the steps below. --- ### Use a dedicated Gmail account ⚠️ **Use a dedicated Gmail account for this API — do NOT use your personal Gmail account.** When creating a new account: 1. Enable [2-Step Verification](https://support.google.com/accounts/answer/185839) with [Microsoft Authenticator](https://www.microsoft.com/en-us/security/mobile-authenticator-app), and save the backup codes. Avoid Google Authenticator — it backs its codes up to the Google account it is signed into, which would link this dedicated account to your personal one. 2. Keep your sign-ins consistent. If you use a VPN, pick one region and stay with it rather than switching locations — an account that appears from different places in a short time is what Google treats as suspicious. The automated setup above signs in from a US browser, so it needs no VPN on your side. ### If Google asks for a phone number Occasionally Google shows a "Verify it's you" page and asks for a phone number to text a code to, even on an account that never had one. Any number that can receive SMS works. It does not have to be one already on the account. If you'd rather not use your personal number, get an inexpensive prepaid line just for this — for example a [Tello](https://tello.com) eSIM on its cheapest plan with texts (about $5/month, activated online). Install it on any phone, receive the code there, and keep the line active so you can pass future checks. Avoid online SMS-rental and "free virtual number" services. Google rejects most of them, and a rejected number can make the lock harder to clear. ### Manual setup ⚠️ **Do NOT use Google Chrome.** Google's integration with Chrome interferes with cookie extraction. Use [Brave](https://brave.com/) or [Ungoogled Chromium](https://github.com/ungoogled-software/ungoogled-chromium) instead. You sign in to Google Vids, then copy the `https://docs.google.com` cookies from Developer Tools and paste them into the `cookies` field below. That one set holds every cookie the API needs: `SID`, `HSID`, `SSID`, `APISID`, `SAPISID`, `__Secure-1PSIDTS` and the `docs.google.com` `OSID`. #### Start a clean browser with the setup script (recommended) Our [Google Account Setup](https://github.com/useapi/google-account-setup) scripts for Windows, macOS and Linux give you a clean, single-use Google sign-in. They open Brave in a brand-new, empty profile, wait while you sign in and copy the cookies, and delete that profile the moment you close the browser. That takes care of three things: - A fresh, empty profile, with no other Google accounts, history or extensions. It runs separately from your normal Brave, which can stay open. - No device-bound sessions. Brave starts with `--disable-features=EnableBoundSessionCredentials,DeviceBoundSessions`, so the cookies also work outside your computer. - The profile is deleted when you close the browser. That sign-in can never be opened in a browser again, so only the API uses it. The scripts read nothing and send nothing — you copy the cookies by hand, exactly as in the manual steps below. Each script is short, so read it before you run it. 1. Install [Brave](https://brave.com/) (on Linux, Chromium works too). 2. Get the script for your system from the sections below: copy it into a file, or download it from [GitHub](https://github.com/useapi/google-account-setup). 3. Run it and choose Google Vids from the menu. 4. In the Brave window, sign in to your dedicated Google account, copy the cookies named above (the script names them too), and paste them into the form on this page. 5. When the account shows as added, close every window of that Brave (on a Mac, quit it with `Cmd+Q`). Keep the script's window open until it reports the profile was deleted, and do not sign in to the same Google account in any other browser afterwards.
Windows — install script [Download it from GitHub](https://github.com/useapi/google-account-setup/blob/main/google-account-setup-windows.cmd), or open Notepad, paste the script below, and save it as `google-account-setup-windows.cmd` (in the Save dialog set `Save as type` to `All Files` so it is not saved as `.txt`). Double-click the saved file. If Windows shows `Windows protected your PC`, click `More info` then `Run anyway`. ```bat Liquid error: Argument error in tag 'include' - Illegal template name ```
macOS — install script [Download it from GitHub](https://github.com/useapi/google-account-setup/blob/main/google-account-setup-mac.command) and run it with `bash ~/Downloads/google-account-setup-mac.command`, or open `Terminal` (Applications → Utilities), paste the script below into a file with `nano ~/google-account-setup-mac.command`, press `Ctrl+O` then `Enter` to save and `Ctrl+X` to exit, then run it with `bash ~/google-account-setup-mac.command`. ```bash Liquid error: Argument error in tag 'include' - Illegal template name ```
Linux / WSL — install script [Download it from GitHub](https://github.com/useapi/google-account-setup/blob/main/google-account-setup-linux.sh), or save the script below to `~/google-account-setup-linux.sh` (for example with `nano ~/google-account-setup-linux.sh`), then run it with `bash ~/google-account-setup-linux.sh`. On WSL this needs Windows 11 (WSLg) for the browser window — otherwise run the Windows script instead. ```bash Liquid error: Argument error in tag 'include' - Illegal template name ```
#### Or start the browser by hand Chromium browsers on Windows and Mac now bind a Google sign-in to the device (Google's Device Bound Session Credentials). Cookies copied from a bound session are refused anywhere else, and the API answers `These cookies are not signed in to Google Vids`. The browser's own flags page does not turn this off (Google overrides it), but a command-line switch does. The [automated setup](#automated-setup-recommended) is not affected. 1. Quit Brave completely, including any instance left in the system tray (check Task Manager for `brave.exe`, on a Mac use `Cmd+Q`). A running Brave ignores the switch. 2. Start it from the Run box (`Win+R`) with this command, which opens a private window with no cookies and without device-bound sessions: ``` "C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe" --incognito --disable-features=EnableBoundSessionCredentials,DeviceBoundSessions ``` On a Mac, run the same switches from Terminal: ``` open -na "Brave Browser" --args --incognito --disable-features=EnableBoundSessionCredentials,DeviceBoundSessions ``` Ungoogled Chromium takes the same `--disable-features` switch. Keep this window open for the steps below. #### Sign in to Google Vids Navigate to [https://docs.google.com/videos](https://docs.google.com/videos) and sign in with your dedicated Gmail account. ![](/assets/images/google-vids-setup-1.jpg) Enter your password, then the 2-Step Verification code. Google names Google Authenticator here whichever authenticator app holds the code. ⚠️ **You MUST check `Don't ask again on this device`** — skipping it will break the API session. ![](/assets/images/google-vids-setup-2.jpg) #### Copy the `https://docs.google.com` cookies Once signed in you see the Google Vids home page. 1. Open Developer Tools: right-click anywhere on the page and select `Inspect` (or press `F12`), then open the `Application` tab 2. Under `Cookies`, select `https://docs.google.com` 3. Click in the cookie table and select all cookies (`Ctrl+A`) 4. Copy them (`Ctrl+C`, or right-click and `Copy`), and paste them into the `cookies` field below ![](/assets/images/google-vids-setup-3.jpg) Before you paste, look for `__Secure-1PSIDRTS` in what you copied. If it is there, the session is device-bound and will be refused: close every Brave window and start again with the command above. ### Add the account Paste everything you copied, exactly as it is. The form below sends it to [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts), which checks the cookies with Google and reads the account's monthly allowance before the account is added.
A successful response is `201` for a new account or `200` for an update, with the account email, its monthly limits and how much of each is left (`quota`). ⚠️ Right after the account is added, close every window of that browser. Do NOT sign out of Google first — signing out ends the session the API now uses. From now on, use this Google account only through the API: do not open it in Google Vids, Gmail or any other Google page, in any browser. ### If Google signs the account out If Google ends the session of a connected account, the API detects it on the next request, re-checks it once, and then emails you right away with a link to re-add the account. Until you re-add it, the account is paused and shows the re-add message in [GET /accounts](/docs/api-google-vids-v1/get-google-vids-accounts). The most common cause is opening the same Google account in a browser. Re-add it with the [automated setup](/assets/setup-browser/google-vids.html) or the setup script, which take about a minute and leave no browser session behind. ### Usage limits Google Vids meters each plan by the month: video in seconds and images by count. A clip uses its length in seconds, whether 720p or 1080p, and an extend uses only the seconds it adds. A request Google refuses uses nothing. Once an allowance runs out Google refuses new generations until it resets on the 1st of the month. The API reports the live limits of each account at [GET /accounts/`email`](/docs/api-google-vids-v1/get-google-vids-accounts-email). === URL: https://useapi.net/docs/api-google-vids-v1/delete-google-vids-accounts-email === Document URL: https://useapi.net/docs/api-google-vids-v1/delete-google-vids-accounts-email --- layout: default title: DELETE accounts/`email` description: "Remove a Google account from the useapi.net Google Vids API via DELETE accounts/email. Its Vids document and saved avatars stay on the Google account." parent: Google Vids API v1 nav_order: 140 permalink: /docs/api-google-vids-v1/delete-google-vids-accounts-email --- ## Delete an account October 7, 2026 --- Remove a connected Google account from your useapi.net account. The stored cookies are deleted and the account slot is freed. Nothing is deleted on Google's side. The account's Vids document and the avatars saved in it stay on the Google account, and you can connect the account again at any time with [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts). Media, asset and avatar ids of a removed account stop working until it is connected again, and an async job still queued for it fails with `404`. > **https://api.useapi.net/v1/google-vids/accounts/`email`** - `email` is the email of a connected account, URL-encoded in the path. ##### Request Headers ``` yaml Authorization: Bearer {API token} ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Responses **204** **204 No Content** — the account was removed. The response body is empty. **400** **400 Bad Request** — the `email` in the path is not a valid email, or no account is connected. ```json { "error": "Path parameter email (not-an-email) not a valid email", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **404** **404 Not Found** — no account is connected for this `email`. ```json { "error": "Account user@example.com not found", "code": 404 } ``` ##### Model `204` has no body. Errors return: ```typescript { // TypeScript, all fields are optional error: string code: number } ``` ##### Examples **Curl** ``` bash curl -X DELETE "https://api.useapi.net/v1/google-vids/accounts/user%40example.com" \ -H "Authorization: Bearer …" ``` **JavaScript** ``` javascript const token = "API token"; const email = "Previously configured account email"; const apiUrl = `https://api.useapi.net/v1/google-vids/accounts/${encodeURIComponent(email)}`; const response = await fetch(apiUrl, { method: "DELETE", headers: { "Authorization": `Bearer ${token}`, }, }); console.log("response", response.status); ``` **Python** ``` python import requests from urllib.parse import quote token = "API token" email = "Previously configured account email" apiUrl = f"https://api.useapi.net/v1/google-vids/accounts/{quote(email, safe='')}" headers = { "Authorization" : f"Bearer {token}" } response = requests.delete(apiUrl, headers=headers) print(response.status_code) ``` === URL: https://useapi.net/docs/api-google-vids-v1/delete-google-vids-avatars-avatarId === Document URL: https://useapi.net/docs/api-google-vids-v1/delete-google-vids-avatars-avatarId --- layout: default title: DELETE avatars/`avatarId` description: "Delete an avatar from its account's Vids document via DELETE avatars/avatarId in the useapi.net Google Vids API. Clips already made with it are not affected." parent: Google Vids API v1 nav_order: 620 permalink: /docs/api-google-vids-v1/delete-google-vids-avatars-avatarId --- ## Delete an avatar October 7, 2026 --- Remove an avatar from the account's Vids document. This works for avatars made with [POST /avatars](/docs/api-google-vids-v1/post-google-vids-avatars) and for those made in the Google Vids web app, as listed by [GET /avatars](/docs/api-google-vids-v1/get-google-vids-avatars). Clips already made with the avatar are not affected. Apart from the one Vids document it creates when you add the account, avatars are the only thing the API saves on a Google account. Generated videos, images and uploads live in Google's temporary storage and need no deleting, see [How long files last](/docs/api-google-vids-v1#how-long-files-last). > **https://api.useapi.net/v1/google-vids/avatars/`avatarId`** - `avatarId` is the avatar's id, URL-encoded in the path (it contains `:` and `@`). It names its account, so no `email` is needed. ##### Request Headers ``` yaml Authorization: Bearer {API token} ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Responses **204** **204 No Content** — the avatar was deleted. The response body is empty. **400** **400 Bad Request** — the path value is not an `avatarId`. ```json { "error": "Path parameter avatarId (…) is not a valid avatar id", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **403** **403 Forbidden** — the `avatarId` was issued to a different API token. ```json { "error": "avatar id does not belong to this API token", "code": 403 } ``` **404** **404 Not Found** — the avatar is already gone from the Vids document, or its account is not connected. ```json { "error": "Avatar not found in the Vids document", "code": 404 } ``` **502** **502 Bad Gateway** — Google did not remove the avatar. Retry. ```json { "error": "Google did not remove the avatar, please retry", "code": 502 } ``` **596** **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](/docs/start-here/setup-google-vids). ```json { "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 } ``` ```json { "error": "Account user@example.com: Google signed this account out. Re-add it at https://useapi.net/docs/start-here/setup-google-vids", "code": 596 } ``` ##### Model `204` has no body. Errors return: ```typescript { // TypeScript, all fields are optional error: string code: number } ``` ##### Examples **Curl** ``` bash AVATARID="user:12345-user@example.com-avatar:eyJnIjoiaDMy…" curl -X DELETE -H "Authorization: Bearer …" \ "https://api.useapi.net/v1/google-vids/avatars/$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=''))" "$AVATARID")" ``` **JavaScript** ``` javascript const token = "API token"; const avatarId = "avatarId from GET /avatars"; const apiUrl = `https://api.useapi.net/v1/google-vids/avatars/${encodeURIComponent(avatarId)}`; const response = await fetch(apiUrl, { method: "DELETE", headers: { "Authorization": `Bearer ${token}`, }, }); console.log("response", response.status); ``` **Python** ``` python import requests from urllib.parse import quote token = "API token" avatarId = "avatarId from GET /avatars" apiUrl = "https://api.useapi.net/v1/google-vids/avatars/" + quote(avatarId, safe="") headers = { "Authorization" : f"Bearer {token}" } response = requests.delete(apiUrl, headers=headers) print(response.status_code) ``` === URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-accounts-email === Document URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-accounts-email --- layout: default title: GET accounts/`email` description: "Check one Google Vids account live via GET accounts/email in the useapi.net API — whether Google still signs it in, and the video seconds and images left this month." parent: Google Vids API v1 nav_order: 120 permalink: /docs/api-google-vids-v1/get-google-vids-accounts-email --- ## Retrieve an account October 7, 2026 --- Get one connected account with a live read from Google: whether the session is still signed in, and how much of each monthly allowance is left. The read uses the stored cookies exactly as a generation does, and every call goes to Google. The video counter is in seconds and the image counter in images. On a Google family plan the video seconds are shared by every family member, so two accounts of one family show the same `video.left`. See [Plans and monthly allowances](/docs/api-google-vids-v1#plans-and-monthly-allowances). A signed-out session found here is handled like on any other request. The API re-checks it once, and if it is still signed out the account is paused and you receive an email with the re-add link. > **https://api.useapi.net/v1/google-vids/accounts/`email`** - `email` is the email of a connected account, URL-encoded in the path. ##### Request Headers ``` yaml Authorization: Bearer {API token} ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Responses **200** **200 OK** ```json { "email": "user@example.com", "maxJobs": 3, "added": "2026-10-07T02:21:08.626Z", "updated": "2026-10-07T05:47:38.929Z", "cookies": [ "SID", "HSID", "SSID", "APISID", "SAPISID", "__Secure-1PSIDTS", "OSID" ], "cookiesExpireAt": "2027-04-05T02:18:00.438Z", "vidsDocId": "1N48K72jE4hpv4A3XPH3rf0EVTpMCERAwf4uDmQPc6v4", "limits": { "video": 10000, "image": 1000, "music": 300 }, "health": "OK", "session": "signed-in", "quota": { "video": { "limit": 10000, "left": 9652, "resetAt": "2026-11-01T07:00:00.000Z" }, "image": { "limit": 1000, "left": 947, "resetAt": "2026-11-01T07:00:00.000Z" }, "music": { "limit": 300, "left": 298, "resetAt": "2026-11-01T07:00:00.000Z" } } } ``` - `session` tells what the live read found: - `signed-in` — the account works, and `quota` is fresh from Google. - `signed-out` — Google signed the account out. It is paused, `health` holds the re-add message and you receive an email with the re-add link. - `verifying` — another request is re-checking the session right now. Retry in about a minute. - `unknown (could not reach Google to re-check)` and `unavailable (…)` — Google could not be reached, or its Vids page did not answer normally. The account is not paused. Retry later. - `unknown` — the session works but the allowance read failed. `quotaError` holds the reason. - `quota` is returned only with `session: signed-in`. A counter Google did not answer is `null`. `resetAt` is the 1st of next month, 00:00 Pacific time. - An account that is already paused (its `health` is the re-add message, or `verifying`) is returned as stored, without `session` or `quota`. Re-add a paused account with [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts). **400** **400 Bad Request** — the `email` in the path is not a valid email, or no account is connected yet. ```json { "error": "Path parameter email (not-an-email) not a valid email", "code": 400 } ``` ```json { "error": "Please configure at least one account at https://useapi.net/docs/api-google-vids-v1/post-google-vids-accounts", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **404** **404 Not Found** — no account is connected for this `email`. ```json { "error": "Account user@example.com not found", "code": 404 } ``` ##### Model ```typescript { // TypeScript, all fields are optional email: string maxJobs: number // jobs this account may run at the same time added: string // ISO 8601, when the account was first connected updated?: string // ISO 8601, the last re-add or maxJobs change cookies: string[] // names of the stored cookies, never their values cookiesExpireAt?: string | null // ISO 8601, the earliest expiry date in the pasted cookies vidsDocId: string // the Google Vids document the API created on the account limits: { // monthly limits read from Google when the account was added video: number | null // seconds of video image: number | null // images music: number | null // songs (not used by this API) } health: string // 'OK', 'verifying', or the reason the account must be re-added addedVia?: 'setup-browser' // present when the account was added by the automated setup session?: string // what the live read found, see Responses quota?: { // session 'signed-in' only, null when a counter did not answer video: { limit: number, left: number, resetAt: string } | null // seconds of video image: { limit: number, left: number, resetAt: string } | null // images music: { limit: number, left: number, resetAt: string } | null // songs (not used by this API) } quotaError?: string // present with session 'unknown' } ``` ##### Examples **Curl** ``` bash curl "https://api.useapi.net/v1/google-vids/accounts/user%40example.com" \ -H "Authorization: Bearer …" ``` **JavaScript** ``` javascript const token = "API token"; const email = "Previously configured account email"; const apiUrl = `https://api.useapi.net/v1/google-vids/accounts/${encodeURIComponent(email)}`; const response = await fetch(apiUrl, { headers: { "Authorization": `Bearer ${token}`, }, }); const result = await response.json(); console.log("response", {response, result}); ``` **Python** ``` python import requests from urllib.parse import quote token = "API token" email = "Previously configured account email" apiUrl = f"https://api.useapi.net/v1/google-vids/accounts/{quote(email, safe='')}" headers = { "Authorization" : f"Bearer {token}" } response = requests.get(apiUrl, headers=headers) print(response, response.json()) ``` === URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-accounts === Document URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-accounts --- layout: default title: GET accounts description: "List the Google accounts connected to the useapi.net Google Vids API via GET accounts, with each account's health, maxJobs and monthly video and image limits." parent: Google Vids API v1 nav_order: 110 permalink: /docs/api-google-vids-v1/get-google-vids-accounts --- ## Retrieve all accounts October 7, 2026 --- List the Google accounts connected with [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts). Each entry shows the account's `health`, its `maxJobs` and the monthly limits Google reported when it was added. This endpoint does not call Google. For the live session and what is left of each allowance use [GET /accounts/`email`](/docs/api-google-vids-v1/get-google-vids-accounts-email). [GET /jobs](/docs/api-google-vids-v1/get-google-vids-jobs) shows how many jobs each account is running. > **https://api.useapi.net/v1/google-vids/accounts** ##### Request Headers ``` yaml Authorization: Bearer {API token} ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Responses **200** **200 OK** ```json { "user@example.com": { "email": "user@example.com", "maxJobs": 3, "added": "2026-10-07T02:21:08.626Z", "updated": "2026-10-07T05:47:38.929Z", "cookies": [ "SID", "HSID", "SSID", "APISID", "SAPISID", "__Secure-1PSIDTS", "OSID" ], "cookiesExpireAt": "2027-04-05T02:18:00.438Z", "vidsDocId": "1N48K72jE4hpv4A3XPH3rf0EVTpMCERAwf4uDmQPc6v4", "limits": { "video": 10000, "image": 1000, "music": 300 }, "health": "OK" }, "another@example.com": { "email": "another@example.com", "maxJobs": 3, "added": "2026-10-07T01:07:47.890Z", "cookies": [ "SID", "HSID", "SSID", "APISID", "SAPISID", "__Secure-1PSIDTS", "OSID" ], "cookiesExpireAt": "2027-04-05T01:05:12.204Z", "vidsDocId": "1zeizDjTAw4DyXjNZKPkHuAhHJt87J6COR_Hc4L3gKJw", "limits": { "video": 10000, "image": 1000, "music": 300 }, "health": "Google signed this account out. Re-add it at https://useapi.net/docs/start-here/setup-google-vids" } } ``` - The response is an object keyed by account email, or `{}` when no account is connected. - `health` is `OK`, `verifying` while the API re-checks an account Google reported as signed out, or the reason the account must be re-added. A paused account takes no new jobs until you re-add it with [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts). **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` ##### Model ```typescript { // TypeScript, all fields are optional [email: string]: { email: string maxJobs: number // jobs this account may run at the same time added: string // ISO 8601, when the account was first connected updated?: string // ISO 8601, the last re-add or maxJobs change cookies: string[] // names of the stored cookies, never their values cookiesExpireAt?: string | null // ISO 8601, the earliest expiry date in the pasted cookies vidsDocId: string // the Google Vids document the API created on the account limits: { // monthly limits read from Google when the account was added video: number | null // seconds of video image: number | null // images music: number | null // songs (not used by this API) } health: string // 'OK', 'verifying', or the reason the account must be re-added addedVia?: 'setup-browser' // present when the account was added by the automated setup } } ``` ##### Examples **Curl** ``` bash curl "https://api.useapi.net/v1/google-vids/accounts" \ -H "Authorization: Bearer …" ``` **JavaScript** ``` javascript const token = "API token"; const apiUrl = "https://api.useapi.net/v1/google-vids/accounts"; const response = await fetch(apiUrl, { headers: { "Authorization": `Bearer ${token}`, }, }); const result = await response.json(); console.log("response", {response, result}); ``` **Python** ``` python import requests token = "API token" apiUrl = "https://api.useapi.net/v1/google-vids/accounts" headers = { "Authorization" : f"Bearer {token}" } response = requests.get(apiUrl, headers=headers) print(response, response.json()) ``` === URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-avatars === Document URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-avatars --- layout: default title: GET avatars description: "List the avatars on your Google Vids accounts via GET avatars in the useapi.net API, including ones made in the Vids web app, with avatarId and voice." parent: Google Vids API v1 nav_order: 610 permalink: /docs/api-google-vids-v1/get-google-vids-avatars --- ## List avatars October 7, 2026 --- List the avatars saved in your accounts' Vids documents, each with an `avatarId` ready to pass as `avatar_1`..`avatar_3` to [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos). The list is read live from Google, so it includes avatars made in the Google Vids web app on that document as well as those made with [POST /avatars](/docs/api-google-vids-v1/post-google-vids-avatars). An avatar made in the web app with one of Google's older narrator voices is listed with `voice: null` and a `note`. It cannot be used in a video through the API. Make a new avatar with [POST /avatars](/docs/api-google-vids-v1/post-google-vids-avatars) instead. Without `email`, every healthy account is read. An account that could not be read is listed under `errors`, and the others are still returned. > **https://api.useapi.net/v1/google-vids/avatars?email=`email`** ##### Request Headers ``` yaml Authorization: Bearer {API token} ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Query Parameters - `email` is optional, read one account only. URL-encode it. ##### Responses **200** **200 OK** ```json { "avatars": [ { "avatarId": "user:12345-user@example.com-avatar:eyJnIjoiaDMy…", "name": "Ruby", "voice": "Kaci", "voiceId": "Autonoe", "voiceStyle": "Bright", "voicePreview": "https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Autonoe.wav", "email": "user@example.com" }, { "avatarId": "user:12345-user@example.com-avatar:eyJnIjoiaDMy…", "name": "Marco", "voice": "Holt", "voiceId": "Charon", "voiceStyle": "Informative", "voicePreview": "https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Charon.wav", "email": "user@example.com" } ] } ``` - `avatars` is `[]` when no account has an avatar. **400** **400 Bad Request** — `email` is not a valid email, or no account is connected yet. ```json { "error": "Please configure at least one account at https://useapi.net/docs/api-google-vids-v1/post-google-vids-accounts", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **404** **404 Not Found** — the account named by `email` is not connected. ```json { "error": "Account user@example.com is not configured", "code": 404 } ``` ##### Model ```typescript { // TypeScript, all fields are optional avatars: { avatarId: string // pass it as avatar_1..avatar_3 to POST /videos name: string voice: string | null // the Vids voice name, null for an older narrator voice voiceId?: string // Google's voice id voiceStyle?: string // Google's label for the voice voicePreview?: string // a public English sample of the voice (WAV) note?: string // voice null: why the avatar cannot be used in a video email: string // the account the avatar is saved on }[] errors?: { // accounts that could not be read email: string error: string }[] } ``` ##### Examples **Curl** ``` bash curl "https://api.useapi.net/v1/google-vids/avatars?email=user%40example.com" \ -H "Authorization: Bearer …" ``` **JavaScript** ``` javascript const token = "API token"; const apiUrl = "https://api.useapi.net/v1/google-vids/avatars"; const response = await fetch(apiUrl, { headers: { "Authorization": `Bearer ${token}`, }, }); const result = await response.json(); console.log("response", {response, result}); ``` **Python** ``` python import requests token = "API token" apiUrl = "https://api.useapi.net/v1/google-vids/avatars" headers = { "Authorization" : f"Bearer {token}" } response = requests.get(apiUrl, headers=headers) print(response, response.json()) ``` === URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-jobs-jobid === Document URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-jobs-jobid --- layout: default title: GET jobs/`jobid` description: "Poll a Google Vids video or image job via GET jobs/jobid in the useapi.net API — its status, the finished mediaId and quota, or the error code, as sent to a replyUrl." parent: Google Vids API v1 nav_order: 510 permalink: /docs/api-google-vids-v1/get-google-vids-jobs-jobid --- ## Retrieve a job October 7, 2026 --- Fetch a job record by its `jobid`. Every generation is a job: [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos), [POST /videos/extend](/docs/api-google-vids-v1/post-google-vids-videos-extend), [POST /videos/upscale](/docs/api-google-vids-v1/post-google-vids-videos-upscale), [POST /videos/edit](/docs/api-google-vids-v1/post-google-vids-videos-edit) and [POST /images](/docs/api-google-vids-v1/post-google-vids-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](#model). Job records are kept for 30 days. > **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 ``` yaml Authorization: Bearer {API token} ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Responses **200** **200 OK** Completed (an async text-to-video job): ```json { "jobid": "user:12345-user@example.com-job:4aa24347-8099-4624-80ec-fb758db74419", "type": "video", "mode": "text", "email": "user@example.com", "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:12345-user@example.com-video: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: ```json { "jobid": "user:12345-user@example.com-job:4aa24347-8099-4624-80ec-fb758db74419", "type": "video", "mode": "text", "email": "user@example.com", "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): ```json { "jobid": "user:12345-user@example.com-job:db97658a-1240-4eee-a9dc-75f7c5123d2e", "type": "video", "mode": "edit", "email": "user@example.com", "status": "failed", "created": "2026-10-07T06:36:31.478Z", "request": { "video": "user:12345-user@example.com-asset:…", "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** **400 Bad Request** The path value is not a Google Vids `jobid`. ```json { "error": "Path parameter jobid (…) is not a valid job id", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **403** **403 Forbidden** ```json { "error": "This job does not belong to this API token", "code": 403 } ``` **404** **404 Not Found** No such job, or its record is older than 30 days. ```json { "error": "Job user:12345-user@example.com-job:00000000-0000-4000-8000-000000000000 not found (records are kept 30 days)", "code": 404 } ``` ##### Model The job record. [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos), [POST /videos/extend](/docs/api-google-vids-v1/post-google-vids-videos-extend), [POST /videos/upscale](/docs/api-google-vids-v1/post-google-vids-videos-upscale), [POST /videos/edit](/docs/api-google-vids-v1/post-google-vids-videos-edit) and [POST /images](/docs/api-google-vids-v1/post-google-vids-images) return it too, and it is the body of the `replyUrl` webhook. ```typescript { // TypeScript, all fields are optional jobid: string // user:--job: 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 // 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 } } ``` | `status` | Meaning | |---|---| | `pending` | Async only: the job is queued and has not started. | | `processing` | Google is generating. A sync job starts here. | | `completed` | Done. `result.mediaId` downloads the file with [GET /media/`mediaId`](/docs/api-google-vids-v1/get-google-vids-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, it moves to another of your accounts. | `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). | | `404` | The account was removed with [DELETE /accounts/`email`](/docs/api-google-vids-v1/delete-google-vids-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, and `retryAt` is the reset time. 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 without a file, or with an unexpected error. | | `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 15 minutes, or the connection to Google was cut, or the job did not finish within its time budget. Google may still finish the file and charge it. | | `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](/docs/start-here/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 **Curl** ``` bash JOBID="user:12345-user@example.com-job:4aa24347-8099-4624-80ec-fb758db74419" 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")" ``` **JavaScript** ``` javascript const token = "API token"; const jobid = "user:12345-user@example.com-job:4aa24347-8099-4624-80ec-fb758db74419"; 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 === "pending" || job.status === "processing"); console.log("job", job); ``` **Python** ``` python import requests, time, urllib.parse token = "API token" jobid = "user:12345-user@example.com-job:4aa24347-8099-4624-80ec-fb758db74419" 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") not in ("pending", "processing"): break print(job) ``` === URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-jobs === Document URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-jobs --- layout: default title: GET jobs description: "See what each Google Vids account is generating via GET jobs in the useapi.net API: the jobs running now and each account's count against maxJobs." parent: Google Vids API v1 nav_order: 500 permalink: /docs/api-google-vids-v1/get-google-vids-jobs --- ## List running jobs October 7, 2026 --- List the jobs running right now and, for every connected account, how many of its `maxJobs` slots they take. A job is listed from the moment [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos), [POST /videos/extend](/docs/api-google-vids-v1/post-google-vids-videos-extend), [POST /videos/upscale](/docs/api-google-vids-v1/post-google-vids-videos-upscale), [POST /videos/edit](/docs/api-google-vids-v1/post-google-vids-videos-edit) or [POST /images](/docs/api-google-vids-v1/post-google-vids-images) accepts it until it completes or fails. Each listed job takes one of its account's slots. When all slots of an account are taken, a new job on it is refused with `429`, and a job without `email` goes to another account that has a free slot. Uploads and avatars take no slot. Poll a single job with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid). This endpoint reads our own records only and never calls Google, so it is cheap to poll. > **https://api.useapi.net/v1/google-vids/jobs** ##### Request Headers ``` yaml Authorization: Bearer {API token} ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Responses **200** **200 OK** ```json { "running": [ { "jobid": "user:12345-user@example.com-job:4aa24347-8099-4624-80ec-fb758db74419", "email": "user@example.com", "created": "2026-10-07T06:29:01.204Z", "type": "video", "mode": "text" } ], "accounts": { "user@example.com": { "running": 1, "maxJobs": 3 }, "another@example.com": { "running": 0, "maxJobs": 3 } } } ``` **400** **400 Bad Request** — no account is connected yet. ```json { "error": "Please configure at least one account at https://useapi.net/docs/api-google-vids-v1/post-google-vids-accounts", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` ##### Model ```typescript { // TypeScript, all fields are optional running: { jobid: string email: string // the account the job runs on created: string // ISO 8601, when the job was accepted type: 'video' | 'image' mode?: 'text' | 'image' | 'ingredients' | 'extend' | 'upscale' | 'edit' // video jobs only }[] accounts: { [email: string]: { running: number // jobs running on this account now maxJobs: number // its limit, set with POST /accounts } } } ``` ##### Examples **Curl** ``` bash curl "https://api.useapi.net/v1/google-vids/jobs" \ -H "Authorization: Bearer …" ``` **JavaScript** ``` javascript const token = "API token"; const apiUrl = "https://api.useapi.net/v1/google-vids/jobs"; const response = await fetch(apiUrl, { headers: { "Authorization": `Bearer ${token}`, }, }); const result = await response.json(); console.log("response", {response, result}); ``` **Python** ``` python import requests token = "API token" apiUrl = "https://api.useapi.net/v1/google-vids/jobs" headers = { "Authorization" : f"Bearer {token}" } response = requests.get(apiUrl, headers=headers) print(response, response.json()) ``` === URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-media-mediaId === Document URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-media-mediaId --- layout: default title: GET media/`mediaId` description: "Download a generated Google Vids video (MP4) or image (JPEG) via GET media/mediaId in the useapi.net API, streamed from Google with Range support for seeking." parent: Google Vids API v1 nav_order: 410 permalink: /docs/api-google-vids-v1/get-google-vids-media-mediaId --- ## Download a video or image October 7, 2026 --- Download a finished video or image. The response body is the file itself, streamed from Google on each request and never stored by us. Google's file links open only with the Google account's cookies, so a finished job returns a `mediaId` instead, and this endpoint fetches the file with the account that made it. Pass the `result.mediaId` of any job from [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos), [POST /videos/extend](/docs/api-google-vids-v1/post-google-vids-videos-extend), [POST /videos/upscale](/docs/api-google-vids-v1/post-google-vids-videos-upscale), [POST /videos/edit](/docs/api-google-vids-v1/post-google-vids-videos-edit) or [POST /images](/docs/api-google-vids-v1/post-google-vids-images), or the `previewMediaId` of a generated [avatar](/docs/api-google-vids-v1/post-google-vids-avatars). Files are temporary: images stay available for a few hours, videos for at least half a day, then this endpoint answers `404`. See [How long files last](/docs/api-google-vids-v1#how-long-files-last). > **https://api.useapi.net/v1/google-vids/media/`mediaId`** - `mediaId` is a video or image `mediaId`, URL-encoded in the path (it contains `:` and `@`). An `assetId` cannot be downloaded. ##### Request Headers ``` yaml Authorization: Bearer {API token} # Optional, passed through to Google Range: bytes=0-1048575 ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. - `Range` is optional. It is forwarded to Google, so a player can seek in a video or a client can resume a download. A range request answers `206 Partial Content` with `Content-Range`. ##### Response headers - `Content-Type`: `video/mp4` for a video, `image/jpeg` for an image. - `Content-Disposition`: `inline; filename="video.mp4"` or `inline; filename="image.jpg"`. - `Content-Length`, `Content-Range`, `Accept-Ranges`: passed through from Google when it sends them. ##### Responses **200** **200 OK** The raw file bytes (not JSON), for example: ``` Content-Type: video/mp4 Content-Length: 718046 Content-Disposition: inline; filename="video.mp4" ``` **206** **206 Partial Content** The requested byte range of the file, when the request carried a `Range` header. **400** **400 Bad Request** The path value is not a video or image `mediaId`. ```json { "error": "Path parameter mediaId (…) is not a valid video / image id", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **403** **403 Forbidden** The `mediaId` was issued to a different API token. ```json { "error": "video id does not belong to this API token", "code": 403 } ``` **404** **404 Not Found** The file has expired at Google (images last a few hours, videos longer), or the account that made it is not connected. ```json { "error": "This file has expired at Google (HTTP 403). Generated files are temporary: download them soon after they are made", "code": 404 } ``` ```json { "error": "Account user@example.com (from the video id) is not configured", "code": 404 } ``` **502** **502 Bad Gateway** Google did not serve the file, or answered with a page instead of the file. Retry shortly. ```json { "error": "Google answered HTTP 500 for this file", "code": 502 } ``` **596** **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](/docs/start-here/setup-google-vids). ```json { "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 } ``` ```json { "error": "Account user@example.com: Google signed this account out. Re-add it at https://useapi.net/docs/start-here/setup-google-vids", "code": 596 } ``` ##### Model A successful response is the file itself (not JSON), with the headers listed above. Errors return: ```typescript { // TypeScript, all fields are optional error: string code: number } ``` ##### Examples **Curl** ``` bash MEDIAID="user:12345-user@example.com-video:eyJ1IjoiaHR0…" curl -H "Authorization: Bearer …" \ "https://api.useapi.net/v1/google-vids/media/$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=''))" "$MEDIAID")" \ --output video.mp4 ``` **JavaScript** ``` javascript const token = "API token"; const mediaId = "mediaId from a finished job"; const apiUrl = `https://api.useapi.net/v1/google-vids/media/${encodeURIComponent(mediaId)}`; const response = await fetch(apiUrl, { headers: { "Authorization": `Bearer ${token}`, }, }); if (!response.ok) console.log("error", response.status, await response.json()); else { const file = await response.arrayBuffer(); console.log("downloaded", file.byteLength, response.headers.get("content-type")); } ``` **Python** ``` python import requests from urllib.parse import quote token = "API token" mediaId = "mediaId from a finished job" apiUrl = "https://api.useapi.net/v1/google-vids/media/" + quote(mediaId, safe="") headers = { "Authorization" : f"Bearer {token}" } with requests.get(apiUrl, headers=headers, stream=True) as response: response.raise_for_status() with open("video.mp4", "wb") as f: for chunk in response.iter_content(chunk_size=1 << 20): f.write(chunk) ``` === URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-voices === Document URL: https://useapi.net/docs/api-google-vids-v1/get-google-vids-voices --- layout: default title: GET voices description: "List the 30 Gemini voices for Google Vids avatars via GET voices in the useapi.net API, with Google's style labels and samples in 18 languages, no token." parent: Google Vids API v1 nav_order: 700 permalink: /docs/api-google-vids-v1/get-google-vids-voices --- ## List voices October 7, 2026 --- List the 30 voices an [avatar](/docs/api-google-vids-v1/post-google-vids-avatars) can speak with, in the order the Vids editor shows them. Each voice has its Vids name, Google's voice id and Google's one-word style label, plus links to Google's own pregenerated sample of the voice in 18 languages. Pass either the `name` or the `voice` id as `voice` to [POST /avatars](/docs/api-google-vids-v1/post-google-vids-avatars). Voices are free. This endpoint is public: it needs no API token and no connected account, and any web page may call it. The list is fixed, so the response is cached for 24 hours. | `name` | `voice` | `style` | English sample | |---|---|---|---| | `Nyla` | `Achernar` | Soft | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Achernar.wav) | | `Holt` | `Charon` | Informative | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Charon.wav) | | `Knox` | `Algieba` | Smooth | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Algieba.wav) | | `Tyra` | `Erinome` | Clear | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Erinome.wav) | | `Paz` | `Enceladus` | Breathy | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Enceladus.wav) | | `Umi` | `Sadaltager` | Knowledgeable | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Sadaltager.wav) | | `Jett` | `Algenib` | Gravelly | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Algenib.wav) | | `Elio` | `Achird` | Friendly | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Achird.wav) | | `Lani` | `Callirrhoe` | Easy-going | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Callirrhoe.wav) | | `Zeno` | `Alnilam` | Firm | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Alnilam.wav) | | `Kaci` | `Autonoe` | Bright | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Autonoe.wav) | | `Tova` | `Aoede` | Breezy | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Aoede.wav) | | `Lora` | `Despina` | Smooth | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Despina.wav) | | `Fola` | `Sulafat` | Warm | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Sulafat.wav) | | `Yori` | `Zubenelgenubi` | Casual | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Zubenelgenubi.wav) | | `Iro` | `Rasalgethi` | Informative | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Rasalgethi.wav) | | `Fira` | `Leda` | Youthful | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Leda.wav) | | `Nyx` | `Iapetus` | Clear | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Iapetus.wav) | | `Neo` | `Puck` | Upbeat | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Puck.wav) | | `Baya` | `Umbriel` | Easy-going | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Umbriel.wav) | | `Peli` | `Laomedeia` | Upbeat | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Laomedeia.wav) | | `Jacy` | `Schedar` | Even | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Schedar.wav) | | `Cale` | `Orus` | Firm | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Orus.wav) | | `Orla` | `Vindemiatrix` | Gentle | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Vindemiatrix.wav) | | `Dori` | `Sadachbia` | Lively | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Sadachbia.wav) | | `Sani` | `Zephyr` | Bright | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Zephyr.wav) | | `Kero` | `Fenrir` | Excitable | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Fenrir.wav) | | `Saro` | `Gacrux` | Mature | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Gacrux.wav) | | `Lito` | `Kore` | Firm | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Kore.wav) | | `Vira` | `Pulcherrima` | Forward | [listen](https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Pulcherrima.wav) | Sample languages: `en`, `es`, `fr`, `de`, `it`, `ja`, `ko`, `pt`, `nl`, `hi`, `id`, `ar`, `ru`, `tr`, `vi`, `th`, `pl`, `uk`. > **https://api.useapi.net/v1/google-vids/voices** ##### Request Headers None. No `Authorization` header is needed. ##### Responses **200** **200 OK** The list, shortened to its first voice and three of its sample languages: ```json { "voices": [ { "name": "Nyla", "voice": "Achernar", "style": "Soft", "preview": "https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Achernar.wav", "previews": { "en": "https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Achernar.wav", "es": "https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/es/Achernar.wav", "fr": "https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/fr/Achernar.wav", ... } }, ... ], "languages": [ "en", "es", "fr", ... ] } ``` **404** **404 Not Found** — a path below `/voices`, which does not exist. ```json { "error": "Unknown path /v1/google-vids/voices/Nyla", "code": 404 } ``` ##### Model ```typescript { // TypeScript, all fields are optional voices: { name: string // the Vids name, e.g. 'Holt' voice: string // Google's voice id, e.g. 'Charon' style: string // Google's one-word label for the voice, e.g. 'Informative' preview: string // the English sample (WAV) previews: { [language: string]: string // the sample in each language of `languages` (WAV) } }[] languages: string[] // the sample languages } ``` ##### Examples **Curl** ``` bash curl "https://api.useapi.net/v1/google-vids/voices" ``` **JavaScript** ``` javascript const response = await fetch("https://api.useapi.net/v1/google-vids/voices"); const { voices } = await response.json(); console.table(voices.map(({ name, voice, style }) => ({ name, voice, style }))); ``` **Python** ``` python import requests voices = requests.get("https://api.useapi.net/v1/google-vids/voices").json()["voices"] for v in voices: print(v["name"], v["voice"], v["style"]) ``` === URL: https://useapi.net/docs/api-google-vids-v1 === Document URL: https://useapi.net/docs/api-google-vids-v1 --- layout: default title: Google Vids API v1 seo_title: "Google Vids API v1: Gemini Omni Video, Images and Avatars" description: "Google Vids API by useapi.net: Gemini Omni 1.1 Flash video at 720p or 1080p, extend, upscale, edit, images and voiced avatars on your Google AI plan, no captcha." nav_order: 2025 has_children: true permalink: /docs/api-google-vids-v1 --- # Google Vids API v1 October 7, 2026 This is the [experimental](/docs/legal) API for [Google Vids](https://docs.google.com/videos) by Google. It generates video with Gemini Omni 1.1 Flash, the model Google added to Vids in September 2026 ([Google's announcement](https://blog.google/products-and-platforms/products/workspace/gemini-omni-in-google-vids/)), and runs on your own Google accounts on a paid Google AI plan. Generate clips from text, from a start image, or from up to 3 references that mix your own images with voiced avatars. Then [extend](/docs/api-google-vids-v1/post-google-vids-videos-extend) a clip, [upscale](/docs/api-google-vids-v1/post-google-vids-videos-upscale) it to 1080p, or [edit](/docs/api-google-vids-v1/post-google-vids-videos-edit) it with a prompt. The API also makes [images](/docs/api-google-vids-v1/post-google-vids-images) in 7 styles and [avatars](/docs/api-google-vids-v1/post-google-vids-avatars), a person's picture with one of 30 Gemini voices that speaks the lines you write in the prompt. Vids has its own monthly allowance on the Google AI plan, separate from Google Flow's credits, and it asks for no captcha. ## What it makes | Output | Endpoint | Details | |---|---|---| | Video, Gemini Omni 1.1 Flash | [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos) | Text to video, start image to video, or up to 3 references (images and avatars). 3 to 10 seconds, `720p` or `1080p`, landscape or portrait, with sound and speech. | | Longer video | [POST /videos/extend](/docs/api-google-vids-v1/post-google-vids-videos-extend) | Adds 3 to 10 seconds to a clip and returns the whole clip, up to about 41 seconds. | | 1080p video | [POST /videos/upscale](/docs/api-google-vids-v1/post-google-vids-videos-upscale) | Turns a 720p clip into 1080p. | | Edited video | [POST /videos/edit](/docs/api-google-vids-v1/post-google-vids-videos-edit) | Changes a generated clip by prompt: colours, objects, style. | | Image | [POST /images](/docs/api-google-vids-v1/post-google-vids-images) | One JPEG of 1376×768, 1024×1024 or 768×1376, in 7 styles. | | Avatar | [POST /avatars](/docs/api-google-vids-v1/post-google-vids-avatars) | A picture plus a fixed voice, used in a video as `avatar_1`..`avatar_3`. | Vids image generation is basic: one prompt in, one small image out (about 1 megapixel, no larger size or upscale), and it takes no reference images. It is handy for quick references, avatar pictures and storyboards. For anything better, use the [Google Flow API](/docs/api-google-flow-v1/post-google-flow-images): Nano Banana with reference images, at up to 4K. ## Google Vids or Google Flow Both APIs generate Omni 1.1 Flash video on the same Google AI plan, from separate allowances. Vids does not use Flow credits, so connecting one Google account to both APIs gives you both allowances. | | Google Vids API | [Google Flow API](/docs/api-google-flow-v1) | |---|---|---| | Allowance | Seconds of video a month, separate from Flow | Flow credits a month | | One 10-second Omni clip | 10 seconds, at `720p` or `1080p` | 15 credits at `720p` | | 10-second Omni clips a month on Ultra $199 | about 1,000 (10,000 seconds, shared by the family plan) | about 1,666 (25,000 credits) | | Omni clip lengths | 3 to 10 seconds in 1-second steps | 4, 6, 8 or 10 seconds | | Extend an Omni clip | ✅ up to about 41 seconds | ❌ Veo clips only | | Captcha | none | reCAPTCHA on every generation | | Other models | — | Veo 3.1, Nano Banana images up to 4K | On Ultra $199 the two allowances together come to about 2,666 ten-second Omni clips a month on one Google account. #### What a 10-second Omni clip costs | Where | One 10-second Omni 1.1 Flash clip | 10-second clips a month | |---|---|---| | Google's metered [Gemini API](https://ai.google.dev/gemini-api/docs/pricing) | about $1.01 at `720p` | as many as you pay for | | [Google Flow API](/docs/api-google-flow-v1) on Google AI Ultra ($199) | 15 credits, about $0.12 | about 1,666 | | [Google Vids API](/docs/api-google-vids-v1) on Google AI Ultra ($199) | 10 seconds of allowance, about $0.20 | about 1,000, shared by the family plan | | Flow and Vids on the same Ultra account | about $0.07 | about 2,666 | The Gemini API bills Omni 1.1 Flash at 5,792 tokens per second of `720p` video, at $17.50 per million tokens. At that rate, 2,666 ten-second clips would cost about $2,700 a month, against one Ultra plan and the $15 useapi.net subscription. Prices as of October 2026. ## Plans and monthly allowances Google meters Vids by the month: video in seconds and images by count. Google's figures for its AI plans, from the [Gemini in Google Vids](https://support.google.com/docs/answer/15609411) help page: | | Google AI Plus | Google AI Pro | Google AI Ultra 5x | Google AI Ultra 20x | |---|---|---|---|---| | AI video clips | 6 a month, combined with AI avatars | 500 seconds a month | 2,500 seconds a month | 10,000 seconds a month | | Image generation and editing | 1 credit per image action | 30 a month | 300 a month | 1,000 a month | What we measured on real accounts (October 2026): - Google AI Ultra $199 is the plan Google calls Ultra 20x: 10,000 seconds of video and 1,000 images a month. - Video seconds are shared by everyone on a Google One family plan. Images are counted per account. Adding more accounts from the same family adds images and parallel jobs, but no video seconds. - A free Google account gets 0 seconds of video and 0 images in Vids, so [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts) refuses it. - A clip uses its length in seconds, and `720p` and `1080p` cost the same. An extend uses only the seconds it adds. An upscale uses the clip's seconds again, so pick `1080p` when you generate. - A request Google refuses, for content or for quota, uses nothing. - Allowances reset on the 1st of the month at 00:00 Pacific time. Every finished job reports what the account has left in `result.quota`, and [GET /accounts/`email`](/docs/api-google-vids-v1/get-google-vids-accounts-email) reads all counters live. When an allowance runs out, the job fails with `429` and `retryAt` set to the reset time. ## Watermark Google states that every Omni clip made in Vids carries an invisible SynthID watermark in its frames. Every MP4 we downloaded also has a visible Gemini ✦ sparkle in the bottom-right corner. Gemini's [media watermark setting](https://support.google.com/gemini/answer/17405358) does not reach Vids: with it switched off, new Vids clips still had the sparkle. The API returns Google's file unchanged. Images have no visible mark. ## How a generation runs - 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 `200` with 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 answers `202` with the job as it stands: fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid). Always check `status`: only `completed` has a `result`. - Async: pass `async: true` or a `replyUrl`. The POST answers `202` at once with the job in `status: "pending"`. Poll [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) or wait for the webhook. - `replyUrl` receives one `POST` of the final job record, as JSON, when the job completes or fails. - Each account runs at most `maxJobs` jobs at a time (default `3`, range `1` to `10`, set with [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts)). [GET /jobs](/docs/api-google-vids-v1/get-google-vids-jobs) shows what is running. Job records are kept for 30 days. Without `email`, a new job goes to one of your accounts that is healthy, has a free `maxJobs` slot and has an allowance for that kind of job. When Google refuses that job because the account's allowance is used up, it moves to another account and runs there. Name an account with `email` to pin a job to it. A job that uses an uploaded file, an avatar or an earlier clip runs on the account that holds it, since every id names its account. Accounts of one family plan share their video seconds, so spreading jobs over them runs more clips at the same time but does not add seconds. ## How long files last Generated videos, generated images and uploaded files live in Google's temporary storage. They are never saved to the account's Vids document, Google Drive or a gallery, so nothing piles up on the account and there is nothing to delete. Download the files you want to keep soon after they are made with [GET /media/`mediaId`](/docs/api-google-vids-v1/get-google-vids-media-mediaId): images stay available for a few hours, videos for at least half a day, and after that the download answers `404`. Upload an input with [POST /assets](/docs/api-google-vids-v1/post-google-vids-assets) shortly before the job that uses it. Avatars are the exception. They are saved in the account's Vids document, together with any avatars made in the Google Vids web app, until you delete them with [DELETE /avatars/`avatarId`](/docs/api-google-vids-v1/delete-google-vids-avatars-avatarId). ## Pricing A flat [$15/month](/docs/subscription) to useapi.net, which covers every useapi.net API, not only Google Vids. Each subscription lets you connect 3 Google accounts, up to 50 in total. Generation runs on your own Google accounts and uses their Vids allowance, so there is no per-clip charge from us. #### One Google account, four APIs The same Google AI plan powers several useapi.net APIs, each from its own allowance, so one Google account connected to all of them gets the most out of the plan: - [Google Flow API](/docs/api-google-flow-v1): Veo 3.1 and Omni 1.1 Flash video, Nano Banana images up to 4K, from Flow credits. - [Google Vids API](/docs/api-google-vids-v1): Omni 1.1 Flash video with avatars and voices, from the Vids allowance, which does not use Flow credits. - [NotebookLM API (Gemini Notebook API)](/docs/api-gemini-notebook-v1): chat with sources, Deep Research and every Studio output, from the Gemini Notebook usage limits. - [FlowMusic API](/docs/api-flowmusic-v1): full songs with Lyria in Google Flow Music, which signs in with a Google account too, on Flow Music's own plans. Each API is set up on its own setup page, and one useapi.net subscription covers all of them. ### Start using the API A single **$15/month** subscription covers every API on useapi.net — one token, all services. You connect up to 3 of your own provider accounts per service, and useapi.net handles the REST API, load balancing, and polling. [Subscribe — $15/month](https://buy.stripe.com/8x2aEX4Bd8Vh9PMg4qeUU03) [Pricing, crypto payment, and volume options](/docs/subscription) — full refund within the first 14 days if you have fewer than 50 successful generations. ⚙️ [Setup Google Vids](/docs/start-here/setup-google-vids) 🔑 [Google Account Setup](https://github.com/useapi/google-account-setup) scripts for a clean, single-use Google sign-in (Windows, macOS, Linux) 📦 [Postman collection](/assets/postman/google-vids-v1.json) (October 7, 2026) 🤖 [LLM-friendly API spec](https://useapi.net/assets/aibot/api-google-vids-v1.txt) Feed this to your LLM to build integrations Developer Community: * Discord Server * Telegram Channel === URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-accounts === Document URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-accounts --- layout: default title: POST accounts description: "Connect a Google AI account to the useapi.net Google Vids API with POST accounts by pasting its docs.google.com cookies, or update its maxJobs by email." parent: Google Vids API v1 nav_order: 100 permalink: /docs/api-google-vids-v1/post-google-vids-accounts --- ## Configure a Google Vids account October 7, 2026 --- Connect a Google account to the API with the cookies of a signed-in [Google Vids](https://docs.google.com/videos) session. The easiest way is the [automated setup](/assets/setup-browser/google-vids.html), which signs in for you and calls this endpoint. See [Setup Google Vids](/docs/start-here/setup-google-vids) for the setup script and the manual cookie copy. The API checks the cookies with Google before saving the account. The account email is read from Google, together with the account's monthly limits and how much of each is left. A free Google account has no Vids allowance (0 seconds of video and 0 images a month) and is refused with `400`. Use an account on a paid [Google AI plan](https://one.google.com/ai). The first time an account is added, the API creates one Google Vids document on it (`vidsDocId`). Every generation names that document, and it is where [avatars](/docs/api-google-vids-v1/post-google-vids-avatars) are saved. Generated videos and images are not stored in it. Posting cookies for an account that is already connected re-adds it: the cookies are replaced, and `added`, `maxJobs` and the Vids document are kept unless you send a new `maxJobs`. Re-adding is also how an account that Google signed out is brought back. After the account is added, do not open that Google account in a browser again. Google Vids needs the `__Secure-1PSIDTS` cookie on every call, and a browser using the same sign-in renews it, which ends the copy the API holds within minutes. This endpoint does two things. To add or re-add an account, post its `cookies`. To change only `maxJobs` on an account that is already connected, post `email` and `maxJobs` and leave `cookies` out: nothing is sent to Google then. Each [useapi.net subscription](/docs/subscription) lets you connect 3 Google accounts, up to 50 in total. > **https://api.useapi.net/v1/google-vids/accounts** ##### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Request Body Add or re-add an account: ```json { "cookies": "SID\tg.a000…\t.google.com\t/\t2027-11-01T00:00:00.000Z\t…\nOSID\tg.a000…\tdocs.google.com\t/\t…", "maxJobs": 3 } ``` - `cookies` is **required** to add or re-add an account. Copy the cookie table of `https://docs.google.com` from DevTools as described in [Setup Google Vids](/docs/start-here/setup-google-vids#manual-setup) and paste it exactly as copied. The paste must contain `SID`, `HSID`, `SSID`, `APISID`, `SAPISID` and `__Secure-1PSIDTS` for `.google.com`, plus `OSID` for `docs.google.com`. A missing cookie returns `400` naming it. Cookies that are not signed in to Google Vids, or that Google refuses for generation, return `400`. Only these seven cookies are stored, and their values are never returned by the API. - `maxJobs` is optional, the number of jobs this account may run at the same time. Range: `1` to `10`. Default: `3` for a new account, the current value on a re-add. Update a connected account: ```json { "email": "user@example.com", "maxJobs": 5 } ``` - `email` is **required** in this mode, the email of a connected account. Do not send it together with `cookies`. - `maxJobs` is **required** in this mode, the new concurrency limit. Range: `1` to `10`. ##### Responses **200** **200 OK** — the account was already connected and has been re-added. ```json { "email": "user@example.com", "maxJobs": 3, "added": "2026-10-06T22:51:03.032Z", "updated": "2026-10-07T01:03:28.469Z", "cookies": [ "SID", "HSID", "SSID", "APISID", "SAPISID", "__Secure-1PSIDTS", "OSID" ], "cookiesExpireAt": "2027-04-05T02:18:00.438Z", "vidsDocId": "13uYNqnKSfoLaWj1GYxZ3Wqe_06hY5k5i0S1_jPCXn2Y", "limits": { "video": 10000, "image": 1000, "music": 300 }, "health": "OK", "quota": { "video": { "limit": 10000, "left": 9936, "resetAt": "2026-11-01T07:00:00.000Z" }, "image": { "limit": 1000, "left": 990, "resetAt": "2026-11-01T07:00:00.000Z" }, "music": { "limit": 300, "left": 298, "resetAt": "2026-11-01T07:00:00.000Z" } } } ``` - `limits` are the monthly limits Google reported when the account was added: seconds of video, images, and songs (music is not used by this API). - `quota` is what the account has left right now. A counter Google did not answer is `null`. [GET /accounts/`email`](/docs/api-google-vids-v1/get-google-vids-accounts-email) reads it live at any time. - An update (`email` + `maxJobs`) returns the same record without `quota`. **201** **201 Created** — a new account was connected. Same body as `200`, without `updated`. **400** **400 Bad Request** — a required cookie is missing, the cookies are not signed in, the account's plan has no Vids allowance, `email` was sent with `cookies`, or a parameter is invalid. ```json { "error": "Missing cookies: __Secure-1PSIDTS. Copy them from docs.google.com/videos (DevTools → Application → Cookies).", "code": 400 } ``` ```json { "error": "user@example.com has no Google Vids allowance on its plan (0 video seconds and 0 images a month). Free Google accounts cannot generate in Vids. Use an account on a Google AI plan.", "code": 400 } ``` ```json { "error": "These cookies are not signed in to Google Vids (HTTP 302 → sign-in). Sign in at https://docs.google.com/videos and copy the cookies again.", "code": 400 } ``` ```json { "error": "Google refused these cookies for Vids generation (401). Copy them again from docs.google.com/videos.", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **402** **402 Payment Required** — the subscription has expired, or a new account needs another [subscription](/docs/subscription). ```json { "error": "useapi.net ⁝ You have 1 subscription, you need 1 additional subscription (2 total) to support 4 accounts for the google_vids API. Upgrade at https://useapi.net/docs/subscription", "code": 402 } ``` **404** **404 Not Found** — update mode: no account is connected for this `email`. ```json { "error": "Account user@example.com not found", "code": 404 } ``` **502** **502 Bad Gateway** — the cookies are signed in, but Google's Vids page did not give the API what it needs, or the Vids document could not be created. Nothing was saved. Retry the same request. ```json { "error": "Could not create the Vids document for this account — please retry", "code": 502 } ``` ##### Model `200` and `201` return the same account record. ```typescript { // TypeScript, all fields are optional email: string maxJobs: number // jobs this account may run at the same time added: string // ISO 8601, when the account was first connected updated?: string // ISO 8601, the last re-add or maxJobs change cookies: string[] // names of the stored cookies, never their values cookiesExpireAt?: string | null // ISO 8601, the earliest expiry date in the pasted cookies vidsDocId: string // the Google Vids document the API created on the account limits: { // monthly limits read from Google when the account was added video: number | null // seconds of video image: number | null // images music: number | null // songs (not used by this API) } health: string // 'OK', 'verifying', or the reason the account must be re-added addedVia?: 'setup-browser' // present when the account was added by the automated setup quota?: { // add and re-add only: what is left right now, null when a counter did not answer video: { limit: number, left: number, resetAt: string } | null // seconds of video image: { limit: number, left: number, resetAt: string } | null // images music: { limit: number, left: number, resetAt: string } | null // songs (not used by this API) } } ``` ##### Examples **Curl** ``` bash curl -X POST "https://api.useapi.net/v1/google-vids/accounts" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer …" \ -d '{ "email": "user@example.com", "maxJobs": 5 }' ``` **JavaScript** ``` javascript const token = "API token"; const cookies = "Cookie table of https://docs.google.com copied from DevTools"; const apiUrl = "https://api.useapi.net/v1/google-vids/accounts"; const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}`, }, body: JSON.stringify({ cookies, maxJobs: 3 }) }); const result = await response.json(); console.log("response", {response, result}); ``` **Python** ``` python import requests token = "API token" cookies = "Cookie table of https://docs.google.com copied from DevTools" apiUrl = "https://api.useapi.net/v1/google-vids/accounts" headers = { "Content-Type": "application/json", "Authorization" : f"Bearer {token}" } data = { "cookies": cookies, "maxJobs": 3 } response = requests.post(apiUrl, headers=headers, json=data) print(response, response.json()) ``` === URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-assets === Document URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-assets --- layout: default title: POST assets description: "Upload a JPEG, PNG, WebP or MP4 of up to 50 MB via POST assets in the useapi.net Google Vids API and get the assetId for a start image, reference or video edit." parent: Google Vids API v1 nav_order: 400 permalink: /docs/api-google-vids-v1/post-google-vids-assets --- ## Upload an asset October 7, 2026 --- Upload an image or a video to one of your accounts and get an `assetId` for it. The file is sent as the raw request body with its MIME type in the `Content-Type` header (no multipart, no JSON). Where an `assetId` goes: - An image is a `startImage` or a `referenceImage_1`..`referenceImage_3` of [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos). An image made with [POST /images](/docs/api-google-vids-v1/post-google-vids-images) needs no upload: pass its `mediaId` there directly. - Uploaded videos cannot be edited: Google refuses every edit of an uploaded video. To edit a clip, pass the `mediaId` of a clip made with this API to [POST /videos/edit](/docs/api-google-vids-v1/post-google-vids-videos-edit). - [POST /avatars](/docs/api-google-vids-v1/post-google-vids-avatars) does not take an uploaded photo, see there why. The `assetId` names the account the file was uploaded to, and only jobs on that account can use it. To use several uploads in one video, upload them all to the same account with `email`. An upload takes no `maxJobs` slot and uses no allowance. Uploads are temporary like every Vids file, so upload an input shortly before the job that uses it. See [How long files last](/docs/api-google-vids-v1#how-long-files-last). > **https://api.useapi.net/v1/google-vids/assets?email=`email`** ##### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: image/jpeg # image/jpeg, image/png, image/webp or video/mp4 ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. - `Content-Type` is **required**, the file's MIME type. Supported values: `image/jpeg`, `image/png`, `image/webp`, `video/mp4`. The request body is the file's raw bytes, from 1 byte to `50 MB`. ##### Query Parameters - `email` is optional, the account to upload to. When omitted, a healthy account is picked at random. URL-encode it. ##### Responses **200** **200 OK** ```json { "assetId": "user:12345-user@example.com-asset:AVL_0qjhK1XnT8IYzCoB9dCO4XxlyHvHv54IZep9pWDRq7fNu8bo7WF-qhIC6OzxYEVNrPLOm1e5x9BrxROKgHRUCIeFWQ_r1tRbzBHTMGfER_jmittzbVWQfvZjzrU2Qv4CyCZtaeJMoqfkPWgZMA5QmCoS8zRLIeapAuj5lYbhjWQgIfRrmdA", "email": "user@example.com", "type": "image/jpeg", "bytes": 113184 } ``` **400** **400 Bad Request** — an unsupported `Content-Type`, an empty body, or a file over 50 MB. ```json { "error": "Content-Type must be one of image/jpeg, image/png, image/webp, video/mp4 (raw file bytes in the body)", "code": 400 } ``` ```json { "error": "File must be 1 byte to 50 MB", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **404** **404 Not Found** — the account named by `email` is not connected. ```json { "error": "Account user@example.com is not configured", "code": 404 } ``` **503** **503 Service Unavailable** — Google did not accept the upload. Retry shortly. ```json { "error": "Google error: Upload failed (HTTP 500)", "code": 503 } ``` **596** **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](/docs/start-here/setup-google-vids). ```json { "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 } ``` ```json { "error": "Account user@example.com: Google signed this account out. Re-add it at https://useapi.net/docs/start-here/setup-google-vids", "code": 596 } ``` ##### Model ```typescript { // TypeScript, all fields are optional assetId: string // user:--asset:AVL_…, pass it as startImage, referenceImage_N or video email: string // the account the file was uploaded to type: string // the Content-Type you sent bytes: number // the file size error?: string // errors only code?: number // errors only } ``` ##### Examples **Curl** ``` bash curl -X POST "https://api.useapi.net/v1/google-vids/assets?email=user%40example.com" \ -H "Authorization: Bearer …" \ -H "Content-Type: image/jpeg" \ --data-binary @dog.jpg ``` **JavaScript** ``` javascript import fs from "fs"; const token = "API token"; const email = "Previously configured account email"; const apiUrl = `https://api.useapi.net/v1/google-vids/assets?email=${encodeURIComponent(email)}`; const response = await fetch(apiUrl, { method: "POST", headers: { "Authorization": `Bearer ${token}`, "Content-Type": "image/jpeg", }, body: fs.readFileSync("dog.jpg") }); const result = await response.json(); console.log("response", {response, result}); ``` **Python** ``` python import requests token = "API token" email = "Previously configured account email" apiUrl = "https://api.useapi.net/v1/google-vids/assets" headers = { "Authorization" : f"Bearer {token}", "Content-Type": "image/jpeg" } with open("dog.jpg", "rb") as f: response = requests.post(apiUrl, headers=headers, params={"email": email}, data=f.read()) print(response, response.json()) ``` === URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-avatars === Document URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-avatars --- layout: default title: POST avatars description: "Create a voiced avatar via POST avatars in the useapi.net Google Vids API from a description or an image, with one of 30 Gemini voices, for use in videos." parent: Google Vids API v1 nav_order: 600 permalink: /docs/api-google-vids-v1/post-google-vids-avatars --- ## Create an avatar October 7, 2026 --- An avatar is a picture of a person plus a fixed voice. Pass its `avatarId` as `avatar_1`..`avatar_3` to [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos), and the clip shows that person speaking the lines you write in the prompt, in the avatar's voice. One clip can hold several avatars, for a dialogue. The picture comes from one of two places: - A description: send `appearance`, plus `outfit`, `shot`, `expression` and `details` if you like, and Google draws the person. The response carries the picture as `previewMediaId`, which [GET /media/`mediaId`](/docs/api-google-vids-v1/get-google-vids-media-mediaId) downloads. - An image made with [POST /images](/docs/api-google-vids-v1/post-google-vids-images): pass its `mediaId` as `image`. An avatar cannot be made from your own photo. An avatar of a real person is Google's likeness feature, which requires a live selfie video and a phone check in the browser, and an API cannot do that. `POST /avatars` refuses an uploaded photo with `400`. The voice is one of the 30 voices listed by [GET /voices](/docs/api-google-vids-v1/get-google-vids-voices), named by its Vids name (`Holt`) or its Google voice id (`Charon`). The avatar is saved in the account's Vids document, where [GET /avatars](/docs/api-google-vids-v1/get-google-vids-avatars) lists it and [DELETE /avatars/`avatarId`](/docs/api-google-vids-v1/delete-google-vids-avatars-avatarId) removes it. It can be used only by videos on that account. ### Cost - Drawing the picture from a description uses 1 image of the account's monthly Vids images. - An avatar from an image made with [POST /images](/docs/api-google-vids-v1/post-google-vids-images) costs nothing more. The image was paid for when it was made. - Voices are free. - A video with an avatar costs its seconds like any other clip, and the avatar takes one of its 3 reference slots. Creating an avatar takes about 20 seconds from a description and about 2 seconds from an image. It answers when the avatar is saved and takes no `maxJobs` slot. > **https://api.useapi.net/v1/google-vids/avatars** ##### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Request Body From a description: ```json { "name": "Marco", "voice": "Holt", "appearance": "a middle-aged man with a short grey beard", "outfit": "navy blazer over a white shirt", "shot": "upper-body", "expression": "a calm, friendly smile", "details": "warm studio lighting", "email": "user@example.com" } ``` From an image made with [POST /images](/docs/api-google-vids-v1/post-google-vids-images): ```json { "name": "Ruby", "voice": "Kaci", "image": "user:12345-user@example.com-image:eyJ1IjoiaHR0…" } ``` - `name` is **required**, the avatar's name. It is a label only and plays no part in a video prompt. Length: `1` to `40` characters. - `voice` is **required**, a voice `name` or `voice` id from [GET /voices](/docs/api-google-vids-v1/get-google-vids-voices), case-insensitive. - `image` is the image `mediaId` of a picture made with [POST /images](/docs/api-google-vids-v1/post-google-vids-images). Send either `image` or `appearance`. An `assetId` of an uploaded photo is refused, see above. - `appearance` is the person to draw, for example their age, hair and features. Send either `appearance` or `image`. Maximum length: `500` characters. - `outfit` is optional with `appearance`, what the person wears. Maximum length: `300` characters. - `shot` is optional with `appearance`, the framing of the picture. Supported values: `close-up` (head and shoulders), `upper-body` (from the waist up), `full-body` (head to feet). Default: `close-up`. - `expression` is optional with `appearance`, the facial expression. When omitted, Google is asked for a smile with teeth. Maximum length: `200` characters. - `details` is optional with `appearance`, anything else about the picture. Maximum length: `1000` characters. - `email` is optional, the account to save the avatar on. With `image`, it defaults to the account that made the image and must match it. Without `image`, a healthy account with an image allowance is picked when it is omitted. ##### Responses **201** **201 Created** From a description: ```json { "avatarId": "user:12345-user@example.com-avatar:eyJnIjoiaDMy…", "name": "Marco", "voice": "Holt", "voiceId": "Charon", "voiceStyle": "Informative", "voicePreview": "https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Charon.wav", "email": "user@example.com", "source": "generated", "previewMediaId": "user:12345-user@example.com-image:eyJ1IjoiaHR0…", "look": { "appearance": "a middle-aged man with a short grey beard", "outfit": "navy blazer over a white shirt", "shot": "upper-body", "expression": "a calm, friendly smile", "details": "warm studio lighting" } } ``` From an image: ```json { "avatarId": "user:12345-user@example.com-avatar:eyJnIjoiaDMy…", "name": "Ruby", "voice": "Kaci", "voiceId": "Autonoe", "voiceStyle": "Bright", "voicePreview": "https://ssl.gstatic.com/docs/videos/audio/voice_samples/gemini-v4s-tts/1.1/en/Autonoe.wav", "email": "user@example.com", "source": "image" } ``` **400** **400 Bad Request** — an unknown voice, neither or both of `image` and `appearance`, an uploaded photo, an image from another account than `email`, an invalid parameter, or Google refused the request. ```json { "error": "Unknown voice Bob. GET /voices lists them (name or voice id)", "code": 400 } ``` ```json { "error": "Give image (an image mediaId from POST /images) or appearance (a description to generate the picture from)", "code": 400 } ``` ```json { "error": "An avatar from your own photo needs Google's identity check (a live selfie video and phone verification in the browser), which an API cannot do. Use an image made with POST /images (pass its mediaId as image), or describe the person with appearance", "code": 400 } ``` ```json { "error": "Parameter name is required", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **403** **403 Forbidden** — the `image` id was issued to a different API token. ```json { "error": "image id does not belong to this API token", "code": 403 } ``` **404** **404 Not Found** — the account named by `email` or by the image id is not connected. ```json { "error": "Account user@example.com is not configured", "code": 404 } ``` **502** **502 Bad Gateway** — Google did not save the avatar. Retry. ```json { "error": "Google did not keep the avatar in the Vids document, please retry", "code": 502 } ``` **596** **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](/docs/start-here/setup-google-vids). ```json { "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 } ``` ```json { "error": "Account user@example.com: Google signed this account out. Re-add it at https://useapi.net/docs/start-here/setup-google-vids", "code": 596 } ``` ##### Model ```typescript { // TypeScript, all fields are optional avatarId: string // user:--avatar:…, pass it as avatar_1..avatar_3 to POST /videos name: string voice: string // the Vids voice name, e.g. 'Holt' voiceId: string // Google's voice id, e.g. 'Charon' voiceStyle: string // Google's label for the voice, e.g. 'Informative' voicePreview: string // a public English sample of the voice (WAV) email: string // the account the avatar is saved on source: 'generated' | 'image' previewMediaId?: string // source 'generated': the drawn picture, download it with GET /media/{mediaId} look?: { // source 'generated': the description you sent appearance: string outfit?: string shot: 'close-up' | 'upper-body' | 'full-body' expression?: string details?: string } error?: string // errors only code?: number // errors only } ``` ##### Examples **Curl** ``` bash curl -X POST "https://api.useapi.net/v1/google-vids/avatars" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer …" \ -d '{ "name": "Marco", "voice": "Holt", "appearance": "a middle-aged man with a short grey beard", "outfit": "navy blazer over a white shirt", "shot": "upper-body" }' ``` **JavaScript** ``` javascript const token = "API token"; const apiUrl = "https://api.useapi.net/v1/google-vids"; const headers = { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }; const avatar = await (await fetch(`${apiUrl}/avatars`, { method: "POST", headers, body: JSON.stringify({ name: "Marco", voice: "Holt", appearance: "a middle-aged man with a short grey beard", shot: "upper-body" }) })).json(); console.log("avatar", avatar); const job = await (await fetch(`${apiUrl}/videos`, { method: "POST", headers, body: JSON.stringify({ prompt: "@avatar_1 looks into the camera and says: \"Hi, I'm Marco. Welcome to our channel.\"", avatar_1: avatar.avatarId, duration: 4 }) })).json(); console.log("video", job.result ?? job.error ?? job); ``` **Python** ``` python import requests token = "API token" apiUrl = "https://api.useapi.net/v1/google-vids" headers = { "Content-Type": "application/json", "Authorization" : f"Bearer {token}" } data = { "name": "Marco", "voice": "Holt", "appearance": "a middle-aged man with a short grey beard", "shot": "upper-body" } avatar = requests.post(f"{apiUrl}/avatars", headers=headers, json=data).json() print(avatar) ``` === URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-images === Document URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-images --- layout: default title: POST images description: "Generate a JPEG via POST images in the useapi.net Google Vids API: 16:9, 1:1 or 9:16 at about 1 megapixel in 7 styles, for references and avatars." parent: Google Vids API v1 nav_order: 300 permalink: /docs/api-google-vids-v1/post-google-vids-images --- ## Generate an image October 7, 2026 --- Generate one image from a prompt with the image generator of [Google Vids](https://docs.google.com/videos). 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](/docs/api-google-flow-v1/post-google-flow-images): Nano Banana with reference images, at up to 4K. How to use the result: - As an avatar picture: pass its `mediaId` as `image` to [POST /avatars](/docs/api-google-vids-v1/post-google-vids-avatars). - As a `startImage` or `referenceImage_N` of [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos): pass its `mediaId`. 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](/docs/api-google-vids-v1#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`](/docs/api-google-vids-v1/get-google-vids-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 `200` with 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 answers `202` with the job as it stands: fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid). Always check `status`: only `completed` has a `result`. - Async: pass `async: true` or a `replyUrl`. The POST answers `202` at once with the job in `status: "pending"`. Poll [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) or wait for the webhook. - `replyUrl` receives one `POST` of the final job record, as JSON, when the job completes or fails. - Each account runs at most `maxJobs` jobs at a time (default `3`, range `1` to `10`, set with [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts)). [GET /jobs](/docs/api-google-vids-v1/get-google-vids-jobs) shows what is running. Job records are kept for 30 days. > **https://api.useapi.net/v1/google-vids/images** ##### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Request Body ```json { "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" } ``` - `prompt` is **required**, what the image shows. Maximum length: `5000` characters. - `aspectRatio` is optional. Supported values: `16:9`, `1:1`, `9:16`. Default: `16:9`. - `style` is optional, one of the style presets of the Vids image panel. Supported values: `none`, `photography`, `sketch`, `background`, `watercolor`, `vector-art`, `cyberpunk`. Default: `none`. - `email` is optional, the account to run on. When omitted, a healthy account with a free `maxJobs` slot and an image allowance is used. - `async` is optional, `true` to answer `202` at once and run the job in the background. Default: `false`. - `replyUrl` is optional, a public `http(s)` URL that receives one `POST` of 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/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) response. Maximum length: `1024` characters. - `replyRef` is optional, your own reference echoed back in the job record. Maximum length: `1024` characters. ##### Responses **200** **200 OK** — sync mode, the image is ready. ```json { "jobid": "user:12345-user@example.com-job:e16a974f-c4ff-4b5a-ba2a-5d6c5c076c82", "type": "image", "email": "user@example.com", "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:12345-user@example.com-image: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** **202 Accepted** — the job is running: with `async: true` or `replyUrl` at once, in sync mode after about 100 seconds of waiting. Fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) (or wait for the webhook). ```json { "jobid": "user:12345-user@example.com-job:f8e8da27-d86e-4f89-bcb3-cabf783945cb", "type": "image", "email": "user@example.com", "status": "pending", "created": "2026-10-07T06:29:29.018Z", "request": { "prompt": "A cup of coffee with latte art, top view", "async": true } } ``` **400** **400 Bad Request** — a parameter is missing or invalid, or Google rejected the request. ```json { "error": "Parameter style (oil-painting) valid values: none,photography,sketch,background,watercolor,vector-art,cyberpunk", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **403** **403 Forbidden** — the account's Google plan has no Vids image allowance. The body is the failed job record with `error.code: 403`. **404** **404 Not Found** — the account named by `email` is not connected. ```json { "error": "Account user@example.com is not configured", "code": 404 } ``` **422** **422 Unprocessable Content** — Google refused the prompt. Nothing was charged. The body is the failed job record, see [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos). **429** **429 Too Many Requests** — the account is running `maxJobs` jobs, every account is busy, the month's images are used up (`error.retryAt` is the reset time), or Google is limiting the account for a minute. ```json { "error": "All 2 healthy accounts are running their maximum number of jobs (maxJobs), please retry shortly", "code": 429 } ``` **504** **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. ```json { "jobid": "user:12345-user@example.com-job:874b371d-b6a2-43c9-88d5-5989bfe5a951", "type": "image", "email": "user@example.com", "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** **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](/docs/start-here/setup-google-vids). ```json { "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 } ``` ```json { "error": "Account user@example.com: 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: ```json { "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`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) and the `replyUrl` webhook return the same shape. An image result has no `duration`, `resolution` or `aspectRatio`. ```typescript { // TypeScript, all fields are optional jobid: string // user:--job: 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 // 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** ``` bash 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" }' ``` **JavaScript** ``` javascript 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); ``` **Python** ``` python 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) ``` === URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-videos-edit === Document URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-videos-edit --- layout: default title: POST videos/edit description: "Edit a generated Gemini Omni clip by prompt via POST videos/edit in the useapi.net Google Vids API: recolour, add objects or restyle. Google refuses uploads." parent: Google Vids API v1 nav_order: 230 permalink: /docs/api-google-vids-v1/post-google-vids-videos-edit --- ## Edit a video October 7, 2026 --- Change a clip with a prompt, for example "Make the paper boat bright yellow". The result is a new clip with a new `mediaId`, and the job runs on the account that holds the source. Edit works on clips Google made: pass a video `mediaId` from [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos), [POST /videos/extend](/docs/api-google-vids-v1/post-google-vids-videos-extend) or [POST /videos/upscale](/docs/api-google-vids-v1/post-google-vids-videos-upscale). In our tests 7 of 7 edits of generated clips worked, including a colour change, an added object, a restyle, an extended 8-second clip and a `1080p` portrait clip. The API also accepts an uploaded video, an `assetId` from [POST /assets](/docs/api-google-vids-v1/post-google-vids-assets), but Google refuses those at once with `422`. That happened to every upload we tried, even a clip this API had generated and we uploaded again. A refusal uses nothing. ### Cost An edit uses the clip's length in seconds from the account's monthly Vids video allowance, the same as generating a clip of that length. A request Google refuses uses nothing. ### 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 `200` with 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 answers `202` with the job as it stands: fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid). Always check `status`: only `completed` has a `result`. - Async: pass `async: true` or a `replyUrl`. The POST answers `202` at once with the job in `status: "pending"`. Poll [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) or wait for the webhook. - `replyUrl` receives one `POST` of the final job record, as JSON, when the job completes or fails. - Each account runs at most `maxJobs` jobs at a time (default `3`, range `1` to `10`, set with [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts)). [GET /jobs](/docs/api-google-vids-v1/get-google-vids-jobs) shows what is running. Job records are kept for 30 days. > **https://api.useapi.net/v1/google-vids/videos/edit** ##### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Request Body ```json { "video": "user:12345-user@example.com-video:eyJ1IjoiaHR0…", "prompt": "Make the paper boat bright yellow", "async": true, "replyUrl": "https://your-domain.com/webhook", "replyRef": "boat-yellow" } ``` - `video` is **required**, the video `mediaId` of the clip to edit, from a finished job's `result`. An `assetId` of an uploaded MP4 is accepted, but Google refuses it. - `prompt` is **required**, the change to make. Maximum length: `5000` characters. - `duration` is optional for a `mediaId`, where it defaults to the clip's length, and **required** for an `assetId`, where it is the uploaded video's length in seconds. Range: `3` to `10`. - `aspectRatio` is optional. Supported values: `landscape`, `portrait`. Default: the source clip's (`landscape` for an `assetId`). - `resolution` is optional. Supported values: `720p`, `1080p`. Default: the source clip's (`720p` for an `assetId`). - `async` is optional, `true` to answer `202` at once and run the job in the background. Default: `false`. - `replyUrl` is optional, a public `http(s)` URL that receives one `POST` of 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/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) response. Maximum length: `1024` characters. - `replyRef` is optional, your own reference echoed back in the job record. Maximum length: `1024` characters. ##### Responses **200** **200 OK** — sync mode, a 3-second clip edited, charged 3 seconds. ```json { "jobid": "user:12345-user@example.com-job:cb856ace-5b20-4bad-8476-70a03c492cb8", "type": "video", "mode": "edit", "email": "user@example.com", "status": "completed", "created": "2026-10-07T06:28:21.680Z", "request": { "video": "user:12345-user@example.com-video:eyJ1IjoiaHR0…", "prompt": "Make the paper boat bright yellow" }, "updated": "2026-10-07T06:28:59.896Z", "completed": "2026-10-07T06:28:59.896Z", "result": { "mediaId": "user:12345-user@example.com-video:eyJ1IjoiaHR0…", "width": 1280, "height": 720, "duration": 3, "resolution": "720p", "aspectRatio": "landscape", "model": "/flix/generate_videos_omni_edit_psq/v1", "quota": { "video": { "limit": 10000, "left": 9621, "resetAt": "2026-11-01T07:00:00.000Z" } }, "elapsedMs": 38167 } } ``` **202** **202 Accepted** — the job is running: with `async: true` or `replyUrl` at once, in sync mode after about 100 seconds of waiting. Fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) (or wait for the webhook). **400** **400 Bad Request** — a parameter is missing or invalid. ```json { "error": "duration (the uploaded video's length in seconds, 3–10) is required when video is an asset id", "code": 400 } ``` ```json { "error": "Parameter video is not a valid video / asset id", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **403** **403 Forbidden** — the `video` id was issued to a different API token. ```json { "error": "video id does not belong to this API token", "code": 403 } ``` **404** **404 Not Found** — the account that holds the source is no longer connected. ```json { "error": "Account user@example.com (from the video id) is not configured", "code": 404 } ``` **422** **422 Unprocessable Content** — Google refused the edit. Every uploaded video gets this answer. Nothing was charged. ```json { "jobid": "user:12345-user@example.com-job:db97658a-1240-4eee-a9dc-75f7c5123d2e", "type": "video", "mode": "edit", "email": "user@example.com", "status": "failed", "created": "2026-10-07T06:36:31.478Z", "request": { "video": "user:12345-user@example.com-asset:AVL_0qh2dWHI…", "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." } } ``` **429** **429 Too Many Requests** — the account is running `maxJobs` jobs, the month's video allowance is used up (`error.retryAt` is the reset time), or Google is limiting the account for a minute. ```json { "error": "Account user@example.com is running 3 of 3 jobs (maxJobs). Wait for one to finish, or raise maxJobs with POST /accounts", "code": 429 } ``` **504** **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** **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](/docs/start-here/setup-google-vids). ```json { "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 } ``` ```json { "error": "Account user@example.com: 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: "edit"`. [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) and the `replyUrl` webhook return the same shape. ```typescript { // TypeScript, all fields are optional jobid: string // user:--job: 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 // 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** ``` bash curl -X POST "https://api.useapi.net/v1/google-vids/videos/edit" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer …" \ -d '{ "video": "user:12345-user@example.com-video:eyJ1IjoiaHR0…", "prompt": "Make the paper boat bright yellow" }' ``` **JavaScript** ``` javascript const token = "API token"; const video = "mediaId of a clip made by this API"; const apiUrl = "https://api.useapi.net/v1/google-vids/videos/edit"; const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}`, }, body: JSON.stringify({ video, prompt: "Make the paper boat bright yellow" }) }); const job = await response.json(); console.log("response", response.status, job.result ?? job.error ?? job); ``` **Python** ``` python import requests token = "API token" video = "mediaId of a clip made by this API" apiUrl = "https://api.useapi.net/v1/google-vids/videos/edit" headers = { "Content-Type": "application/json", "Authorization" : f"Bearer {token}" } data = { "video": video, "prompt": "Make the paper boat bright yellow" } response = requests.post(apiUrl, headers=headers, json=data) print(response, response.json()) ``` === URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-videos-extend === Document URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-videos-extend --- layout: default title: POST videos/extend description: "Extend a Gemini Omni clip by 3–10 seconds via POST videos/extend in the useapi.net Google Vids API, up to about 41 s, optionally switching to portrait or 1080p." parent: Google Vids API v1 nav_order: 210 permalink: /docs/api-google-vids-v1/post-google-vids-videos-extend --- ## Extend a video October 7, 2026 --- Continue a clip made by this API with 3 to 10 more seconds of Gemini Omni 1.1 Flash video. The `prompt` describes what happens in the new seconds. The result is the whole clip, the source followed by its continuation, with a new `mediaId`. A 3-second clip extended by 3 seconds comes back as one 6-second clip. The source is a video `mediaId` from [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos), an earlier extend, [POST /videos/upscale](/docs/api-google-vids-v1/post-google-vids-videos-upscale) or [POST /videos/edit](/docs/api-google-vids-v1/post-google-vids-videos-edit). The job runs on the account that made it. One clip can be extended several times, each extend branching into its own new clip. An extend may change the shape of the clip. With `aspectRatio` and `resolution` left out, the result keeps the source's. Set them to turn a landscape clip into a portrait one, or a `720p` clip into `1080p`, and the whole returned clip has the new shape. [Google Flow](/docs/api-google-flow-v1/post-google-flow-videos-extend) extends Veo clips only, so this is the way to extend an Omni clip. ### How long a clip can get Google keeps about the first 31 seconds of the source. Chains of extends work up to 40 seconds, for example 10 + 10 + 10 + 10, and each step returns the whole clip. Extending a longer clip returns its first ~31 seconds plus the new seconds and drops the rest of the source: in our tests a 40-second clip extended by 10 came back as 41 seconds, and by 4 as 35 seconds. So the longest clip is about 41 seconds. An extend takes longer as the clip grows, about 65, 78 and 94 seconds for results of 20, 30 and 40 seconds. That is close to the 120-second limit of a sync request, so run long extends with `async: true` or a `replyUrl`. ### Cost An extend uses only the seconds it adds, its `duration`, from the account's monthly Vids video allowance, whatever the length of the source. A request Google refuses uses nothing. ### 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 `200` with 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 answers `202` with the job as it stands: fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid). Always check `status`: only `completed` has a `result`. - Async: pass `async: true` or a `replyUrl`. The POST answers `202` at once with the job in `status: "pending"`. Poll [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) or wait for the webhook. - `replyUrl` receives one `POST` of the final job record, as JSON, when the job completes or fails. - Each account runs at most `maxJobs` jobs at a time (default `3`, range `1` to `10`, set with [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts)). [GET /jobs](/docs/api-google-vids-v1/get-google-vids-jobs) shows what is running. Job records are kept for 30 days. > **https://api.useapi.net/v1/google-vids/videos/extend** ##### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Request Body ```json { "mediaId": "user:12345-user@example.com-video:eyJ1IjoiaHR0…", "prompt": "Camera tilts up to the rainy sky", "duration": 3, "aspectRatio": "portrait", "resolution": "1080p", "async": true, "replyUrl": "https://your-domain.com/webhook", "replyRef": "boat-extend-1" } ``` - `mediaId` is **required**, the video `mediaId` of the clip to extend, from a finished job's `result`. - `prompt` is **required**, what happens in the added seconds. Maximum length: `5000` characters. - `duration` is optional, the number of seconds to add. Range: `3` to `10`. Default: `8`. - `aspectRatio` is optional, the shape of the returned clip. Supported values: `landscape`, `portrait`. Default: the source clip's. - `resolution` is optional, the resolution of the returned clip. Supported values: `720p`, `1080p`. Default: the source clip's. - `async` is optional, `true` to answer `202` at once and run the job in the background. Default: `false`. - `replyUrl` is optional, a public `http(s)` URL that receives one `POST` of 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/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) response. Maximum length: `1024` characters. - `replyRef` is optional, your own reference echoed back in the job record. Maximum length: `1024` characters. ##### Responses **200** **200 OK** — sync mode. Here a 3-second landscape `720p` clip was extended by 3 seconds into a 6-second portrait `1080p` clip, charged 3 seconds. ```json { "jobid": "user:12345-user@example.com-job:cb215bfd-7134-4d71-bef2-e1991ff81848", "type": "video", "mode": "extend", "email": "user@example.com", "status": "completed", "created": "2026-10-07T06:26:11.800Z", "request": { "mediaId": "user:12345-user@example.com-video:eyJ1IjoiaHR0…", "prompt": "Camera tilts up to the rainy sky", "duration": 3, "aspectRatio": "portrait", "resolution": "1080p" }, "updated": "2026-10-07T06:27:52.191Z", "completed": "2026-10-07T06:27:52.191Z", "result": { "mediaId": "user:12345-user@example.com-video:eyJ1IjoiaHR0…", "width": 1080, "height": 1920, "duration": 6, "resolution": "1080p", "aspectRatio": "portrait", "model": "/flix/generate_videos_omni_extend_psq/v1", "quota": { "video": { "limit": 10000, "left": 9627, "resetAt": "2026-11-01T07:00:00.000Z" } }, "elapsedMs": 100336 } } ``` **202** **202 Accepted** — the job is running: with `async: true` or `replyUrl` at once, in sync mode after about 100 seconds of waiting. Fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) (or wait for the webhook). **400** **400 Bad Request** — a parameter is missing or invalid, or Google rejected the request. ```json { "error": "Parameter mediaId is not a valid video id", "code": 400 } ``` ```json { "error": "Parameter duration (11) is more than 10", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **403** **403 Forbidden** — the `mediaId` was issued to a different API token. ```json { "error": "video id does not belong to this API token", "code": 403 } ``` **404** **404 Not Found** — the account that made the clip is no longer connected. ```json { "error": "Account user@example.com (from the video id) is not configured", "code": 404 } ``` **422** **422 Unprocessable Content** — Google refused the prompt or the clip. Nothing was charged. The body is the failed job record, see [POST /videos](/docs/api-google-vids-v1/post-google-vids-videos). **429** **429 Too Many Requests** — the account is running `maxJobs` jobs, the month's video allowance is used up (`error.retryAt` is the reset time), or Google is limiting the account for a minute. ```json { "error": "Account user@example.com is running 3 of 3 jobs (maxJobs). Wait for one to finish, or raise maxJobs with POST /accounts", "code": 429 } ``` **503** **503 Service Unavailable** — Google answered with a server error. We saw this once when extending a 40-second clip. Retry, or extend a shorter clip. ```json { "error": { "code": 503, "message": "Google error: Internal error encountered." } } ``` The body is the failed job record, shortened here to its `error`. **504** **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. ```json { "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" } } ``` The body is the failed job record, shortened here to its `error`. **596** **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](/docs/start-here/setup-google-vids). ```json { "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 } ``` ```json { "error": "Account user@example.com: 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: "extend"`. [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) and the `replyUrl` webhook return the same shape. `result.duration` is the length of the whole returned clip. ```typescript { // TypeScript, all fields are optional jobid: string // user:--job: 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 // 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** ``` bash curl -X POST "https://api.useapi.net/v1/google-vids/videos/extend" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer …" \ -d '{ "mediaId": "user:12345-user@example.com-video:eyJ1IjoiaHR0…", "prompt": "The paper boat spins and sails into a puddle", "duration": 10, "async": true }' ``` **JavaScript** ``` javascript const token = "API token"; const mediaId = "mediaId of a clip made by this API"; const apiUrl = "https://api.useapi.net/v1/google-vids"; const headers = { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }; const response = await fetch(`${apiUrl}/videos/extend`, { method: "POST", headers, body: JSON.stringify({ mediaId, prompt: "The paper boat spins and sails into a puddle", duration: 10, async: true }) }); let job = await response.json(); while (job.status === "pending" || job.status === "processing") { await new Promise(r => setTimeout(r, 10000)); job = await (await fetch(`${apiUrl}/jobs/${encodeURIComponent(job.jobid)}`, { headers })).json(); } console.log("job", job.result ?? job.error); ``` **Python** ``` python import time import requests from urllib.parse import quote token = "API token" mediaId = "mediaId of a clip made by this API" apiUrl = "https://api.useapi.net/v1/google-vids" headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"} data = {"mediaId": mediaId, "prompt": "The paper boat spins and sails into a puddle", "duration": 10, "async": True} job = requests.post(f"{apiUrl}/videos/extend", headers=headers, json=data).json() while job.get("status") in ("pending", "processing"): time.sleep(10) job = requests.get(f"{apiUrl}/jobs/{quote(job['jobid'], safe='')}", headers=headers).json() print(job.get("result") or job.get("error")) ``` === URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-videos-upscale === Document URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-videos-upscale --- layout: default title: POST videos/upscale description: "Upscale a 720p Gemini Omni clip to 1080p via POST videos/upscale in the useapi.net Google Vids API. It is charged the clip's seconds a second time." parent: Google Vids API v1 nav_order: 220 permalink: /docs/api-google-vids-v1/post-google-vids-videos-upscale --- ## Upscale a video to 1080p October 7, 2026 --- 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](/docs/api-google-vids-v1/post-google-vids-videos), [POST /videos/extend](/docs/api-google-vids-v1/post-google-vids-videos-extend) or [POST /videos/edit](/docs/api-google-vids-v1/post-google-vids-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](/docs/api-google-vids-v1/post-google-vids-videos) when you know you want it. An [extend](/docs/api-google-vids-v1/post-google-vids-videos-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 `200` with 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 answers `202` with the job as it stands: fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid). Always check `status`: only `completed` has a `result`. - Async: pass `async: true` or a `replyUrl`. The POST answers `202` at once with the job in `status: "pending"`. Poll [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) or wait for the webhook. - `replyUrl` receives one `POST` of the final job record, as JSON, when the job completes or fails. - Each account runs at most `maxJobs` jobs at a time (default `3`, range `1` to `10`, set with [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts)). [GET /jobs](/docs/api-google-vids-v1/get-google-vids-jobs) shows what is running. Job records are kept for 30 days. > **https://api.useapi.net/v1/google-vids/videos/upscale** ##### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Request Body ```json { "mediaId": "user:12345-user@example.com-video:eyJ1IjoiaHR0…", "async": true, "replyUrl": "https://your-domain.com/webhook", "replyRef": "boat-1080p" } ``` - `mediaId` is **required**, the video `mediaId` of a `720p` clip, from a finished job's `result`. - `async` is optional, `true` to answer `202` at once and run the job in the background. Default: `false`. - `replyUrl` is optional, a public `http(s)` URL that receives one `POST` of 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/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) response. Maximum length: `1024` characters. - `replyRef` is optional, your own reference echoed back in the job record. Maximum length: `1024` characters. ##### Responses **200** **200 OK** — sync mode, a 3-second `720p` clip upscaled to `1080p`, charged 3 seconds. ```json { "jobid": "user:12345-user@example.com-job:3fe9115f-a433-40f5-b7c0-60ad390a124e", "type": "video", "mode": "upscale", "email": "user@example.com", "status": "completed", "created": "2026-10-07T06:27:55.554Z", "request": { "mediaId": "user:12345-user@example.com-video:eyJ1IjoiaHR0…" }, "updated": "2026-10-07T06:28:19.945Z", "completed": "2026-10-07T06:28:19.945Z", "result": { "mediaId": "user:12345-user@example.com-video: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** **202 Accepted** — the job is running: with `async: true` or `replyUrl` at once, in sync mode after about 100 seconds of waiting. Fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) (or wait for the webhook). **400** **400 Bad Request** — `mediaId` is missing or invalid, or the clip is already `1080p`. ```json { "error": "This clip is already 1080p", "code": 400 } ``` ```json { "error": "Parameter mediaId is required", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **403** **403 Forbidden** — the `mediaId` was issued to a different API token. ```json { "error": "video id does not belong to this API token", "code": 403 } ``` **404** **404 Not Found** — the account that made the clip is no longer connected. ```json { "error": "Account user@example.com (from the video id) is not configured", "code": 404 } ``` **429** **429 Too Many Requests** — the account is running `maxJobs` jobs, the month's video allowance is used up (`error.retryAt` is the reset time), or Google is limiting the account for a minute. ```json { "error": "Account user@example.com is running 3 of 3 jobs (maxJobs). Wait for one to finish, or raise maxJobs with POST /accounts", "code": 429 } ``` **504** **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** **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](/docs/start-here/setup-google-vids). ```json { "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 } ``` ```json { "error": "Account user@example.com: 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`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) and the `replyUrl` webhook return the same shape. ```typescript { // TypeScript, all fields are optional jobid: string // user:--job: 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 // 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** ``` bash curl -X POST "https://api.useapi.net/v1/google-vids/videos/upscale" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer …" \ -d '{ "mediaId": "user:12345-user@example.com-video:eyJ1IjoiaHR0…" }' ``` **JavaScript** ``` javascript 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); ``` **Python** ``` python 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()) ``` === URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-videos === Document URL: https://useapi.net/docs/api-google-vids-v1/post-google-vids-videos --- layout: default title: POST videos description: "Generate Gemini Omni 1.1 Flash video via POST videos in the useapi.net Google Vids API from text, a start image or up to 3 image and avatar references." parent: Google Vids API v1 nav_order: 200 permalink: /docs/api-google-vids-v1/post-google-vids-videos --- ## Generate a video October 7, 2026 --- Generate a video clip with Gemini Omni 1.1 Flash in [Google Vids](https://docs.google.com/videos). Clips are 3 to 10 seconds long, at `720p` or `1080p`, landscape or portrait, and come with sound. Characters speak the lines you write in the prompt, and an [avatar](/docs/api-google-vids-v1/post-google-vids-avatars) speaks them in its own voice. A clip can start from one of three inputs: | `mode` in the job | Inputs | What Google does | |---|---|---| | `text` | `prompt` only | Text to video. | | `image` | `startImage` | The clip opens on that image. | | `ingredients` | `referenceImage_1`..`referenceImage_3` and/or `avatar_1`..`avatar_3` | Up to 3 references in all, images and avatars together. The clip shows the people, objects and places they picture. | `startImage` cannot be combined with references. An image is either an `assetId` from [POST /assets](/docs/api-google-vids-v1/post-google-vids-assets) or the `mediaId` of an image made with [POST /images](/docs/api-google-vids-v1/post-google-vids-images), which the API fetches from Google and uploads for you on that image's account. The job record echoes the id you sent. Avatars come from [POST /avatars](/docs/api-google-vids-v1/post-google-vids-avatars) or [GET /avatars](/docs/api-google-vids-v1/get-google-vids-avatars). All inputs of one request must live on the same account, and the job runs there. The finished clip's `mediaId` downloads it with [GET /media/`mediaId`](/docs/api-google-vids-v1/get-google-vids-media-mediaId) and continues it with [POST /videos/extend](/docs/api-google-vids-v1/post-google-vids-videos-extend), [POST /videos/upscale](/docs/api-google-vids-v1/post-google-vids-videos-upscale) and [POST /videos/edit](/docs/api-google-vids-v1/post-google-vids-videos-edit). ### Cost A clip uses its `duration` in seconds of the account's monthly Vids video allowance, at the same rate for `720p` and `1080p`. An avatar or a reference adds nothing. A request Google refuses uses nothing. See [Plans and monthly allowances](/docs/api-google-vids-v1#plans-and-monthly-allowances). Every MP4 carries Google's visible Gemini ✦ in the bottom-right corner and an invisible SynthID watermark, see [Watermark](/docs/api-google-vids-v1#watermark). ### 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 `200` with 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 answers `202` with the job as it stands: fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid). Always check `status`: only `completed` has a `result`. - Async: pass `async: true` or a `replyUrl`. The POST answers `202` at once with the job in `status: "pending"`. Poll [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) or wait for the webhook. - `replyUrl` receives one `POST` of the final job record, as JSON, when the job completes or fails. - Each account runs at most `maxJobs` jobs at a time (default `3`, range `1` to `10`, set with [POST /accounts](/docs/api-google-vids-v1/post-google-vids-accounts)). [GET /jobs](/docs/api-google-vids-v1/get-google-vids-jobs) shows what is running. Job records are kept for 30 days. ### Prompt markers You can place `@`-markers inside `prompt` that stand for the reference parameters you send, as in [Google Flow](/docs/api-google-flow-v1/post-google-flow-videos). Markers are case-insensitive and optional. | Marker | Stands for | |---|---| | `@referenceImage_1`..`@referenceImage_3` | the matching `referenceImage_N` body parameter | | `@avatar_1`..`@avatar_3` | the matching `avatar_N` body parameter | Rules: - Each marker needs its body parameter. Otherwise the API returns `400` with `'avatar_2' was not provided in the request body`. - A reference that the prompt does not mention is still used. Google sees it ahead of the prompt text. - The same marker may appear several times in one prompt. - An avatar's name plays no part in the prompt. Two avatars may share a name and still appear in one clip, told apart by `@avatar_1` and `@avatar_2`. - Other strings, such as `@gmail.com` or `@image_1`, stay plain prompt text. Example, two avatars and a reference image: ```json { "prompt": "@avatar_1 and @avatar_2 sit at @referenceImage_1. @avatar_2 says: \"This coffee is perfect.\" @avatar_1 nods and says: \"Told you.\"", "avatar_1": "user:12345-user@example.com-avatar:eyJnIjoiaDMy…", "avatar_2": "user:12345-user@example.com-avatar:eyJnIjoiaDMy…", "referenceImage_1": "user:12345-user@example.com-asset:AVL_0qgATU91…", "duration": 6 } ``` > **https://api.useapi.net/v1/google-vids/videos** ##### Request Headers ``` yaml Authorization: Bearer {API token} Content-Type: application/json # Alternatively you can use multipart/form-data # Content-Type: multipart/form-data ``` - `API token` is **required**, see [Setup useapi.net](/docs/start-here/setup-useapi) for details. ##### Request Body ```json { "prompt": "@referenceImage_1 rides in the passenger seat of @referenceImage_2 driving along @referenceImage_3", "referenceImage_1": "user:12345-user@example.com-asset:AVL_0qjhK1Xn…", "referenceImage_2": "user:12345-user@example.com-asset:AVL_0qjOxEMQ…", "referenceImage_3": "user:12345-user@example.com-asset:AVL_0qgP9eeS…", "duration": 4, "aspectRatio": "landscape", "resolution": "720p", "async": true, "replyUrl": "https://your-domain.com/webhook", "replyRef": "car-ride-1" } ``` - `prompt` is **required**, what happens in the clip, including any spoken lines. It may carry `@`-markers, see [Prompt markers](#prompt-markers). Maximum length: `5000` characters. - `duration` is optional, the clip length in seconds. Range: `3` to `10`. Default: `8`. - `aspectRatio` is optional. Supported values: `landscape` (16:9), `portrait` (9:16). Default: `landscape`. - `resolution` is optional. Supported values: `720p` (1280×720 or 720×1280), `1080p` (1920×1080 or 1080×1920). Default: `720p`. Both cost the same. A `1080p` clip takes about twice as long to generate. - `startImage` is optional, an `assetId` from [POST /assets](/docs/api-google-vids-v1/post-google-vids-assets) or an image `mediaId` from [POST /images](/docs/api-google-vids-v1/post-google-vids-images). The clip opens on this image. Not accepted together with `referenceImage_N` or `avatar_N`. - `referenceImage_1`, `referenceImage_2`, `referenceImage_3` are optional, the people, objects or places to show, each an `assetId` from [POST /assets](/docs/api-google-vids-v1/post-google-vids-assets) or an image `mediaId` from [POST /images](/docs/api-google-vids-v1/post-google-vids-images). - `avatar_1`, `avatar_2`, `avatar_3` are optional, `avatarId`s from [POST /avatars](/docs/api-google-vids-v1/post-google-vids-avatars) or [GET /avatars](/docs/api-google-vids-v1/get-google-vids-avatars). An avatar keeps its look and speaks in its own voice. References and avatars together: at most `3`. - `email` is optional, the account to run on. When omitted, the account that holds the inputs is used, or, for a text-only clip, a healthy account with a free `maxJobs` slot and a video allowance. - `async` is optional, `true` to answer `202` at once and run the job in the background. Default: `false`. - `replyUrl` is optional, a public `http(s)` URL that receives one `POST` of 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/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) response. Maximum length: `1024` characters. - `replyRef` is optional, your own reference echoed back in the job record. Maximum length: `1024` characters. Any other parameter returns `400 Parameter not supported`. ##### Responses **200** **200 OK** — sync mode, the clip is ready. ```json { "jobid": "user:12345-user@example.com-job:f6df3fd0-3c2d-4215-8a6b-ecd150fbf21e", "type": "video", "mode": "ingredients", "email": "user@example.com", "status": "completed", "created": "2026-10-07T06:24:34.765Z", "request": { "prompt": "@referenceImage_1 rides in the passenger seat of @referenceImage_2 driving along @referenceImage_3", "referenceImage_1": "user:12345-user@example.com-asset:AVL_0qjhK1Xn…", "referenceImage_2": "user:12345-user@example.com-asset:AVL_0qjOxEMQ…", "referenceImage_3": "user:12345-user@example.com-asset:AVL_0qgP9eeS…", "duration": 4 }, "updated": "2026-10-07T06:25:01.482Z", "completed": "2026-10-07T06:25:01.482Z", "result": { "mediaId": "user:12345-user@example.com-video:eyJ1IjoiaHR0…", "width": 1280, "height": 720, "duration": 4, "resolution": "720p", "aspectRatio": "landscape", "model": "/flix/generate_videos_omni_r2v_psq/v1", "quota": { "video": { "limit": 10000, "left": 9636, "resetAt": "2026-11-01T07:00:00.000Z" } }, "elapsedMs": 26664 } } ``` **202** **202 Accepted** — the job is running: with `async: true` or `replyUrl` at once, in sync mode after about 100 seconds of waiting. Fetch the result with [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) (or wait for the webhook). ```json { "jobid": "user:12345-user@example.com-job:a553b7c4-23d7-4818-b1f2-a0528442ddb0", "type": "video", "mode": "text", "email": "user@example.com", "status": "pending", "created": "2026-10-07T06:31:32.041Z", "request": { "prompt": "A snail crawling over a mossy log, macro", "duration": 3, "replyUrl": "https://your-domain.com/webhook", "replyRef": "snail-1" }, "replyUrl": "https://your-domain.com/webhook", "replyRef": "snail-1" } ``` **400** **400 Bad Request** — a parameter is missing or invalid, inputs are combined in a way Vids does not take, or Google rejected the request. A failed sync job answers with its job record, other cases with: ```json { "error": "'referenceImage_2' was not provided in the request body", "code": 400 } ``` ```json { "error": "Use either startImage or referenceImage_1..3 / avatar_1..3, not both", "code": 400 } ``` ```json { "error": "Up to 3 references in all: referenceImage_1..3 and avatar_1..3 together", "code": 400 } ``` ```json { "error": "user:12345-another@example.com-asset:AVL_0qjhK1Xn… lives on another@example.com, not user@example.com: every input of one job must come from the same account", "code": 400 } ``` ```json { "error": "Parameter duration (11) is more than 10", "code": 400 } ``` An image `mediaId` that Google no longer serves: ```json { "error": "referenceImage_1: Google answered HTTP 404 for this image (it may have expired). Generate it again or upload it with POST /assets", "code": 400 } ``` An avatar made in the Vids web app with one of Google's older narrator voices cannot be used here. Make a new avatar with [POST /avatars](/docs/api-google-vids-v1/post-google-vids-avatars). ```json { "error": "avatar_1 uses an older Vids narrator voice that the API cannot send. Make a new avatar with POST /avatars", "code": 400 } ``` **401** **401 Unauthorized** Invalid API token. ```json { "error": "useapi.net ⁝ Unauthorized", "code": 401 } ``` **403** **403 Forbidden** — an input id was issued to a different API token, or the account's Google plan has no Vids video allowance (the failed job record, `error.code: 403`). ```json { "error": "image id does not belong to this API token", "code": 403 } ``` **404** **404 Not Found** — the account named by `email` or by an input id is not connected. ```json { "error": "Account user@example.com is not configured", "code": 404 } ``` **422** **422 Unprocessable Content** — Google refused the prompt or the inputs. Nothing was charged. Change the prompt or the inputs and try again. ```json { "jobid": "user:12345-user@example.com-job:db97658a-1240-4eee-a9dc-75f7c5123d2e", "type": "video", "mode": "text", "email": "user@example.com", "status": "failed", "created": "2026-10-07T06:36:31.478Z", "request": { "prompt": "…", "duration": 4 }, "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." } } ``` **429** **429 Too Many Requests** — the account is running `maxJobs` jobs, every account is busy, the month's allowance is used up, or Google is limiting the account for a minute. A job that ran out of allowance fails with `error.retryAt` set to the reset time. ```json { "error": "Account user@example.com is running 3 of 3 jobs (maxJobs). Wait for one to finish, or raise maxJobs with POST /accounts", "code": 429 } ``` ```json { "jobid": "user:12345-user@example.com-job:5706597d-b739-44d8-b7d4-277de6612c24", "type": "video", "mode": "text", "email": "user@example.com", "status": "failed", "created": "2026-10-07T06:32:10.218Z", "request": { "prompt": "A spinning top on a wooden table", "duration": 10 }, "updated": "2026-10-07T06:32:11.624Z", "completed": "2026-10-07T06:32:11.624Z", "error": { "code": 429, "message": "Account user@example.com has 6 of 10000 left this month in Google Vids, not enough for this request. It resets at 2026-11-01T07:00:00.000Z", "retryAt": "2026-11-01T07:00:00.000Z" } } ``` **503** **503 Service Unavailable** — Google answered with a server error, or the async job could not be queued. Retry shortly. ```json { "error": { "code": 503, "message": "Google error: Internal error encountered." } } ``` The body is the failed job record, shortened here to its `error`. **504** **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. ```json { "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" } } ``` The body is the failed job record, shortened here to its `error`. **596** **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](/docs/start-here/setup-google-vids). ```json { "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 } ``` ```json { "error": "Account user@example.com: 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 a video allowance: ```json { "error": "No healthy Google Vids account with a video allowance configured. Check GET /accounts", "code": 596 } ``` ##### Model The job record. [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid) and the `replyUrl` webhook return the same shape. In sync mode a failed job answers with the HTTP status in its `error.code`. The codes are listed on [GET /jobs/`jobid`](/docs/api-google-vids-v1/get-google-vids-jobs-jobid#model). ```typescript { // TypeScript, all fields are optional jobid: string // user:--job: 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 // 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** ``` bash curl -X POST "https://api.useapi.net/v1/google-vids/videos" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer …" \ -d '{ "prompt": "A paper boat drifting down a rain gutter, close up", "duration": 6, "resolution": "1080p", "async": true }' ``` **JavaScript** ``` javascript 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}/videos`, { method: "POST", headers, body: JSON.stringify({ prompt: "A paper boat drifting down a rain gutter, close up", duration: 6, resolution: "1080p", async: true }) }); let job = await response.json(); console.log("submitted", response.status, job); while (job.status === "pending" || job.status === "processing") { await new Promise(r => setTimeout(r, 10000)); job = await (await fetch(`${apiUrl}/jobs/${encodeURIComponent(job.jobid)}`, { headers })).json(); console.log(job.status); } if (job.status === "completed") { const video = await fetch(`${apiUrl}/media/${encodeURIComponent(job.result.mediaId)}`, { headers }); console.log("video bytes", (await video.arrayBuffer()).byteLength); } else console.log("error", job.error); ``` **Python** ``` python import time 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 paper boat drifting down a rain gutter, close up", "duration": 6, "resolution": "1080p", "async": True } response = requests.post(f"{apiUrl}/videos", headers=headers, json=data) job = response.json() print("submitted", response.status_code, job) while job.get("status") in ("pending", "processing"): time.sleep(10) job = requests.get(f"{apiUrl}/jobs/{quote(job['jobid'], safe='')}", headers=headers).json() print(job["status"]) if job.get("status") == "completed": video = requests.get(f"{apiUrl}/media/{quote(job['result']['mediaId'], safe='')}", headers=headers) with open("video.mp4", "wb") as f: f.write(video.content) else: print("error", job.get("error")) ``` === Cross-reference: General Q&A === For cross-cutting tips (rate limiting, prompt moderation, common patterns) see https://useapi.net/assets/aibot/qa.txt WARNING: Q&A items are general-purpose and may reference deprecated APIs, sunsetted services, or scenarios not applicable to the API documented above. Cross-check against this service's endpoint documentation before applying any Q&A guidance.