Generate Images

November 17, 2025 (June 15, 2026)

Table of contents

  1. Model Capabilities
  2. Content Moderation
  3. Request Headers
  4. Request Body
    1. Inline @-mention markers (optional)
  5. Responses
  6. Model
  7. Examples
  8. Try It

Generate images using AI models Imagen 4, Nano Banana / Gemini 2.5 Flash Image, Nano Banana 2 / Gemini 3.1 Flash Image, and Nano Banana Pro / Gemini 3 Pro Image from text prompts with optional reference images. Use any Google AI subscription or even free account for image generations.

This endpoint features dynamic concurrency management, allowing anywhere from 3 to 20 parallel generations depending on real-time capacity. Image generation typically completes within 10-20 seconds.

Model Capabilities

Parameter Imagen 4
imagen-4 (default)
Nano Banana 2
nano-banana-2
Nano Banana Pro
nano-banana-pro
T2I (text-to-image)
I2I (reference images) ✓ (max 3) ✓ (max 10) ✓ (max 10)
Aspect ratios 16:9, 4:3, 1:1, 3:4, 9:16 16:9, 4:3, 1:1, 3:4, 9:16, auto 16:9, 4:3, 1:1, 3:4, 9:16, auto
Default aspect ratio 16:9 16:9 (T2I) / auto (I2I) 16:9 (T2I) / auto (I2I)
count ✓ (1-4) ✓ (1-4) ✓ (1-4)
seed
Subscription all all all

auto is only valid in image-to-image mode (at least one reference_* provided) — the backend derives the aspect ratio from the first reference image.

Legacy alias nano-banana is still accepted and maps to nano-banana-2.

Content Moderation

If your generation is moderated, retrying with the same prompt often succeeds on subsequent attempts — moderation decisions can vary between requests. Alternatively, switching between imagen-4, nano-banana-2, and nano-banana-pro models may help, as each has different content-moderation behavior.

https://api.useapi.net/v1/google-flow/images

Request Headers

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

Request Body

{
  "prompt": "A serene mountain landscape at sunset with vibrant colors",
  "model": "imagen-4",
  "aspectRatio": "16:9",
  "count": 4,
  "seed": 123456
}
  • email is optional. The email address of the Google Flow account to use.

    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.

    If reference images (reference_1 to _10) are provided, the email parameter can be omitted—the API will automatically use the same account where the images were uploaded.

  • prompt is required, text description for image generation.
  • model is optional, the AI model to use for image generation (default: imagen-4).
    Supported values: imagen-4, nano-banana-2, nano-banana-pro. Legacy alias nano-banana is still accepted and maps to nano-banana-2.
  • aspectRatio is optional, output image aspect ratio. Supported values: 16:9, 4:3, 1:1, 3:4, 9:16, auto. Legacy aliases landscape (→ 16:9) and portrait (→ 9:16) are still accepted. auto is only valid with nano-banana-2 or nano-banana-pro when at least one reference_* is provided — the backend derives the aspect ratio from the first reference image. Default:
    • text-to-image (no references): 16:9
    • imagen-4 image-to-image: 16:9
    • nano-banana-2 / nano-banana-pro image-to-image: auto
  • count is optional, number of image variations to generate (1-4, default: 4).
  • seed is optional, random seed for reproducible results (integer ≥ 0).
  • reference_1 to reference_10 are optional, use mediaGenerationId from POST /assets/email for reference images. imagen-4 supports max 3 references, nano-banana-2 and nano-banana-pro support up to 10.
  • character_1 to character_7 are optional, character reference-ids from POST /characters. Characters mix freely with reference_* — they share the same per-model image-ref budget on Google’s side (per-character image counts roll into the total). Imagen models that don’t accept reference images also don’t accept characters.
  • replyUrl is optional, webhook URL for job status callbacks. Receives POST requests with job status updates (created, completed, failed). The JSON payload shape matches GET /jobs/jobId response. Callbacks timeout after 5 seconds.
  • replyRef is optional, custom reference string passed back in webhook callbacks. Useful for tracking jobs on your end.
  • captchaToken, captchaRetry, captchaOrder are optional, mutually exclusive captcha parameters. See Captcha Parameters for details.

Auto-detection: If model is not specified: with references selects nano-banana-2, without references defaults to imagen-4.

Inline @-mention markers (optional)

You can place @-markers inside prompt that resolve to the body parameters you supply. Markers are case-insensitive and opt-in — a prompt with no markers behaves exactly like before.

Supported markers:

Marker Resolves to
@character_1..7 matching character_N body param
@reference_1..10 matching reference_N body param

Rules:

  • Each marker MUST have a matching body slot supplied. Otherwise the API returns 400 with 'character_N' was not provided in the request body.
  • A slot referenced inline still goes into the upstream reference array — markers are positional/grounding info, not a replacement for the body params.
  • Same slot may be inlined multiple times; the upstream reference array de-duplicates by id.
  • Body params supplied but NOT inlined still flow to the upstream reference array (unchanged behavior).
  • Unknown strings like @gmail.com or @anyword_1 (no _<digit> after a recognized slot name) pass through as literal prompt text.

Example:

{
  "model": "nano-banana-pro",
  "prompt": "@character_1 standing next to @reference_1, golden hour light",
  "character_1": "user:123-email:...-character:...-imgs:1",
  "reference_1": "user:123-email:...-image:..."
}

Responses

  • 200 OK

    Images generated successfully. Returns job ID and media array with generated image data.

    {
      "jobId": "j1731859345678i-u12345-email:jo***@gmail.com-bot:google-flow",
      "media": [
        {
          "name": "…redacted…",
          "workflowId": "…redacted…",
          "image": {
            "generatedImage": {
              "seed": 123456,
              "mediaGenerationId": "user:12345…redacted…",
              "mediaVisibility": "PRIVATE",
              "prompt": "A serene mountain landscape at sunset with vibrant colors",
              "modelNameType": "IMAGEN_3_5",
              "workflowId": "…redacted…",
              "fifeUrl": "https://storage.googleapis.com/…redacted…",
              "aspectRatio": "IMAGE_ASPECT_RATIO_LANDSCAPE",
              "requestData": {
                "promptInputs": [
                  {
                    "textInput": "A serene mountain landscape at sunset with vibrant colors"
                  }
                ],
                "imageGenerationRequestData": {
                  "imageGenerationImageInputs": []
                }
              }
            }
          }
        }
      ],
      "captcha": {
        "service": "AntiCaptcha",
        "taskId": "abc123...",
        "durationMs": 3500,
        "attempts": [
          {
            "service": "AntiCaptcha",
            "taskId": "abc123...",
            "durationMs": 3500,
            "success": true
          }
        ]
      }
    }
    
  • 400 Bad Request

    Invalid request (validation error, reference count exceeded, email mismatch, or content policy violation).

    General error:

    {
      "error": "Invalid request parameters"
    }
    

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

    Invalid API token.

    {
      "error": "Unauthorized"
    }
    
  • 402 Payment Required

    Subscription expired or insufficient credits.

    {
      "error": "Account has no subscription or subscription expired"
    }
    
  • 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 not configured.

    {
      "error": "Google Flow account [email protected] not found"
    }
    
  • 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.

  • 500 Internal Server Error

    One or more generated images were moderated by Google’s content policy. Try one of the following:

    • Switch to imagen-4 model (often successfully processes prompts rejected by nano-banana)
    • Modify your prompt or remove/change reference images
    • Retry the same request (moderation decisions can vary between attempts)
    {
      "error": {
        "code": 500,
        "message": "Internal error encountered.",
        "status": "INTERNAL"
      }
    }
    
  • 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
    }
    
  • 596 Session Error

    Google session refresh failed. The account cookies needs to be updated following the instructions in Setup Google Flow.

    {
      "error": "Failed to refresh session."
    }
    

Model

  • jobId - Unique job identifier (for use with GET /jobs/jobId)
  • media - Array of generated images (1-4 images based on count)
  • media[].image.generatedImage - Generated image data object
  • generatedImage.fifeUrl - Direct signed URL to access the generated image (valid for limited time)
  • generatedImage.seed - Seed used for this generation (for reproducibility)
  • generatedImage.mediaGenerationId - mediaGenerationId for use in subsequent API calls
  • generatedImage.prompt - The prompt used for generation
  • generatedImage.modelNameType - Model variant used (IMAGEN_3_5, R2I, GEM_PIX, GEM_PIX_2, NARWHAL)
  • generatedImage.aspectRatio - Generated image aspect ratio (IMAGE_ASPECT_RATIO_LANDSCAPE, IMAGE_ASPECT_RATIO_LANDSCAPE_FOUR_THREE, IMAGE_ASPECT_RATIO_SQUARE, IMAGE_ASPECT_RATIO_PORTRAIT_THREE_FOUR, or IMAGE_ASPECT_RATIO_PORTRAIT)
  • generatedImage.mediaVisibility - Visibility setting (always “PRIVATE”)
  • generatedImage.workflowId - Unique workflow identifier
  • generatedImage.requestData - Request data used for this generation including prompt inputs and reference images
  • media[].name - Internal identifier for the media item
  • media[].workflowId - Unique workflow identifier for this generation
  • captcha - Captcha metadata for debugging/research
  • captcha.service - Provider that returned the successful token
  • captcha.taskId - Task ID from the captcha service
  • captcha.durationMs - Total time for all captcha attempts
  • captcha.attempts - Array of all captcha attempts (including failures)
{
  jobId: string                         // Job identifier
  media: Array<{
    name: string                    // Internal media identifier
    workflowId: string              // Unique workflow ID
    image: {
      generatedImage: {
        seed: number
        mediaGenerationId: string   // Format: user:{userid}-email:{hex}-image:{id}
        mediaVisibility: string     // "PRIVATE"
        prompt: string
        modelNameType: string       // "IMAGEN_3_5" | "R2I" | "GEM_PIX" | "GEM_PIX_2" | "NARWHAL"
        workflowId: string
        fifeUrl: string             // Direct signed URL to generated image
        aspectRatio: string         // "IMAGE_ASPECT_RATIO_LANDSCAPE" | "IMAGE_ASPECT_RATIO_LANDSCAPE_FOUR_THREE" | "IMAGE_ASPECT_RATIO_SQUARE" | "IMAGE_ASPECT_RATIO_PORTRAIT_THREE_FOUR" | "IMAGE_ASPECT_RATIO_PORTRAIT"
        requestData: {
          promptInputs: Array<{
            textInput: string
          }>
          imageGenerationRequestData: {
            imageGenerationImageInputs: Array<{
              mediaGenerationId: string
              imageInputType: string  // "IMAGE_INPUT_TYPE_REFERENCE"
            }>
          }
        }
      }
    }
  }>
  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
    }>
  }
  error?: string | {                // Error: string (useapi.net) or object (Google API)
    code: number
    message: string
    status: string
    details: Array<{
      '@type': string
      reason: string
      metadata?: {
          canUpgradeForQuota: boolean
        }
    }>
  }
  // The following siblings appear only on the load-balancer empty-set 429,
  // i.e. when error === "no_eligible_account" (see 429 response tab).
  message?: string                  // Customer-facing explanation
  retryAfter?: string               // ISO-8601 timestamp of earliest retry
  skipReasons?: Array<{             // Per-account filter rationale
    email: string
    reason: string                  // Google 429 reason that triggered the quarantine
    model: string                   // Quarantined model, or "*" for account-wide
  }>
}

Examples

  • curl -X POST \
         -H "Authorization: Bearer YOUR_API_TOKEN" \
         -H "Content-Type: application/json" \
         -d '{
           "prompt": "A serene mountain landscape at sunset with vibrant colors",
           "model": "imagen-4",
           "aspectRatio": "16:9",
           "count": 4,
           "seed": 123456
         }' \
         "https://api.useapi.net/v1/google-flow/images" > response.json
    
    # Download images using fifeUrl
    curl -o image_1.jpg "$(cat response.json | jq -r '.media[0].image.generatedImage.fifeUrl')"
    curl -o image_2.jpg "$(cat response.json | jq -r '.media[1].image.generatedImage.fifeUrl')"
    # Continue for remaining images...
    
  • const token = 'YOUR_API_TOKEN';
    const apiUrl = 'https://api.useapi.net/v1/google-flow/images';
    
    const response = await fetch(apiUrl, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        prompt: 'A serene mountain landscape at sunset with vibrant colors',
        model: 'imagen-4',
        aspectRatio: '16:9',
        count: 4,
        seed: 123456
      })
    });
    
    const result = await response.json();
    console.log('Generated images:', result.media.length);
    
    // Download and save images
    for (const [index, item] of result.media.entries()) {
      const img = item.image.generatedImage;
      console.log(`Image ${index + 1} seed:`, img.seed);
      console.log(`mediaGenerationId:`, img.mediaGenerationId);
    
      // Download image from fifeUrl
      const imageResponse = await fetch(img.fifeUrl);
      const imageBlob = await imageResponse.blob();
    
      // In Node.js with fs:
      // const buffer = Buffer.from(await imageBlob.arrayBuffer());
      // require('fs').writeFileSync(`generated_image_${index + 1}.jpg`, buffer);
    
      // In browser: create download link or display in <img> element
      // const url = URL.createObjectURL(imageBlob);
      // document.querySelector('img').src = url;
    }
    
  • import requests
    
    token = 'YOUR_API_TOKEN'
    api_url = 'https://api.useapi.net/v1/google-flow/images'
    
    headers = {
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    }
    
    data = {
        'prompt': 'A serene mountain landscape at sunset with vibrant colors',
        'model': 'imagen-4',
        'aspectRatio': '16:9',
        'count': 4,
        'seed': 123456
    }
    
    response = requests.post(api_url, headers=headers, json=data)
    result = response.json()
    
    print(f"Generated {len(result['media'])} images")
    
    # Download and save images
    for index, item in enumerate(result['media']):
        img = item['image']['generatedImage']
        print(f"Image {index + 1} seed:", img['seed'])
        print(f"mediaGenerationId:", img['mediaGenerationId'])
    
        # Download image from fifeUrl
        image_response = requests.get(img['fifeUrl'])
        with open(f'generated_image_{index + 1}.jpg', 'wb') as f:
            f.write(image_response.content)
    

Try It