Upscale Videos

January 20, 2026 (May 25, 2026)

Table of contents

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

Upscale a previously generated video to 1080p or 4K resolution.

  • Currently, video upscaling requires a paid Google AI subscription or remaining credits.
  • Currently, 4K resolution requires a Google AI Ultra subscription. Other paid accounts can only use 1080p resolution.
  • 1080p upscaling is free. 4K upscaling currently costs 50 credits.
  • Video upscaling typically completes within 30-60 seconds, with 4K taking a few minutes.
  • Upscaling the same video twice returns a cached result (no additional credits consumed). Use the video URL from the first upscale response.

https://api.useapi.net/v1/google-flow/videos/upscale

Request Headers

Authorization: Bearer {API token}
Content-Type: application/json
# Alternatively you can use multipart/form-data
# Content-Type: multipart/form-data

Request Body

{
  "mediaGenerationId": "user:12345-email:6a6f...-video:CAMaJDMx...",
  "resolution": "1080p"
}
  • mediaGenerationId is required. The mediaGenerationId from a previously generated video via POST /videos.
  • resolution is optional. Target resolution for upscaling (default: 1080p).
    Supported values: 1080p, 4K.
  • async is optional, enables fire-and-forget mode (default: false).
    When true, returns immediately with 201 Created and job metadata. Poll GET /jobs/jobId for completion status.
  • replyUrl is optional, webhook URL for job status callbacks.
    Receives POST requests with job status updates (created, started, completed, failed). The JSON payload shape matches GET /jobs/jobId response.
  • replyRef is optional, custom reference string passed back in webhook callbacks.
  • captchaToken, captchaRetry, captchaOrder are optional, mutually exclusive captcha parameters. See Captcha Parameters for details.

Responses

  • 200 OK

    Video upscaled successfully. Both operations[] (legacy, with fifeUrl) and media[] (current, with videoUrl) are populated.

    {
      "jobId": "j1737312345678v-u12345-email:jo***@gmail.com-bot:google-flow",
      "operations": [
        {
          "operation": {
            "name": "2fefd089-...redacted..._upsampled",
            "metadata": {
              "@type": "type.googleapis.com/google.internal.labs.aisandbox.v1.Media",
              "name": "2fefd089-...redacted..._upsampled",
              "video": {
                "seed": 0,
                "model": "veo_3_1_upsampler_1080p",
                "aspectRatio": "VIDEO_ASPECT_RATIO_LANDSCAPE",
                "isLooped": false,
                "upsampleResolution": "VIDEO_UPSAMPLE_RESOLUTION_1080P",
                "fifeUrl": "https://flow-content.google/video/2fefd089-..._upsampled?Expires=...",
                "servingBaseUri": "https://flow-content.google/image/2fefd089-..._upsampled?Expires=...",
                "mediaGenerationId": "user:12345-email:6a6f...-video:2fefd089-..._upsampled",
                "mediaVisibility": "PRIVATE"
              }
            }
          },
          "sceneId": "",
          "status": "MEDIA_GENERATION_STATUS_SUCCESSFUL",
          "mediaGenerationId": "user:12345-email:6a6f...-video:2fefd089-..._upsampled"
        }
      ],
      "media": [
        {
          "name": "2fefd089-...redacted..._upsampled",
          "projectId": "9f63078c-...redacted...",
          "workflowId": "66612805-...redacted...",
          "workflowStepId": "CAI",
          "mediaMetadata": {
            "createTime": "2026-05-20T23:31:41.145235Z",
            "requestData": { "videoGenerationRequestData": { "...": "..." }, "clientPlatform": "CLIENT_PLATFORM_WEB" },
            "mediaStatus": { "mediaGenerationStatus": "MEDIA_GENERATION_STATUS_SUCCESSFUL" },
            "visibility": "PRIVATE"
          },
          "video": {
            "generatedVideo": {
              "seed": 0,
              "model": "veo_3_1_upsampler_1080p",
              "baseImageMediaGenerationId": "",
              "isLooped": false,
              "aspectRatio": "VIDEO_ASPECT_RATIO_LANDSCAPE",
              "upsampleMetadata": { "videoUpsampleResolution": "VIDEO_UPSAMPLE_RESOLUTION_1080P" }
            },
            "dimensions": { "length": "0s" },
            "operation": { "name": "2fefd089-..._upsampled" }
          },
          "mediaGenerationId": "user:12345-email:6a6f...-video:2fefd089-..._upsampled",
          "videoUrl": "https://flow-content.google/video/2fefd089-..._upsampled?Expires=...",
          "thumbnailUrl": "https://flow-content.google/image/2fefd089-..._upsampled?Expires=..."
        }
      ],
      "remainingCredits": 18760,
      "captcha": {
        "service": "AntiCaptcha",
        "taskId": "abc123...",
        "durationMs": 3500,
        "attempts": [
          {
            "service": "AntiCaptcha",
            "taskId": "abc123...",
            "durationMs": 3500,
            "success": true
          }
        ]
      }
    }
    
  • 201 Created

    Job created in async mode (async: true). Video upscaling is processing in the background.

    Use GET /jobs/jobId to poll for completion status.

    {
      "jobid": "j1737312345678v-u12345-email:jo***@gmail.com-bot:google-flow",
      "type": "video",
      "status": "created",
      "created": "2026-01-19T12:34:56.789Z",
      "request": {
        "async": true,
        "mediaGenerationId": "user:12345-email:6a6f...-video:CAMaJDMx...",
        "resolution": "1080p"
      },
      "response": {
        "captcha": {
          "service": "AntiCaptcha",
          "taskId": "14af1dbb-885c-4e25-8121-7a79489dfd0e",
          "durationMs": 5357
        }
      }
    }
    
  • 400 Bad Request

    Invalid request.

    {
      "error": "Error message"
    }
    
  • 401 Unauthorized

    Invalid API token.

    {
      "error": "Unauthorized"
    }
    
  • 403 Forbidden

    Request rejected by Google — the reCAPTCHA token was outright rejected (not just scored low). After internal retries with fresh tokens, the worker returns this. The top-level error field carries a captcha_quality: prefix so tooling can detect this failure class. Increase captchaRetry (default 3) in the request body to 5 or higher, and configure additional providers via POST /accounts/captcha-providers so captchaOrder can cycle across them. If issues persist, contact your reCAPTCHA provider(s) support.

  • 404 Not Found

    Account not found or video not found.

    {
      "error": "Google Flow account [email protected] not found"
    }
    
  • 408 Request Timeout

    Video upscaling polling timeout (after 10 minutes).

    {
      "error": "Polling timeout"
    }
    
  • 429 Too Many Requests

    Google returns several RESOURCE_EXHAUSTED 429 variants. Check the reason field and respond accordingly:

    Reason Meaning Scope What to do Cooldown
    PUBLIC_ERROR_
    USER_REQUESTS_THROTTLED
    Per-user concurrency limit (the token was fine) All models on the account Run fewer parallel requests, retry later ~30 min
    PUBLIC_ERROR_
    USER_QUOTA_REACHED
    Account’s overall Flow quota cap All models on the account Add accounts, or omit email to load-balance ~30 min
    PUBLIC_ERROR_
    PER_MODEL_DAILY_QUOTA_REACHED
    Per-model daily quota Only that model, on that account Switch model, or wait Next UTC midnight
    PUBLIC_ERROR_
    UNUSUAL_ACTIVITY_TOO_MUCH_TRAFFIC
    Captcha-provider issue — low reCAPTCHA score (worker already auto-retried) Per request Add more captcha providers + captchaOrder, or raise captchaRetry 60s

    Every 429 returns the cooldown two ways — an HTTP Retry-After: <seconds> header and a body retryAfter: <ISO timestamp> field. Honor it before retrying.

    When email is omitted, the first three reasons quarantine the account and the load balancer routes around it. If every account is quarantined for the model you get 429 with error: "no_eligible_account". Routing details: GET /jobs › Load Balancing Algorithm.

    Captcha-quality failures prefix the top-level error with captcha_quality: (e.g. "captcha_quality: PUBLIC_ERROR_UNUSUAL_ACTIVITY_TOO_MUCH_TRAFFIC after 3 attempts") so you can detect them without parsing the nested body.

  • 503 Service Unavailable

    503 has two distinct causes — check the response body to tell them apart.

    A transient Google-side outage. Wait 5-10 seconds and retry.

    {
      "error": {
        "code": 503,
        "message": "Service temporarily unavailable.",
        "status": "UNAVAILABLE"
      }
    }
    

    A captcha-provider failure — the top-level error is prefixed Captcha service failed:. The problem is your captcha provider (check its API key and balance), not Google. Don’t retry until the provider is back.

    {
      "error": "Captcha service failed: ERROR_ZERO_BALANCE",
      "code": 503
    }
    

Model

  • Video upscaling completed. Returns upscaled video data with signed URLs. Re-upscaling the same video returns rawBytes (base64 video data) instead of URLs.

    {
      jobId: string                              // Job identifier
      operations: Array<{                        // Legacy shape, still populated for upscale (with fifeUrl)
        operation: {
          name: string
          metadata: {
            '@type': string
            name: string
            video: {
              seed: number
              model: string                      // veo_3_1_upsampler_1080p | veo_3_1_upsampler_4k
              aspectRatio: string                // VIDEO_ASPECT_RATIO_LANDSCAPE | PORTRAIT
              isLooped: boolean
              upsampleResolution?: string        // 'VIDEO_UPSAMPLE_RESOLUTION_1080P' | 'VIDEO_UPSAMPLE_RESOLUTION_4K'
              fifeUrl: string                    // Signed video URL (MP4)
              servingBaseUri: string             // Signed thumbnail URL (JPEG)
              mediaGenerationId: string          // Encoded reference ID for the upscaled video
              mediaVisibility: string
            }
          }
        }
        sceneId: string
        status: string                           // MEDIA_GENERATION_STATUS_SUCCESSFUL | FAILED
        mediaGenerationId: string
      }>
      media: Array<{                             // Current shape — same fields as POST /videos
        name: string                             // Media identifier (raw UUID)
        projectId: string
        workflowId?: string
        workflowStepId?: string                  // e.g. "CAI" for upscale
        mediaMetadata: {
          createTime?: string                    // ISO 8601 timestamp
          requestData?: object                   // Full Google Flow request payload
          mediaStatus: {
            mediaGenerationStatus: string        // MEDIA_GENERATION_STATUS_SUCCESSFUL | FAILED
            error?: { code: number; message: string }
          }
          visibility?: string
        }
        video?: {
          generatedVideo: {
            seed: number
            model: string                        // veo_3_1_upsampler_1080p | veo_3_1_upsampler_4k
            baseImageMediaGenerationId?: string  // Source video media ID
            isLooped: boolean
            aspectRatio: string                  // VIDEO_ASPECT_RATIO_LANDSCAPE | PORTRAIT
            upsampleMetadata?: { videoUpsampleResolution: string }  // VIDEO_UPSAMPLE_RESOLUTION_1080P | _4K
          }
          dimensions?: { length?: string }       // Often "0s" for upscale (not meaningful)
          operation: { name: string }
        }
        mediaGenerationId: string                // Encoded reference ID for use in subsequent API calls
        videoUrl?: string                        // Signed video download URL (MP4)
        thumbnailUrl?: string                    // Signed thumbnail download URL (JPEG)
      }>
      remainingCredits?: number
      captcha?: {                                // Captcha metadata
        service: string                          // "CapSolver" | "AntiCaptcha" | "YesCaptcha" | "CapMonster" | "SolveCaptcha" | "2Captcha" | "EzCaptcha" | "UserProvided"
        taskId?: string
        durationMs: number
        attempts: Array<{
          service: string
          taskId?: string
          durationMs: number
          success: boolean
          error?: string
        }>
      }
    }
    
  • Job created and processing in background. Structure matches GET /jobs/jobId response.

    {
      jobid: string                              // Job identifier
      type: 'video'                              // Job type
      status: 'created'                          // Job status
      created: string                            // ISO 8601 timestamp
      request: {
        async: true
        mediaGenerationId: string                // Original video reference
        resolution?: string                      // "1080p" | "4K"
        replyUrl?: string
        replyRef?: string
      }
      response: {
        captcha?: {                              // Present when captcha was used
          service: string                        // Provider or "UserProvided"
          taskId?: string                        // Absent for UserProvided
          durationMs: number
        }
      }
    }
    
  • Error response structure.

    {
      jobId?: string                             // Present for job-related errors
      error: string                              // Error summary message
      code?: number                              // HTTP status code
      response?: {                               // API response with error details
        error?: {
          code: number
          message: string
          status: string
          details?: Array<{
            '@type': string
            reason: string
          }>
        }
      }
    }
    

Examples

  • # First generate a video
    curl -X POST \
         -H "Authorization: Bearer YOUR_API_TOKEN" \
         -H "Content-Type: application/json" \
         -d '{"prompt": "A serene mountain landscape at sunset"}' \
         "https://api.useapi.net/v1/google-flow/videos" > generate.json
    
    # Extract mediaGenerationId from the response
    MEDIA_ID=$(jq -r '.media[0].mediaGenerationId' generate.json)
    
    # Upscale the video to 1080p
    curl -X POST \
         -H "Authorization: Bearer YOUR_API_TOKEN" \
         -H "Content-Type: application/json" \
         -d "{\"mediaGenerationId\": \"$MEDIA_ID\", \"resolution\": \"1080p\"}" \
         "https://api.useapi.net/v1/google-flow/videos/upscale" > upscale.json
    
    # Extract upscaled video URL and download
    VIDEO_URL=$(jq -r '.media[0].videoUrl' upscale.json)
    curl "$VIDEO_URL" --output upscaled_video.mp4
    
  • const token = 'YOUR_API_TOKEN';
    
    // First generate a video
    const generateResponse = await fetch('https://api.useapi.net/v1/google-flow/videos', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        prompt: 'A serene mountain landscape at sunset'
      })
    });
    
    const generated = await generateResponse.json();
    // Prefer media[] over deprecated operations[]
    const mediaGenerationId = generated.media[0].mediaGenerationId;
    
    // Upscale the video
    const upscaleResponse = await fetch('https://api.useapi.net/v1/google-flow/videos/upscale', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        mediaGenerationId,
        resolution: '1080p'
      })
    });
    
    const upscaled = await upscaleResponse.json();
    // Prefer media[] over deprecated operations[]
    const videoUrl = upscaled.media[0].videoUrl;
    
    // Download upscaled video (Node.js)
    const videoResponse = await fetch(videoUrl);
    const videoBuffer = await videoResponse.arrayBuffer();
    require('fs').writeFileSync('upscaled_video.mp4', Buffer.from(videoBuffer));
    console.log('Upscaled video saved!');
    
  • import requests
    
    token = 'YOUR_API_TOKEN'
    headers = {
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    }
    
    # First generate a video
    generate_response = requests.post(
        'https://api.useapi.net/v1/google-flow/videos',
        headers=headers,
        json={'prompt': 'A serene mountain landscape at sunset'}
    )
    generated = generate_response.json()
    # Prefer media[] over deprecated operations[]
    media_generation_id = generated['media'][0]['mediaGenerationId']
    
    # Upscale the video
    upscale_response = requests.post(
        'https://api.useapi.net/v1/google-flow/videos/upscale',
        headers=headers,
        json={
            'mediaGenerationId': media_generation_id,
            'resolution': '1080p'
        }
    )
    upscaled = upscale_response.json()
    # Prefer media[] over deprecated operations[]
    video_url = upscaled['media'][0]['videoUrl']
    
    # Download upscaled video
    video_response = requests.get(video_url)
    with open('upscaled_video.mp4', 'wb') as f:
        f.write(video_response.content)
    print('Upscaled video saved!')
    

Try It