Upload Assets
November 17, 2025 (June 15, 2026)
Table of contents
Upload assets to Google Flow. Supports image and video uploads:
| Content-Type | File Extension | Max size |
|---|---|---|
| image/png | png | 20 MB |
| image/jpeg | jpeg | 20 MB |
| image/webp | webp | 20 MB |
| video/mp4 | mp4 | 100 MB |
POST raw content using Make.com and similar nocode tools.
https://api.useapi.net/v1/google-flow/assets/
Request Headers
Authorization: Bearer {API token}
Content-Type: select from the table above
API tokenis required, see Setup useapi.net for details.Content-Typeis required, see table above.
Path Parameters
-
emailis optional. The email address of the Google Flow account to use (URL-encoded if necessary).When only one account is configured, the API will automatically use that account.
With multiple accounts configured, omitting the email parameter triggers automatic load balancing based on image generation job statistics to select the healthiest account.
Note: The endpoint can be called as either
POST /assets(no email) orPOST /assets/:email(explicit email).
Request Body
Binary file contents (raw bytes). Set Content-Type to match the file:
image/png,image/jpeg,image/webpfor image uploadsvideo/mp4for video uploads (used asreferenceVideo_1inomni-flashV2V edit)
The image and video paths return slightly different response shapes — see the 200 response below.
Responses
-
Upload successful. The response shape differs between image and video uploads — see both below.
Image upload response
Returned when
Content-Typeisimage/png,image/jpeg, orimage/webp.{ "media": { "name": "ff9aa5cc-...redacted...", "projectId": "5c37e988-...redacted...", "workflowId": "69603881-...redacted...", "workflowStepId": "CAE", "mediaMetadata": { "createTime": "2026-02-27T16:34:25.128454Z", "requestData": { "clientPlatform": "CLIENT_PLATFORM_WEB" }, "visibility": "PRIVATE" }, "image": { "userUploadedImage": { "aspectRatio": "IMAGE_ASPECT_RATIO_UNSPECIFIED" }, "dimensions": { "width": 1024, "height": 1024 } } }, "workflow": { "name": "69603881-...redacted...", "metadata": { "displayName": "upload.webp", "createTime": "2026-02-27T16:34:25.128454Z", "primaryMediaId": "ff9aa5cc-...redacted..." }, "projectId": "5c37e988-...redacted..." }, "mediaGenerationId": { "mediaGenerationId": "user:12345-email:6a6f...-image:ff9aa5cc-...redacted..." }, "width": 1024, "height": 1024, "email": "jo***@gmail.com" }Field Description mediaFull media object from Google Flow API with upload details and dimensions media.image.dimensionsImage dimensions as reported by Google ( widthandheight)workflowWorkflow metadata including display name and project ID mediaGenerationId.mediaGenerationIdReference ID for use in subsequent API calls. Format: user:{userid}-email:{hex_encoded_email}-image:{internal_media_id}. Pass this to GET /assets/mediaGenerationIdto read back the original bytes via a signed URL.widthImage width in pixels heightImage height in pixels emailAccount email that was used for the upload (useful when email was omitted and auto-selected via load balancing) Video upload response
Returned when
Content-Typeisvideo/mp4. Use the returnedmediaGenerationIdasreferenceVideo_1on POST /videos withmodel: "omni-flash"to drive V2V edit.{ "media": { "name": "07c542b0-...redacted...", "projectId": "5c37e988-...redacted...", "workflowId": "290a1f7a-...redacted...", "workflowStepId": "CAE", "mediaMetadata": { "createTime": "2026-05-20T23:04:23.089821Z", "requestData": { "clientPlatform": "CLIENT_PLATFORM_WEB" }, "mediaStatus": { "mediaGenerationStatus": "MEDIA_GENERATION_STATUS_PENDING" }, "visibility": "PRIVATE" }, "video": { "dimensions": { "width": 1280, "height": 720, "length": "11.940s" }, "videoOffset": { "startOffset": "0s", "endOffset": "11.940s" }, "userUploadedVideo": { "encodedVideo": "" } } }, "mediaGenerationId": { "mediaGenerationId": "user:12345-email:6a6f...-video:07c542b0-...redacted..." }, "durationSeconds": 11.94, "width": 1280, "height": 720, "email": "jo***@gmail.com" }Field Description mediaFull media object from Google Flow API with upload details and dimensions (mirrors the image response shape, with a video{}sub-object instead ofimage{})media.video.dimensionsVideo dimensions as reported by Google ( width,height,length)mediaGenerationId.mediaGenerationIdReference ID for use as referenceVideo_1on POST /videos. Format:user:{userid}-email:{hex_encoded_email}-video:{internal_media_id}. Also accepted by GET /assets/mediaGenerationIdto read back the original bytes via a signed URL.durationSecondsVideo duration in seconds. Use this to pre-compute endFrameIndex_1for V2V edit:min(round(durationSeconds × 24), 240)widthVideo width in pixels heightVideo height in pixels emailAccount email that was used for the upload -
Invalid request (empty content, unsupported content type, file too large, or content policy violation).
General error:
{ "error": "File size (25165824) is over 20971520 bytes" }Content policy error:
{ "error": { "code": 400, "message": "Request contains an invalid argument.", "status": "INVALID_ARGUMENT", "details": [ { "@type": "type.googleapis.com/google.rpc.ErrorInfo", "reason": "PUBLIC_ERROR_TRUMP_FACE_DETECTED" } ] } } -
Invalid API token.
{ "error": "Unauthorized" } -
Account not found or not configured.
{ "error": "Google Flow account [email protected] not found" } -
A
429means Google is rate-limiting the account that handled your upload, for one of two reasons:Reason Meaning Cooldown PUBLIC_ERROR_USER_QUOTA_REACHEDThe account’s overall Flow quota cap ~30 min PUBLIC_ERROR_USER_REQUESTS_THROTTLEDPer-user concurrency limit (too many requests at once) ~30 min The response carries a
Retry-Afterheader and aretryAftertimestamp — honor it before retrying.If you passed
email, that account is the one being limited — wait out the cooldown or upload to a different account. If you omittedemailand have more than one account, the load balancer automatically routes around limited accounts, so you only see a429(error: "no_eligible_account") once every account is limited — see GET /jobs › Load Balancing Algorithm. -
Google’s upload service is temporarily unavailable. The error is forwarded with a
Retry-Afterheader — wait a few seconds and retry. This endpoint uses no captcha provider, so theCaptcha service failed503 does not apply here.{ "error": { "code": 503, "message": "Service temporarily unavailable.", "status": "UNAVAILABLE" } } -
596 Session Error
Google session refresh failed. The account needs to be reconfigured. Delete the account using DELETE /accounts/
emailand add it again by strictly following the procedure in Setup Google Flow.{ "error": "Failed to refresh session: 500 Internal Server Error" }
Model
Image upload response
{
media: { // Full media object from Google Flow API
name: string // Media UUID
projectId: string
workflowId: string
workflowStepId: string
mediaMetadata?: {
createTime?: string // ISO 8601 timestamp
requestData?: object
visibility?: string // "PRIVATE"
}
image?: {
userUploadedImage?: {
aspectRatio: string // "IMAGE_ASPECT_RATIO_UNSPECIFIED" | "LANDSCAPE" | "PORTRAIT"
}
dimensions?: {
width: number
height: number
}
}
}
workflow?: { // Workflow metadata
name: string // Workflow UUID
metadata?: {
displayName?: string // Original filename
createTime?: string
primaryMediaId?: string // Same as media.name
}
projectId?: string
}
mediaGenerationId: {
mediaGenerationId: string // Reference ID: user:{userid}-email:{hex_encoded_email}-image:{internal_media_id}
}
width: number // Image width in pixels
height: number // Image height in pixels
email: string // Account email used for upload
error?: string | { // Error: string (useapi.net) or object (Google API)
code: number
message: string
status: string
details: Array<{
'@type': string
reason: string
}>
}
}
Video upload response
Returned when Content-Type: video/mp4.
{
media?: { // Mirrors image response shape (with video{} instead of image{})
name: string
projectId: string
workflowId: string
workflowStepId: string
mediaMetadata: {
createTime: string
requestData: { clientPlatform: string }
mediaStatus: { mediaGenerationStatus: string }
visibility: string
}
video: {
dimensions: { width: number; height: number; length: string } // length is "11.940s"
videoOffset: { startOffset: string; endOffset: string }
userUploadedVideo: { encodedVideo: string }
}
}
mediaGenerationId: {
mediaGenerationId: string // Reference ID: user:{userid}-email:{hex_encoded_email}-video:{internal_media_id}
// — use as referenceVideo_1 on POST /videos with model='omni-flash'
}
durationSeconds?: number // Video duration in seconds
width?: number // Video width in pixels (from upload finalize response)
height?: number // Video height in pixels
email: string // Account email used for upload
error?: string | { // Error: string (useapi.net) or object (Google API)
code: number
message: string
status: string
details: Array<{
'@type': string
reason: string
}>
}
}
Examples
-
# Option 1: Without email (auto-selection/load balancing) curl -X POST \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: image/jpeg" \ --data-binary @/path/to/your/image.jpeg \ "https://api.useapi.net/v1/google-flow/assets" # Option 2: With specific email curl -X POST \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: image/jpeg" \ --data-binary @/path/to/your/image.jpeg \ "https://api.useapi.net/v1/google-flow/assets/john%40gmail.com" -
const token = 'YOUR_API_TOKEN'; // Option 1: Without email (auto-selection/load balancing) const apiUrl = 'https://api.useapi.net/v1/google-flow/assets'; // Option 2: With specific email // const email = '[email protected]'; // const apiUrl = `https://api.useapi.net/v1/google-flow/assets/${encodeURIComponent(email)}`; // Load image - Example 1: Fetch from URL const imageUrl = "https://upload.wikimedia.org/wikipedia/commons/7/7d/Mona_Lisa_color_restoration.jpg"; const responseImage = await fetch(imageUrl); const blob = await responseImage.blob(); // Load image - Example 2: From local file (Node.js) // const fsp = require('fs').promises; // const imageFileName = "./cat.png"; // const blob = new Blob([await fsp.readFile(imageFileName)]); // Load image - Example 3: From file input element // // <input id="image-file" type="file"> // const imageFile = document.getElementById('image-file'); // const blob = imageFile.files[0]; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': blob.type || 'image/jpeg' }, body: blob }); const result = await response.json(); console.log('Upload result:', result); console.log('Reference ID:', result.mediaGenerationId.mediaGenerationId); console.log('Account used:', result.email); -
import requests from urllib.parse import quote token = 'YOUR_API_TOKEN' # Option 1: Without email (auto-selection/load balancing) api_url = 'https://api.useapi.net/v1/google-flow/assets' # Option 2: With specific email # email = '[email protected]' # api_url = f'https://api.useapi.net/v1/google-flow/assets/{quote(email)}' # Load image - Example 1: Fetch from URL # image_url = "https://upload.wikimedia.org/wikipedia/commons/7/7d/Mona_Lisa_color_restoration.jpg" # response_image = requests.get(image_url) # file_content = response_image.content # Load image - Example 2: From local file # image_file_path = "./image.jpg" # with open(image_file_path, 'rb') as image_file: # file_content = image_file.read() headers = { 'Authorization': f'Bearer {token}', 'Content-Type': 'image/jpeg' } response = requests.post( api_url, headers=headers, data=file_content ) result = response.json() print('Upload result:', result) print('Reference ID:', result.get('mediaGenerationId', {}).get('mediaGenerationId')) print('Account used:', result.get('email'))