Skip to content

Async Request Mode

When mode is "async", the server immediately returns a task ID and processes the generation in the background. Clients poll for results. Best for batch processing or latency-sensitive scenarios.

Workflow

Client                              Server
  │                                    │
  │─── POST /generate (async) ───────►│
  │                                    │  Returns generationId immediately
  │◄── 200 { generationId } ──────────│
  │                                    │  Processing in background...
  │─── GET /generate?id=xxx ─────────►│
  │◄── { status: "processing" } ──────│
  │                                    │
  │─── GET /generate?id=xxx ─────────►│
  │◄── { status: "processing" } ──────│
  │                                    │  Generation complete
  │─── GET /generate?id=xxx ─────────►│
  │◄── { status: "completed" } ───────│
  │    { outputImageUrls: [...] }      │

Request Example

1. Submit Generation Task

sh
curl -X POST https://www.nananobanana.com/api/v1/generate \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer nb_your_api_key_here" \
  -d '{
    "prompt": "Chinese ink painting style landscape",
    "selectedModel": "nano-banana",
    "mode": "async"
  }'

2. Poll for Results

sh
curl https://www.nananobanana.com/api/v1/generate?id=YOUR_GENERATION_ID \
  -H "Authorization: Bearer nb_your_api_key_here"

Response Format

Submit Success (200 OK)

json
{
  "success": true,
  "async": true,
  "generationId": "clxx...",
  "message": "Generation started. Use GET /api/v1/generate?id={generationId} to poll for results.",
  "creditsUsed": 1,
  "remainingCredits": 99
}
FieldTypeDescription
successbooleanWhether submission succeeded
asyncbooleanAlways true, indicates async mode
generationIdstringTask ID for polling
messagestringInstruction message
creditsUsednumberCredits consumed
remainingCreditsnumberRemaining account credits

Polling Response

When polling GET /api/v1/generate?id={generationId}, check the processingStatus:

Processing:

json
{
  "data": {
    "id": "clxx...",
    "prompt": "Chinese ink painting style landscape",
    "outputImageUrls": null,
    "modelUsed": "nano-banana",
    "processingStatus": "processing",
    "creditsUsed": 1,
    "createdAt": "2025-01-01T00:00:00.000Z"
  }
}

Completed:

json
{
  "data": {
    "id": "clxx...",
    "prompt": "Chinese ink painting style landscape",
    "outputImageUrls": ["https://..."],
    "modelUsed": "nano-banana",
    "processingStatus": "completed",
    "creditsUsed": 1,
    "createdAt": "2025-01-01T00:00:00.000Z"
  }
}

Failed:

json
{
  "data": {
    "id": "clxx...",
    "prompt": "Chinese ink painting style landscape",
    "outputImageUrls": null,
    "modelUsed": "nano-banana",
    "processingStatus": "failed",
    "errorMessage": "Generation failed due to server error",
    "creditsUsed": 1,
    "createdAt": "2025-01-01T00:00:00.000Z"
  }
}

Server Busy (503 Service Unavailable)

When the concurrent task limit is reached:

json
{
  "error": "Server is busy, too many concurrent tasks. Please retry later.",
  "type": "server_busy",
  "activeTasks": 10
}

WARNING

When the server is busy, consumed credits are automatically refunded.

Code Examples

python
import requests
import time

API_KEY = "nb_your_api_key_here"
BASE_URL = "https://www.nananobanana.com/api/v1"
HEADERS = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {API_KEY}"
}

# Async mode — submit task and poll for results
response = requests.post(
    f"{BASE_URL}/generate",
    headers=HEADERS,
    json={
        "prompt": "Chinese ink painting style landscape",
        "selectedModel": "nano-banana",
        "mode": "async"
    }
)

result = response.json()

# Handle server busy
if response.status_code == 503:
    print("Server busy, please retry later.")
    exit()

if not result.get("success"):
    print("Submit failed:", result.get("error"))
    exit()

generation_id = result["generationId"]
print(f"Task submitted! ID: {generation_id}")
print(f"Credits used: {result['creditsUsed']}")

# Poll for results
max_retries = 60  # Max 60 polls (~3 minutes)
for i in range(max_retries):
    status_response = requests.get(
        f"{BASE_URL}/generate?id={generation_id}",
        headers=HEADERS
    )
    data = status_response.json()["data"]
    
    print(f"[{i+1}/{max_retries}] Status: {data['processingStatus']}")
    
    if data["processingStatus"] == "completed":
        print("✅ Generation complete!")
        print("Image URLs:", data["outputImageUrls"])
        break
    elif data["processingStatus"] == "failed":
        print("❌ Generation failed:", data.get("errorMessage"))
        break
    
    time.sleep(3)  # Poll every 3 seconds
else:
    print("⏰ Timeout: generation did not complete in time.")
javascript
const API_KEY = "nb_your_api_key_here";
const BASE_URL = "https://www.nananobanana.com/api/v1";
const HEADERS = {
  "Content-Type": "application/json",
  "Authorization": `Bearer ${API_KEY}`
};

// Async mode — submit task and poll for results
async function generateAsync() {
  const response = await fetch(`${BASE_URL}/generate`, {
    method: "POST",
    headers: HEADERS,
    body: JSON.stringify({
      prompt: "Chinese ink painting style landscape",
      selectedModel: "nano-banana",
      mode: "async"
    })
  });

  // Handle server busy
  if (response.status === 503) {
    console.error("Server busy, please retry later.");
    return;
  }

  const result = await response.json();
  if (!result.success) {
    console.error("Submit failed:", result.error);
    return;
  }

  const generationId = result.generationId;
  console.log(`Task submitted! ID: ${generationId}`);
  console.log(`Credits used: ${result.creditsUsed}`);

  // Poll for results
  const maxRetries = 60;
  for (let i = 0; i < maxRetries; i++) {
    const statusRes = await fetch(
      `${BASE_URL}/generate?id=${generationId}`,
      { headers: HEADERS }
    );
    const { data } = await statusRes.json();

    console.log(`[${i + 1}/${maxRetries}] Status: ${data.processingStatus}`);

    if (data.processingStatus === "completed") {
      console.log("✅ Generation complete!");
      console.log("Image URLs:", data.outputImageUrls);
      return;
    } else if (data.processingStatus === "failed") {
      console.error("❌ Generation failed:", data.errorMessage);
      return;
    }

    await new Promise(r => setTimeout(r, 3000)); // Poll every 3 seconds
  }

  console.error("⏰ Timeout: generation did not complete in time.");
}

generateAsync();
python
import requests
import time

API_KEY = "nb_your_api_key_here"
BASE_URL = "https://www.nananobanana.com/api/v1"
HEADERS = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {API_KEY}"
}

prompts = [
    "Sunrise at Mount Fuji",
    "The Eiffel Tower at night",
    "Autumn streets of Kyoto",
]

# Submit batch tasks
task_ids = []
for prompt in prompts:
    response = requests.post(
        f"{BASE_URL}/generate",
        headers=HEADERS,
        json={
            "prompt": prompt,
            "selectedModel": "nano-banana",
            "mode": "async"
        }
    )
    result = response.json()
    if result.get("success"):
        task_ids.append(result["generationId"])
        print(f"✅ Submitted: {prompt[:20]}... -> {result['generationId']}")
    else:
        print(f"❌ Failed: {prompt[:20]}... -> {result.get('error')}")

print(f"\nSubmitted {len(task_ids)} tasks. Polling for results...\n")

# Poll all tasks
pending = set(task_ids)
results = {}

while pending:
    for task_id in list(pending):
        resp = requests.get(
            f"{BASE_URL}/generate?id={task_id}",
            headers=HEADERS
        )
        data = resp.json()["data"]
        
        if data["processingStatus"] == "completed":
            results[task_id] = data["outputImageUrls"]
            pending.discard(task_id)
            print(f"✅ Completed: {task_id}")
        elif data["processingStatus"] == "failed":
            pending.discard(task_id)
            print(f"❌ Failed: {task_id} - {data.get('errorMessage')}")
    
    if pending:
        print(f"⏳ {len(pending)} tasks still processing...")
        time.sleep(3)

print(f"\nAll done! {len(results)} images generated.")
for task_id, urls in results.items():
    print(f"  {task_id}: {urls}")

Best For

  • ✅ Batch generating multiple images
  • ✅ Background task processing (no user waiting)
  • ✅ Latency-sensitive HTTP response scenarios
  • ✅ Architectures that decouple "submit" and "get results"

Polling Recommendations

ParameterRecommendedNotes
Poll interval3 secondsAvoid excessive requests
Max retries60~3 minutes timeout
Initial delay5 secondsGive the server time to start

Important Notes

WARNING

  • Credits are deducted when the task is submitted, not when generation completes.
  • If the server is busy (503), credits are automatically refunded.
  • When generation fails, credits are not automatically refunded.
  • Set a reasonable polling timeout to avoid waiting indefinitely.

Released under the MIT License.