Skip to content

Images API ​

Endpoints for managing generated images.

List Images ​

Retrieve paginated list of images.

http
GET /api/images

Query Parameters ​

ParameterTypeDefaultDescription
limitinteger20Items per page (max 100)
offsetinteger0Pagination offset
searchstring-Search prompt text
searchModestringexactexact, all, or any matching
dateFromstring-ISO start date filter
dateTostring-ISO end date filter
aspectRatiostring-Filter by aspect ratio
operationTypestring-Filter by operation: generate, edit, upload, character, characters, product or product-ref. Any other value is a 400
minSizenumber-Minimum size in bytes
maxSizenumber-Maximum size in bytes
sessionIdstring-Filter by session
hasNegativePromptboolean-Only images with negative prompts
modelIdstring-Model filter — any of the eight model IDs, or the retired gemini-flash-image to find images it made: gemini-flash-lite-image, gemini-nano-banana-2.1, gemini-pro-image, openai-gpt-image-2, openai-gpt-image-2.6-flare, openai-gpt-image-2.6-sunburst, openai-gpt-image-2.5-flare, openai-gpt-image-2.5-sunburst
resolutionTierstring-1k, 2k, 4k (comma‑separated)
stylePresetIdinteger-Filter by style preset
productReferenceIdinteger-Filter by product reference
isReferenceboolean-true for reference images only
projectstring-A project's key (or name), or none for images without a project
tagsstring-Tag keys, comma-separated or as repeated tags parameters; an image must have every one (up to 10)

Results are newest‑first; sorting is not currently configurable.

Each image carries project ({ "id", "name", "key" }, or null) and tags ([{ "name", "key" }]). See Projects and Tags.

Request ​

bash
curl -X GET "https://gobananasai.com/api/images?limit=20&search=sunset" \
  -H "X-API-Key: sk_live_xxx"

Response ​

json
{
  "data": [
    {
      "id": 42,
      "sessionId": "sess_abc123",
      "fullUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-a1b2c3d4.png",
      "thumbnailUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-a1b2c3d4-thumb.jpg",
      "width": 1024,
      "height": 1024,
      "sizeBytes": 1048576,
      "prompt": "A beautiful sunset over the ocean",
      "negativePrompt": "blurry, low quality",
      "operation": "generate",
      "aspectRatio": "square",
      "createdAt": "2024-01-15T10:30:00.000Z",
      "project": { "id": 7, "name": "Brand Refresh", "key": "brand-refresh" },
      "tags": [{ "name": "hero", "key": "hero" }]
    }
  ],
  "pagination": {
    "total": 150,
    "limit": 20,
    "offset": 0
  }
}

Generate Image ​

Create a new image from a text prompt.

http
POST /api/images

Request Body ​

FieldTypeRequiredDescription
promptstringYesText description (Gemini max: 16384, OpenAI models max: 32000)
negative_promptstringNoWhat to avoid (max: 1024)
aspect_ratiostringNoNamed aliases (square, portrait, landscape) or ratios (1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9). Default: square (see Aspect ratio default)
nintegerNoNumber of images (1-4)
model_idstringNogemini-flash-lite-image (default), gemini-nano-banana-2.1, gemini-pro-image, openai-gpt-image-2, openai-gpt-image-2.6-flare, openai-gpt-image-2.6-sunburst, openai-gpt-image-2.5-flare, or openai-gpt-image-2.5-sunburst. Validated against tenant allowedModels. gemini-flash-image is a deprecated alias of gemini-nano-banana-2.1
resolution_tierstringNoGemini output tier: 1k, 2k, or 4k. Lite is fixed at 1K; higher tiers require Nano Banana 2.1 or Pro. No current model offers 0.5k
use_google_searchbooleanNoEnable Google Search grounding for Nano Banana 2.1 or Pro
enable_thinkingbooleanNoEnable Gemini thinking mode for Lite, Nano Banana 2.1 or Pro
sizestringNoOpenAI models only: auto or WIDTHxHEIGHT meeting OpenAI size constraints
output_formatstringNoOpenAI models only: png (default), jpeg, webp
qualitystringNoOpenAI models only: low, medium, high, auto; xhigh and max require GPT Image 2.5 or 2.6
output_compressionintegerNoOpenAI models only (jpeg/webp): 0–100
backgroundstringNoOpenAI models only: auto (default) or opaque; GPT Image 2.5 and 2.6 also support transparent with png or webp
moderationstringNoOpenAI models only: auto (default) or low
complexitystringNoGPT Image 2.6 only: low, medium or high planning effort, separate from quality. Omitted, 2.6 uses high. Other OpenAI models answer 400 invalid_request; Gemini models ignore it
system_instructionstringNoStyle guidance
style_preset_idintegerNoApply saved preset by ID
style_preset_namestringNoApply saved preset by name
reference_imagesstring[]NoAdditional reference R2 keys (advanced). Each must be an image stored in this workspace (its key starts with your workspace id); any other key is rejected with 400
reference_group_idintegerNoUse a saved reference group by ID
reference_group_idsinteger[]NoUse multiple groups (1–5)
reference_group_namestringNoUse a group by name
reference_modestringNo'style' for style transfer or 'add' to place the referenced elements (logos, products) in the image and keep their exact design, colours and proportions
session_idstringNoCustom session ID
character_idintegerNoSingle character ID for consistent generation
character_idsinteger[]NoArray of character IDs (1-5) for multi-character scenes
product_idintegerNoSingle product reference ID
product_idsinteger[]NoArray of product IDs (1-6) for product placement
image_to_edit_idintegerNoIf set, edits that image instead of generating new
camera_lookstringNoA built-in real-camera look: disposable-flash, skate-fisheye, old-phone-selfie, camcorder-still, point-and-shoot-night, street-candid-35mm, security-camera or instant-film. Its camera sentence goes before the prompt and its lighting and texture sentences after it; its negative and ratio hint apply only when nothing else sets them. Not with enhance_prompt or image_to_edit_id (400 invalid_request, sync or ?async=true). A synchronous response's metadata.camera_look names it. See Camera looks
reference_sheetstringNoA built-in identity plate: face-plate, outfit-plate or three-panel. Its layout sentence goes before the prompt and its lighting and backdrop sentences after it; its negative and ratio hint apply only when nothing else sets them. Not with camera_look, enhance_prompt or image_to_edit_id (400 invalid_request, sync or ?async=true). A synchronous response's metadata.reference_sheet names it. See Reference sheets
projectstringNoProject to file the new images in (created if new; none for no project; blank counts as not given). See Projects and Tags
tagsstring[]NoUp to 10 tags for the new images

Default Model

gemini-flash-lite-image (Nano Banana 2 Lite) is the current default. Pass model_id to opt into gemini-nano-banana-2.1 (Nano Banana 2.1: 2K/4K, broader ratios, stronger multi-reference workflows), Pro features (grounding and premium production quality), openai-gpt-image-2 for best-in-class text rendering and quality tiers, or openai-gpt-image-2.6-flare / openai-gpt-image-2.6-sunburst (GPT Image 2.6) and openai-gpt-image-2.5-flare / openai-gpt-image-2.5-sunburst (GPT Image 2.5) for xhigh/max quality and transparent backgrounds. Requested models must be in the tenant allowlist.

Aspect ratio default ​

When you don't pass aspect_ratio, the shape is decided in this order:

  1. aspect_ratio in the request, if given.
  2. Otherwise a default saved on a scene, style preset or character you use (checked in that order).
  3. Otherwise the ratio hint of the camera_look or reference_sheet, if given.
  4. Otherwise square (1:1).

Edits (image_to_edit_id) keep the source image's shape unless you pass aspect_ratio or a scene, style preset or character supplies one.

Character & Product Integration ​

Generate images with saved characters and/or products directly via the main endpoint:

Limits:

  • Maximum 5 characters per scene
  • Maximum 6 products per scene
  • Maximum total reference images: 14 for Gemini, 16 for OpenAI models
  • Cannot mix singular and array form (e.g., character_id + character_ids)

Example: Character + Product Combined

bash
curl -X POST "https://gobananasai.com/api/images" \
  -H "X-API-Key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "at a sports stadium, professional advertisement",
    "character_ids": [19, 20],
    "product_ids": [2],
    "aspect_ratio": "16:9"
  }'

Prompt Construction: The system automatically builds optimized prompts based on what you provide:

  • Characters only: "The characters (Name1 and Name2) from the reference images {your prompt}"
  • Products only: "Using the products shown in the reference images, {your prompt}. Maintain exact design..."
  • Both: "The characters with the products shown in reference images, {your prompt}. Maintain exact product design..."
  • reference_images with reference_mode: "add": "Include the elements shown in the reference images in the scene: {your prompt}. ...maintaining their exact design, colors, and proportions."
  • reference_images with reference_mode: "style": "Using the visual style from the reference images, {your prompt}. Match the artistic style, color palette, lighting, mood, and visual aesthetic from the references."

Request ​

bash
curl -X POST "https://gobananasai.com/api/images" \
  -H "X-API-Key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A majestic mountain landscape at golden hour with dramatic clouds",
    "negative_prompt": "blurry, watermark, text",
    "aspect_ratio": "landscape",
    "n": 2
  }'

Response ​

json
{
  "data": {
    "images": [
      {
        "id": 43,
        "d1_record_id": 43,
        "full_url": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-e5f6g7h8.png",
        "thumbnail_url": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-e5f6g7h8-thumb.jpg",
        "width": 1365,
        "height": 1024,
        "size_bytes": 2097152,
        "format": "png",
        "prompt": "A majestic mountain landscape at golden hour with dramatic clouds",
        "negative_prompt": "blurry, watermark, text",
        "has_synthid": true,
        "created_at": "2024-01-15T10:35:00.000Z"
      }
    ],
    "metadata": {
      "requested": 2,
      "generated": 2,
      "session_id": "sess_def456"
    },
    "executionId": "exec-abc123"
  }
}

Each image's id is its gallery id (the same value as d1_record_id). Use it with GET /api/images/:id or image_to_edit_id; when you run several generations in parallel, don't look up the newest image with GET /api/images?limit=1, because another call may have saved one after yours.

Get Image Details ​

Retrieve metadata and edit history for a specific image.

http
GET /api/images/:id

Request ​

bash
curl -X GET "https://gobananasai.com/api/images/42" \
  -H "X-API-Key: sk_live_xxx"

Response ​

json
{
  "data": {
    "id": 42,
    "sessionId": "sess_abc123",
    "fullUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-a1b2c3d4.png",
    "thumbnailUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-a1b2c3d4-thumb.jpg",
    "width": 1024,
    "height": 1024,
    "sizeBytes": 1048576,
    "prompt": "A beautiful sunset over the ocean",
    "negativePrompt": "blurry, low quality",
    "operation": "generate",
    "aspectRatio": "square",
    "createdAt": "2024-01-15T10:30:00.000Z",
    "modelId": "gemini-pro-image",
    "stylePresetId": null,
    "productReferenceId": null,
    "referenceGroupIds": null,
    "project": { "id": 7, "name": "Brand Refresh", "key": "brand-refresh" },
    "tags": [{ "name": "hero", "key": "hero" }]
  }
}

Edit Image ​

Edit an existing image by ID.

http
POST /api/edit-image

Request Body ​

FieldTypeRequiredDescription
image_idintegerYesDatabase ID of image to edit
promptstringYesEdit instruction
negative_promptstringNoWhat to avoid
aspect_ratiostringNoChange aspect ratio

Request ​

bash
curl -X POST "https://gobananasai.com/api/edit-image" \
  -H "X-API-Key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "image_id": 42,
    "prompt": "Add a silhouette of a sailboat in the distance"
  }'

Response ​

json
{
  "thumbnailUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/edit-m3n4o5p6-thumb.jpg",
  "fullUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/edit-m3n4o5p6.png",
  "width": 1024,
  "height": 1024,
  "sizeBytes": 1124352,
  "format": "png",
  "prompt": "Add a silhouette of a sailboat in the distance",
  "parentImageId": 42,
  "d1RecordId": 49,
  "createdAt": "2024-01-15T10:40:00.000Z"
}

Delete Image ​

Delete an image and its associated files.

http
DELETE /api/images/:id

Request ​

bash
curl -X DELETE "https://gobananasai.com/api/images/42" \
  -H "X-API-Key: sk_live_xxx"

Response ​

Returns 204 No Content on success (empty body).

Note

Deleting an image does not delete its edit children. Child images retain their parent_image_id reference for history tracking.

Bulk Operations ​

Bulk Delete ​

http
POST /api/images/delete-bulk

Request ​

bash
curl -X POST "https://gobananasai.com/api/images/delete-bulk" \
  -H "X-API-Key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [41, 42, 43, 44]
  }'

Response ​

json
{
  "data": {
    "deleted": [41, 42, 43, 44],
    "failed": [],
    "summary": {
      "total": 4,
      "succeeded": 4,
      "failed": 0
    }
  }
}

Bulk Download ​

http
POST /api/images/download

Request ​

bash
curl -X POST "https://gobananasai.com/api/images/download" \
  -H "X-API-Key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "imageIds": [41, 42, 43]
  }' \
  --output images.zip

Returns a ZIP file containing the requested images.

Projects and Tags ​

An image can be in one project and carry up to 20 tags. Names match loosely by key: "Brand Refresh", "brand_refresh" and "BRAND-REFRESH" are one project, with the key brand-refresh. Project names are up to 100 characters and tags up to 50; none is not a project name. A renamed or merged project keeps answering to its old names.

Changes need a workspace owner or manager. OAuth clients can list projects and tags (images:read). They create them by organizing images (images:edit), or by filing new images with project or tags on generate (images:generate) and upload (images:edit). Renaming, merging and deleting are not available to them.

Organize Images ​

Move up to 100 images to a project, or out of theirs, and add or remove tags. Give at least one of project, addTags and removeTags.

http
POST /api/images/organize
FieldTypeRequiredDescription
imageIdsinteger[]Yes1–100 image ids
projectobject or nullNo{ "name": "..." } (found or created), { "id": 7 }, or null to take the images out of their project
addTagsstring[]NoUp to 10 tags to add
removeTagsstring[]NoUp to 10 tags to remove
bash
curl -X POST "https://gobananasai.com/api/images/organize" \
  -H "X-API-Key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "imageIds": [42, 43], "project": { "name": "Brand Refresh" }, "addTags": ["hero"] }'
json
{
  "data": {
    "updated": [42, 43],
    "notFound": [],
    "project": { "id": 7, "name": "Brand Refresh", "key": "brand-refresh" },
    "addedTags": [{ "name": "hero", "key": "hero" }]
  }
}

Ids that don't exist, and other workspaces' ids, come back in notFound. A project { "id" } your workspace doesn't have answers 404 project_not_found and changes nothing.

Select All Matching ​

The ids of every image GET /api/images would show for the same query parameters, in the same order, up to 1,000.

http
GET /api/images/ids
json
{ "data": { "ids": [44, 43, 40], "total": 3, "truncated": false } }

truncated is true when more than 1,000 images match.

List Projects ​

http
GET /api/projects
json
{
  "data": {
    "projects": [
      { "id": 7, "name": "Brand Refresh", "key": "brand-refresh", "imageCount": 12, "lastImageAt": "2024-01-15 10:30:00" }
    ],
    "unassignedCount": 30
  }
}

Most recently used first. unassignedCount is the number of images without a project.

Create a Project ​

POST /api/projects with { "name": "Brand Refresh" } finds the project that already has the name or creates it: 201 when created, 200 when found, with { "data": { "id", "name", "key", "created" } }.

Rename a Project ​

PATCH /api/projects/:id with { "name": "Brand Refresh 2026" } answers { "data": { "id", "name", "key" } }. When another project already has the name, it answers 409:

json
{
  "error": "Another project already uses this name",
  "code": "project_name_taken",
  "conflictProjectId": 9
}

Merge Projects ​

POST /api/projects/:id/merge with { "intoProjectId": 9 } moves the project's images and names into project 9 and deletes it: { "data": { "project": { "id", "name", "key" }, "movedImages": 12 } }.

Delete a Project ​

DELETE /api/projects/:id answers { "data": { "deleted": true, "unassignedImages": 12 } }. The images stay, without a project.

Tags ​

GET /api/tags answers { "data": { "tags": [{ "id": 3, "name": "hero", "key": "hero", "imageCount": 8 }] } }, the most used first. DELETE /api/tags/:id removes the tag from every image and answers { "data": { "deleted": true } }.

Upload an Image File ​

Upload a local image file (PNG, JPEG, WebP or GIF, up to 20 MB) directly, as multipart/form-data.

http
POST /api/images/upload

Form Fields ​

FieldTypeRequiredDescription
filefileYesThe image
file_namestringNoFilename to record instead of the file's own
projectstringNoProject to file the image in (none for no project; blank counts as not given)
tagsstringNoUp to 10 tags, as repeated fields or one comma-separated value

Without a project field, the X-Go-Bananas-Project header names the project: encodeURIComponent of a name, sent by the local connector with its folder's name.

Request ​

bash
curl -X POST "https://gobananasai.com/api/images/upload" \
  -H "X-API-Key: sk_live_xxx" \
  -F "file=@./hero.png" \
  -F "project=Brand Refresh" \
  -F "tags=hero,final"

Response ​

json
{
  "image_id": 51,
  "r2_key": "acme-corp/2024-01-15/upload-u1v2w3x4.png",
  "public_url": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/upload-u1v2w3x4.png",
  "thumbnail_url": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/upload-u1v2w3x4-thumb.webp",
  "size_bytes": 482133,
  "mime_type": "image/png",
  "file_name": "hero.png",
  "project": { "id": 7, "name": "Brand Refresh", "key": "brand-refresh" },
  "message": "File uploaded successfully. Image ID: 51. Ready for editing with edit_uploaded_image or edit_image MCP tools."
}

If the image is saved but its project and tags cannot be applied, the response adds "warnings": ["Saved, but the project and tags could not be applied."].

Upload Image for Editing ​

Upload an external image for editing.

http
POST /api/upload-for-editing

Request Body ​

FieldTypeRequiredDescription
image_urlstringYesPublic URL of image
file_namestringNoOriginal filename
mime_typestringNoImage MIME type

Request ​

bash
curl -X POST "https://gobananasai.com/api/upload-for-editing" \
  -H "X-API-Key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "image_url": "https://example.com/my-image.jpg",
    "file_name": "product-photo.jpg"
  }'

Response ​

json
{
  "image_id": 50,
  "r2_key": "acme-corp/2024-01-15/upload-q7r8s9t0.jpg",
  "public_url": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/upload-q7r8s9t0.jpg",
  "size_bytes": 524288,
  "mime_type": "image/jpeg",
  "message": "Image uploaded successfully. ID: 50. Ready for editing."
}

Generate with Character ​

Generate an image featuring a saved character.

http
POST /api/characters/:identifier/generate

Request Body ​

FieldTypeRequiredDescription
scene_promptstringYesScene description
additional_detailsstringNoExtra details
aspect_ratiostringNoAspect ratio
override_negative_promptstringNoOverride character negative prompt
session_idstringNoCustom session ID

identifier is the character ID or name in the URL path.

Request ​

bash
curl -X POST "https://gobananasai.com/api/characters/Luna/generate" \
  -H "X-API-Key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "scene_prompt": "walking through a magical forest at night",
    "aspect_ratio": "portrait"
  }'

Response ​

json
{
  "data": {
    "imageId": 51,
    "sessionId": "sess_abc123",
    "fullUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-u1v2w3x4.png",
    "thumbnailUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-u1v2w3x4-thumb.jpg",
    "width": 768,
    "height": 1024,
    "prompt": "The character from the reference images walking through a magical forest at night",
    "message": "Image generated successfully with character \"Luna\""
  }
}

Generate with Product ​

Generate marketing image with saved product.

http
POST /api/products/:identifier/generate

Request Body ​

FieldTypeRequiredDescription
scene_promptstringYesMarketing scene
additional_detailsstringNoExtra styling
aspect_ratiostringNoAspect ratio
number_of_imagesintegerNo1-4 images
negative_promptstringNoOptional negative prompt

identifier is the product ID or name in the URL path.

Request ​

bash
curl -X POST "https://gobananasai.com/api/products/Premium%20Headphones/generate" \
  -H "X-API-Key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "scene_prompt": "on a minimalist desk with soft morning light",
    "aspect_ratio": "16:9",
    "number_of_images": 2
  }'

Response ​

json
{
  "data": {
    "productId": 3,
    "productName": "Premium Headphones",
    "scenePrompt": "on a minimalist desk with soft morning light",
    "images": [
      {
        "id": 52,
        "url": "https://pub-xxx.r2.dev/...",
        "thumbnail_url": "https://pub-xxx.r2.dev/...-thumb.jpg"
      }
    ],
    "message": "Marketing images generated successfully"
  }
}

Error Responses ​

400 Bad Request ​

json
{
  "error": "Invalid request payload",
  "details": ["prompt is required"]
}

404 Not Found ​

json
{
  "error": "Image not found"
}

429 Rate Limited ​

json
{
  "error": "Rate limit exceeded",
  "retryAfter": 30
}

Next Steps ​