Nano Banana Expert API documentation

Introduction

Nano Banana Expert provides a REST API for AI image and video generation, balance management and history. Every model of the site is available through the API: Nano Banana 2.1, GPT Image 2 and 2.5, Seedream 5.0 Flash, Qwen Image 2.1, Ideogram 4.5, Grok Imagine Image 2 and Recraft V4.1 for images; Kling 3.0, Seedance 2.5 and six more models for video. Use it to embed generation into your apps, bots and scripts.

Base URL

https://nanobanana.expert/api/v1

To get an API key, go to Dashboard → API tab.

Authentication

All API requests must include the Authorization header with your API key in Bearer token format. Keys start with the nb_ prefix.

HTTP
Authorization: Bearer nb_your_api_key_here

Each request uses your account's banana balance. The key is tied to your account — do not share it with third parties.

Models

Pick a model with the model field. The values below are the same ones API responses and history return.

Images — POST /generate

modelModelNotes
nb21Nano Banana 2.1defaultGeneral purpose, the default. Text-to-image and editing with reference_images (up to 10), resolution up to 4K. The legacy value nb2 is accepted as an alias.
gpt25_flareGPT Image 2.5 FlareFast, GPT Image 2 quality. quality up to max.
gpt25_sunburstGPT Image 2.5 SunburstTop quality and precise edits. quality up to max.
gpt2GPT Image 2Best with text inside images. quality: low, medium, high.
seedream5_flashSeedream 5.0 FlashFast and affordable, confident in-image text. reference_images up to 10, resolution 1K or 2K.
qwen21Qwen Image 2.1Generation and editing, typography. reference_images up to 10, resolution 1K or 2K.
ideogram45Ideogram 4.5Best in-image text: posters, logos. quality: low, medium, high; with reference_images the first image is the edit source, up to four more are references.
grok2Grok Imagine Image 2Follows the prompt closely. reference_images up to 5, resolution 1K only, no quality parameter.
recraft_v41Recraft V4.1Design, banners, branding. Text-to-image only, flat price.
recraft_v41_utilityRecraft V4.1 UtilityFast lightweight Recraft. Text-to-image only.
recraft_v41_vectorRecraft V4.1 VectorSVG output: logos and icons. Text-to-image only.
recraft_bgRecraft: background removalBackground removal: no prompt, exactly one image in reference_images, returns a transparent PNG.

Video — POST /video

modelModelNotes
seedance25Seedance 2.5
Modes
references, frames, text
Duration
4–30 s
Resolutions
480p, 720p, 1080p
Aspect ratios
auto, 21:9, 16:9, 4:3, 1:1, 3:4, 9:16
Sound
on/off
kling30Kling 3.0
Modes
frames, text
Duration
3–15 s
Resolutions
720p, 1080p, 4K
Aspect ratios
auto, 16:9, 9:16, 1:1
Sound
on/off
grok15Grok Imagine 1.5default
Modes
frames (first_frame), references, text
Duration
1–15 s
Resolutions
480p, 720p, 1080p
Aspect ratios
auto, 16:9, 9:16, 1:1, 3:2, 2:3
Sound
built-in
wan30Wan 3.0
Modes
frames, references, text
Duration
2–30 s
Resolutions
480p, 720p, 1080p
Aspect ratios
auto, 16:9, 4:3, 1:1, 3:4, 9:16
Sound
on/off
h3MiniMax H3
Modes
references, frames, text
Duration
5–15 s
Resolutions
768p, 2K
Aspect ratios
auto, 21:9, 16:9, 4:3, 1:1, 3:4, 9:16
Sound
built-in
omni11Gemini Omni Flash 1.1
Modes
references, frames, text
Duration
4–10 s (×2)
Resolutions
360p, 720p, 1080p, 4K
Aspect ratios
16:9, 9:16
Sound
built-in
hh11HappyHorse 1.1
Modes
frames (first_frame), references, text
Duration
3–15 s
Resolutions
720p, 1080p
Aspect ratios
16:9, 9:16, 1:1, 4:3, 3:4, 4:5, 5:4, 21:9, 9:21
Sound
built-in
flux3FLUX 3
Modes
frames, text
Duration
5–20 s
Resolutions
720p, 1080p
Aspect ratios
auto, 21:9, 2:1, 16:9, 4:3, 1:1, 3:4, 9:16
Sound
on/off

Balance

Returns the current balance of your account.

GET
/api/v1/balance

Get banana and coupon balance

Response

JSON
{
  "bananas": 1250,
  "generation_coupons": 2,
  "coupon_scope": { "model": "gpt2", "quality": "low", "resolution": "1k" }
}

Examples

cURL
curl -H "Authorization: Bearer nb_your_key" \
  https://nanobanana.expert/api/v1/balance
JavaScript
const res = await fetch('https://nanobanana.expert/api/v1/balance', {
  headers: { 'Authorization': 'Bearer nb_your_key' }
});
const { bananas, generation_coupons } = await res.json();
console.log(`Balance: ${bananas} bananas`);

Image Generation

Generates an image from a text description. The cost is deducted from your balance.

POST
/api/v1/generate

Create an image from a prompt

Request body

ParameterTypeDescription
promptstringRequired (except for model="recraft_bg", where it is ignored). Text description of the image, or an edit instruction when reference_images is provided.
reference_imagesstring[]Optional. Array of source images for image-to-image: editing, enhancement, a character or product from a photo. Each item is a public http(s) URL or a base64 data URL like data:image/png;base64,…. When this field is present the request runs in edit mode. The limit depends on the model: 10 for nb21, seedream5_flash and qwen21; 16 for gpt2, gpt25_flare and gpt25_sunburst; 5 for ideogram45 and grok2; exactly 1 for recraft_bg; Recraft V4.1 models do not accept references. For most models the price equals text-to-image. The exception is gpt25_flare and gpt25_sunburst on the economy tier: every image is billed separately and included in bananas_spent (on the stable tier references are free, but the generation itself costs more).
modelstringOptional, default "nb21" (Nano Banana 2.1, general-purpose; the legacy value "nb2" is accepted as an alias). Values and their specifics are listed in the Models section: "gpt2", "gpt25_flare", "gpt25_sunburst", "seedream5_flash", "qwen21", "ideogram45", "grok2", "recraft_v41", "recraft_v41_utility", "recraft_v41_vector" and "recraft_bg" (Recraft: background removal without generation — prompt is not needed, reference_images must contain exactly one image, the result is always a transparent PNG, flat price independent of resolution). Recraft V4.1 models are text-to-image only: reference_images are not accepted, resolution and quality are ignored, flat price; transparent_background is ignored for vector. An unknown value is read as "nb21".
qualitystringOptional. For "gpt2" and "ideogram45": "low" | "medium" (default) | "high"; "gpt25_flare" and "gpt25_sunburst" also accept "xhigh" and "max". A level the model does not support is read as "medium"; other models ignore the parameter. Affects detail and cost. For GPT Image on the "stable" tier the price is the same for every quality level (the quality value is still forwarded to the model).
aspect_ratiostringOptional. Example: "16:9", "1:1", "9:16". Default: "1:1".
resolutionstringOptional. "1k" | "2k" | "4k". Default: "1k". The ceiling depends on the model: nb21 and GPT Image — up to 4K, seedream5_flash and qwen21 — up to 2K, ideogram45 and grok2 — 1K only. A value above the ceiling is clamped to it and the price follows the resulting resolution.
output_formatstringOptional. "png" | "jpeg" | "webp". Default: "png".
transparent_backgroundbooleanOptional. true — remove the background and return a transparent PNG (post-processing). Works with any raster model; ignored for recraft_bg and recraft_v41_vector. A small surcharge applies on top of the generation price (free on coupon generations). On success the result is always PNG; the response field transparent_background = true.
seednumberOptional. Seed for reproducible results.
preferred_providerstringOptional. Provider tier: "economy" (cheapest, less stable), "stable" (default — recommended, balanced cost/quality), "reliable" (premium — maximum stability). Legacy values accepted: "cheap" → "economy", "official" → "stable". The tier applies to GPT Image 2 and 2.5; nb21, seedream5_flash, qwen21, ideogram45 and grok2 have a fixed route. When the primary route fails the request moves to the backup route (see fallback).
fallbackbooleanOptional, default true. false — never switch to the backup route: if the primary route of the chosen tier fails, the request ends with a 502 error instead of retrying with a more expensive provider. The backup step is billed at its own rate, so false protects you from the extra charge, but some requests will need to be retried on your side.

Response

JSON
{
  "image_url": "https://...",
  "bananas_spent": 42,
  "used_coupon": false,
  "seed": 1234567890,
  "generation_id": "uuid",
  "provider_chain": ["primary"],
  "transparent_background": false
}

provider_chain — попытки генерации в порядке выполнения. ["primary"] — основной маршрут выбранного tier'а сработал с первого раза; ["primary", "fallback"] — основной не ответил, картинку сделал запасной маршрут, и bananas_spent считается по его тарифу. Не хотите доплачивать за запасной — передайте "fallback": false.

Examples

cURL
curl -X POST https://nanobanana.expert/api/v1/generate \
  -H "Authorization: Bearer nb_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a banana in space, cinematic lighting",
    "aspect_ratio": "16:9",
    "resolution": "1k",
    "output_format": "png",
    "transparent_background": true
  }'
JavaScript
const res = await fetch('https://nanobanana.expert/api/v1/generate', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer nb_your_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    prompt: 'a banana in space, cinematic lighting',
    aspect_ratio: '16:9',
    resolution: '1k',
    preferred_provider: 'stable', // economy / stable / reliable
  }),
});
const { image_url, bananas_spent } = await res.json();
console.log('Generated:', image_url);

Image-to-image (enhance an uploaded picture)

To enhance or rework an existing image, pass it in the reference_images array along with a prompt — same endpoint. The prompt describes what to change (or leave it as a brief "keep as is" instruction for an upscale). Both http(s) URLs and base64 data URLs are supported.

cURL
curl -X POST https://nanobanana.expert/api/v1/generate \
  -H "Authorization: Bearer nb_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "make the lighting cinematic, keep the subject",
    "reference_images": ["https://example.com/photo.jpg"],
    "resolution": "2k"
  }'
JavaScript
// Option 1 — public URL (recommended, no body size limits)
await fetch('https://nanobanana.expert/api/v1/generate', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer nb_your_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    prompt: 'restore colors, increase sharpness',
    reference_images: ['https://example.com/photo.jpg'],
    resolution: '2k',
  }),
});

// Option 2 — base64 data URL (image/png|jpeg|webp|gif)
const dataUrl = 'data:image/jpeg;base64,/9j/4AAQSk...';
await fetch('https://nanobanana.expert/api/v1/generate', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer nb_your_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    prompt: 'restore colors, increase sharpness',
    reference_images: [dataUrl],
  }),
});

Public URLs are recommended: they work without request-body size limits. Base64 is convenient for quick experiments but may hit the platform body limit (~4 MB). Image-to-image pricing matches the standard generation price for the chosen resolution, except GPT Image 2.5 on the economy tier, where every image in reference_images is billed separately.

cURL — model: recraft_bg (background removal)
curl -X POST https://nanobanana.expert/api/v1/generate \
  -H "Authorization: Bearer nb_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "recraft_bg",
    "reference_images": ["https://example.com/photo.jpg"]
  }'

Video generation

Video is generated asynchronously — from one to several minutes. POST /video charges the price right away and returns a job id with status processing (HTTP 202). Then poll GET /video/{id} every 5–10 seconds until the status is success (video_url in the response) or failed (the price is refunded if the provider did not charge). Image coupons do not apply to video; free videos from a package (video_coupons in GET /balance) are used automatically when the model, resolution and duration match their scope — the response then has used_coupon: true and bananas_spent: 0.

POST
/api/v1/video

Start a video generation (202 with id)

GET
/api/v1/video/{id}

Status and the finished video URL

GET
/api/v1/video

Your videos, newest first (limit, offset)

The mode follows from the fields you send: first_frame (and last_frame) — the video starts from your image and keeps its proportions; reference_images — the model takes the character and style from the images and builds its own scene; neither — text-to-video. All images must be public https URLs; base64 is not accepted for video.

Request body

ParameterTypeDescription
modelstringOptional. Video model, "kling30" by default. See the Models section for the list and capabilities.
promptstringRequired (except with shots). What happens in the frame and how the camera moves.
durationnumberOptional. Duration in seconds, an integer within the model range. Defaults to the model standard (usually 5 s).
resolutionstringOptional. One of the model resolutions ("480p", "720p", "1080p", "4k"…). Defaults to the cheapest.
aspect_ratiostringOptional. "16:9", "9:16", "1:1" and other model ratios. With first_frame defaults to "auto" — the image ratio; for models without "auto" — "16:9".
audiobooleanOptional. Sound in the video, true by default. Ignored by models with built-in sound.
first_framestringOptional. URL of the image the video starts with.
last_framestringOptional. URL of the image the video ends with (not every model — see Models).
reference_imagesstring[]Optional. Array of reference image URLs (character, product, style). Not together with first_frame. Refer to them in the prompt as @Image1, @Image2…
shotsobject[]Optional, "kling30" only. Multi-shot: up to 5 shots { "prompt", "duration" } — a video of several scenes, duration = sum of shots (3–15 s).
auto_fallbackbooleanOptional. true — if the primary provider fails, try a backup one (may cost more). Defaults to the service setting.

Response — 202

JSON
{
  "id": "uuid",
  "status": "processing",
  "bananas_spent": 503,
  "balance": 12497
}

Video status — GET /api/v1/video/{id}

JSON
{
  "id": "uuid",
  "status": "success",            // processing | success | failed
  "video_url": "https://...mp4",  // only when status = success
  "model": "kling30",
  "mode": "frames",
  "prompt": "the camera slowly orbits the product",
  "duration": 5,
  "resolution": "720p",
  "aspect_ratio": "auto",
  "width": 720,
  "height": 960,
  "bananas_spent": 503,
  "error": null,
  "moderation": false,
  "created_at": "2026-09-25T12:00:00Z"
}

Examples

cURL — Kling 3.0, first frame
curl -X POST https://nanobanana.expert/api/v1/video \
  -H "Authorization: Bearer nb_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling30",
    "prompt": "the camera slowly orbits the product, soft studio light",
    "first_frame": "https://example.com/product.jpg",
    "duration": 5,
    "resolution": "720p"
  }'

curl https://nanobanana.expert/api/v1/video/VIDEO_ID \
  -H "Authorization: Bearer nb_your_key"
JavaScript — start and poll
const headers = {
  'Authorization': 'Bearer nb_your_key',
  'Content-Type': 'application/json',
};

const start = await fetch('https://nanobanana.expert/api/v1/video', {
  method: 'POST',
  headers,
  body: JSON.stringify({
    model: 'seedance25',
    prompt: 'a woman in @Image1 walks through a neon-lit street',
    reference_images: ['https://example.com/character.jpg'],
    duration: 5,
    aspect_ratio: '9:16',
  }),
});
const { id } = await start.json();

let video;
do {
  await new Promise(r => setTimeout(r, 8000));
  video = await (await fetch(`https://nanobanana.expert/api/v1/video/${id}`, { headers })).json();
} while (video.status === 'processing');

console.log(video.status === 'success' ? video.video_url : video.error);
cURL — Kling 3.0 multi-shot
curl -X POST https://nanobanana.expert/api/v1/video \
  -H "Authorization: Bearer nb_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling30",
    "first_frame": "https://example.com/hero.jpg",
    "shots": [
      { "prompt": "close-up, the hero looks at the camera", "duration": 3 },
      { "prompt": "wide shot, the hero turns and walks away", "duration": 4 }
    ]
  }'

Videos are stored for a limited time — download video_url to your side. At most two videos per account can be in progress at once (otherwise 429).

Generation History

Returns a list of your generations in reverse chronological order. This method returns images. For videos use GET /api/v1/video.

GET
/api/v1/history

Get generation history

Query parameters

ParameterDescription
limitNumber of records (max 100, default 20)
offsetOffset for pagination (default 0)

Response

JSON
{
  "generations": [
    {
      "id": "uuid",
      "prompt": "a banana in space",
      "image_url": "https://...",
      "model": "nb21",
      "seed": 1234567890,
      "created_at": "2026-03-04T12:00:00Z"
    }
  ],
  "total": 42,
  "limit": 20,
  "offset": 0
}
cURL
curl "https://nanobanana.expert/api/v1/history?limit=10&offset=0" \
  -H "Authorization: Bearer nb_your_key"

Key Management via API

You can manage API keys programmatically through the API itself.

GET
/api/v1/keys

Get list of active keys

POST
/api/v1/keys

Create a new key (shown only once)

DELETE
/api/v1/keys?id=uuid

Revoke a key by ID

cURL — create key
curl -X POST https://nanobanana.expert/api/v1/keys \
  -H "Authorization: Bearer nb_your_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "My Bot"}'
cURL — revoke key
curl -X DELETE "https://nanobanana.expert/api/v1/keys?id=key-uuid-here" \
  -H "Authorization: Bearer nb_your_key"

Error Codes

CodeMeaningSolution
401UnauthorizedCheck the Authorization: Bearer nb_... header
402Insufficient fundsTop up your banana balance at /dashboard
400Bad RequestCheck required request parameters
403ForbiddenAccount blocked or video generation is not open yet
429Too Many RequestsToo many requests; for video — more than two videos in progress
500Internal ErrorInternal server error
502Generation FailedGeneration failed at the provider — retry the request; with fallback: false any primary-route failure ends this way
503Service UnavailableService temporarily unavailable

All errors are returned in the format { "error": "message" }.