Concatenate Videos

January 29, 2026 (September 2, 2026)

Table of contents

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

Concatenate multiple previously generated videos into a single video. This is a synchronous operation that returns base64-encoded video data.

  • Combines 2-10 videos into a single video file.
  • Each clip contributes its full recorded length: 8 seconds for a standard Veo clip, 4 or 6 seconds for the short Veo durations, and up to 10 seconds for an Omni 1.1 Flash edit. Earlier versions cut every clip at 8 seconds, which silently dropped the last 2 seconds of each 10-second Omni clip.
  • All videos must have the same aspect ratio (all landscape or all portrait).
  • No captcha required - this endpoint doesn’t require reCAPTCHA solving.
  • Optional trimming allows removing frames from the start/end of each video for smoother transitions.
  • Returns large base64-encoded video data (~7MB per input video).
  • Concatenation typically completes within 15-20 seconds.

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

Request Headers

Authorization: Bearer {API token}
Content-Type: application/json

Request Body

{
  "media": [
    { "mediaGenerationId": "user:12345-email:6a6f...-video:CAMaJDMx..." },
    { "mediaGenerationId": "user:12345-email:6a6f...-video:CAMaJDMy...", "trimStart": 0.5 },
    { "mediaGenerationId": "user:12345-email:6a6f...-video:CAMaJDMz...", "trimEnd": 1 }
  ]
}
  • media is required. Array of 2-10 video references to concatenate. Each item contains:
    • mediaGenerationId is required. The mediaGenerationId from a previously generated or extended video.
    • trimStart is optional. Seconds to trim from the start of this video (0-10, default: 0). When concatenating extended videos, use trimStart: 1 to remove the ~1 second overlap with the source video.
    • trimEnd is optional. Seconds to trim from the end of this video (0-10, default: 0).
    • trimStart plus trimEnd must be less than the clip’s own length, otherwise the request returns 400.
    • Clips from POST /videos/upscale can be joined too, and the output keeps their resolution. Google records no length on an upscaled clip, so its length is taken from the clip it was upscaled from.

Notes:

  • All videos must belong to the same Google Flow account (same email).
  • All videos must have the same aspect ratio.
  • Videos are concatenated in the order provided.
  • Omni 1.1 Flash edits chained from one source all re-render the same time window, so joining them repeats the source motion with each edit applied. See the video reference notes on POST /videos.

Responses

  • 200 OK

    Videos concatenated successfully. Returns job ID and base64-encoded video data.

    {
      "jobId": "j1737312345678v-u12345-email:jo***@gmail.com-bot:google-flow",
      "status": "MEDIA_GENERATION_STATUS_SUCCESSFUL",
      "inputsCount": 3,
      "encodedVideo": "AAAAIGZ0eXBpc29t...~21MB base64..."
    }
    
  • 400 Bad Request

    Invalid request.

    {
      "error": "Error message",
      "code": 400
    }
    
  • 401 Unauthorized

    Invalid API token.

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

    Account not found or video not found.

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

    Concatenation polling timeout (after 3 minutes).

    {
      "error": "Polling timeout"
    }
    

Model

{
  jobId: string                    // Job identifier
  status: string                   // MEDIA_GENERATION_STATUS_SUCCESSFUL | FAILED
  inputsCount: number              // Number of input videos
  encodedVideo: string             // Base64-encoded MP4 (~7MB per input, decode and save as .mp4)
  error?: string | {               // Error: string (useapi.net) or object (Google API)
    code: number
    message: string
    status: string
    details?: Array<{
      '@type': string
      reason: string
    }>
  }
}

Examples

  • # Generate first video
    curl -X POST \
         -H "Authorization: Bearer YOUR_API_TOKEN" \
         -H "Content-Type: application/json" \
         -d '{"prompt": "A serene mountain landscape at sunrise"}' \
         "https://api.useapi.net/v1/google-flow/videos" > video1.json
    
    # Generate second video (or extend the first)
    curl -X POST \
         -H "Authorization: Bearer YOUR_API_TOKEN" \
         -H "Content-Type: application/json" \
         -d '{"prompt": "The sun rises higher, birds fly across the sky"}' \
         "https://api.useapi.net/v1/google-flow/videos" > video2.json
    
    # Extract mediaGenerationIds
    VIDEO1_ID=$(jq -r '.media[0].mediaGenerationId' video1.json)
    VIDEO2_ID=$(jq -r '.media[0].mediaGenerationId' video2.json)
    
    # Concatenate videos
    curl -X POST \
         -H "Authorization: Bearer YOUR_API_TOKEN" \
         -H "Content-Type: application/json" \
         -d "{\"media\": [{\"mediaGenerationId\": \"$VIDEO1_ID\"}, {\"mediaGenerationId\": \"$VIDEO2_ID\", \"trimStart\": 0.5}]}" \
         "https://api.useapi.net/v1/google-flow/videos/concatenate" > concat.json
    
    # Decode base64 and save as MP4
    jq -r '.encodedVideo' concat.json | base64 -d > concatenated_video.mp4
    
  • const token = 'YOUR_API_TOKEN';
    
    // Assume you have two video mediaGenerationIds
    const videoId1 = 'user:12345-email:6a6f...-video:CAMaJDMx...';
    const videoId2 = 'user:12345-email:6a6f...-video:CAMaJDMy...';
    
    // Concatenate videos
    const concatResponse = await fetch('https://api.useapi.net/v1/google-flow/videos/concatenate', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        media: [
          { mediaGenerationId: videoId1 },
          { mediaGenerationId: videoId2, trimStart: 0.5 }  // Trim 0.5s from start for smooth transition
        ]
      })
    });
    
    const result = await concatResponse.json();
    
    // Decode base64 and save (Node.js)
    const buffer = Buffer.from(result.encodedVideo, 'base64');
    require('fs').writeFileSync('concatenated_video.mp4', buffer);
    console.log('Concatenated video saved!');
    
    // Or use in browser as data URL for preview
    const dataUrl = `data:video/mp4;base64,${result.encodedVideo}`;
    document.getElementById('video-player').src = dataUrl;
    
  • import requests
    import base64
    
    token = 'YOUR_API_TOKEN'
    headers = {
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    }
    
    # Assume you have two video mediaGenerationIds
    video_id_1 = 'user:12345-email:6a6f...-video:CAMaJDMx...'
    video_id_2 = 'user:12345-email:6a6f...-video:CAMaJDMy...'
    
    # Concatenate videos
    concat_response = requests.post(
        'https://api.useapi.net/v1/google-flow/videos/concatenate',
        headers=headers,
        json={
            'media': [
                {'mediaGenerationId': video_id_1},
                {'mediaGenerationId': video_id_2, 'trimStart': 0.5}  # Trim 0.5s for smooth transition
            ]
        }
    )
    result = concat_response.json()
    
    # Decode base64 and save
    video_data = base64.b64decode(result['encodedVideo'])
    with open('concatenated_video.mp4', 'wb') as f:
        f.write(video_data)
    print(f'Concatenated video saved! ({len(video_data)} bytes)')
    

Try It