Upload Assets

November 17, 2025 (May 25, 2026)

Table of contents

  1. Request Headers
  2. Path Parameters
  3. Request Body
  4. Responses
  5. Model
    1. Image upload response
    2. Video upload response
  6. Examples
  7. Try It

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/email

Request Headers

Authorization: Bearer {API token}
Content-Type: select from the table above
  • API token is required, see Setup useapi.net for details.
  • Content-Type is required, see table above.

Path Parameters

  • email is 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) or POST /assets/:email (explicit email).

Request Body

Binary file contents (raw bytes). Set Content-Type to match the file:

  • image/png, image/jpeg, image/webp for image uploads
  • video/mp4 for video uploads (used as referenceVideo_1 in omni-flash V2V edit)

The image and video paths return slightly different response shapes — see the 200 response below.

Responses

  • 200 OK

    Upload successful. The response shape differs between image and video uploads — see both below.

    Image upload response

    Returned when Content-Type is image/png, image/jpeg, or image/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
    media Full media object from Google Flow API with upload details and dimensions
    media.image.dimensions Image dimensions as reported by Google (width and height)
    workflow Workflow metadata including display name and project ID
    mediaGenerationId.mediaGenerationId Reference ID for use in subsequent API calls. Format: user:{userid}-email:{hex_encoded_email}-image:{internal_media_id}
    width Image width in pixels
    height Image height in pixels
    email Account email that was used for the upload (useful when email was omitted and auto-selected via load balancing)

    Video upload response

    Returned when Content-Type is video/mp4. Use the returned mediaGenerationId as referenceVideo_1 on POST /videos with model: "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
    media Full media object from Google Flow API with upload details and dimensions (mirrors the image response shape, with a video{} sub-object instead of image{})
    media.video.dimensions Video dimensions as reported by Google (width, height, length)
    mediaGenerationId.mediaGenerationId Reference ID for use as referenceVideo_1 on POST /videos. Format: user:{userid}-email:{hex_encoded_email}-video:{internal_media_id}
    durationSeconds Video duration in seconds. Use this to pre-compute endFrameIndex_1 for V2V edit: min(round(durationSeconds × 24), 240)
    width Video width in pixels
    height Video height in pixels
    email Account email that was used for the upload
  • 400 Bad Request

    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"
          }
        ]
      }
    }
    
  • 401 Unauthorized

    Invalid API token.

    {
      "error": "Unauthorized"
    }
    
  • 404 Not Found

    Account not found or not configured.

    {
      "error": "Google Flow account [email protected] not found"
    }
    
  • 429 Too Many Requests

    Rate limit or quota exhausted (concurrency limit or account quota reached).

    When the reason is PUBLIC_ERROR_USER_REQUESTS_THROTTLED the response includes a Retry-After: 1800 header (30 minutes — matches the internal quarantine TTL on the throttled account). During that window the account is removed from load-balanced selection, so callers that didn’t pin email will auto-route to a different account in their pool.

    {
      "error": {
        "code": 429,
        "message": "Resource has been exhausted (e.g. check quota).",
        "status": "RESOURCE_EXHAUSTED",
        "details": [
          {
            "@type": "type.googleapis.com/google.rpc.ErrorInfo",
            "reason": "PUBLIC_ERROR_USER_REQUESTS_THROTTLED"
          }
        ]
      }
    }
    
  • 596 Session Error

    Google session refresh failed. The account needs to be reconfigured. Delete the account using DELETE /accounts/email and 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'))
    

Try It